Compare commits

..

494 Commits

Author SHA1 Message Date
ringabout
10564f25b3 fixes #24719; improves order of destruction (#25060)
fixes #24719

(cherry picked from commit 8e57a9f623)
2025-07-19 08:22:53 +02:00
narimiran
fbc7e54e95 revert Atlas commit to the one compatible with 2.0.x 2025-07-14 09:48:48 +02:00
Juan M Gómez
7f3dbd5656 Updates nimble commit (#25036)
(cherry picked from commit 370ee61f6d)
2025-07-08 16:23:45 +02:00
ringabout
71f3e100b6 provides a $ function for Path (#23617)
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 4e7c70fd7d)
2025-07-02 09:59:38 +02:00
ringabout
d2cb099e44 fixes #24881; build_all.sh koch tools fails to build atlas (#24884)
fixes #24881

To test: `nim c koch.nim` + delete the `dist` directory

(cherry picked from commit af9219ada7)
2025-07-01 14:23:58 +02:00
Miran
7e51e48cac update the tooling versions (#24878)
(cherry picked from commit 11e4bd668c)
2025-06-30 14:10:33 +02:00
ringabout
19c89622ca fixes #23564; hasCustomPragma skips alises types (#24994)
fixes #23564

perhaps handle generic aliases (tyGenericInst for aliases types) if
needed

(cherry picked from commit 7e6fa9e2d6)
2025-06-27 13:47:24 +02:00
Jacek Sieka
b1d9af4d5f Ensure that gc interface remains non-raising (#25006)
GC_fullCollect in particular has an annoying `Exception` effect

(cherry picked from commit aba9361510)
2025-06-18 16:15:42 +02:00
metagn
c467532484 don't set sym of generic param type value to generic param sym (#24995)
fixes #23713

`linkTo` normally sets the sym of the type as well as the type of the
sym, but this is not wanted for custom pragmas as it would look up the
definition of the generic param and not the definition of its value. I
don't see a practical use for this either.

(cherry picked from commit 7701b3c7e6)
2025-06-16 11:17:19 +02:00
Eugene Kabanov
114d0b8bdc Fix FreeBSD getThreadId() should use different syscall definition for 64bit platforms. (#24977)
(cherry picked from commit 7a53db6874)
2025-06-06 08:33:38 +02:00
Alfred Morgan
f8ce7ddd6d Patch 24922 (#24923)
(cherry picked from commit b61a614e8a)
2025-06-03 07:38:25 +02:00
Andreas Rumpf
cd6dbbd7f3 fixes #4851 [backport] (#24954)
(cherry picked from commit 1e602490e9)
2025-05-19 17:54:43 +02:00
narimiran
acac0bc1f2 bump NimVersion to 2.0.17 2025-04-22 16:26:30 +02:00
narimiran
82f3a57612 bump NimVersion to 2.0.16 2025-04-21 19:10:44 +02:00
metagn
7e589bcbe4 add bit type overloads of $ and repr (#24865)
fixes #24864

(cherry picked from commit 97d819a251)
2025-04-14 10:56:41 +02:00
metagn
dbed9310ba ignore typeof in closure iterators (#24861)
fixes #24859

(cherry picked from commit f58cd51fc4)
2025-04-14 10:54:56 +02:00
ringabout
9524edec60 fixes #24850; macro-generated if/else and when/else statements have m… (#24852)
…ismatched indentation with repr

fixes #24850

(cherry picked from commit 29a2e25d1e)
2025-04-09 07:57:52 +02:00
metagn
574db65396 make fillObjectFields recur over base type (#24854)
fixes #24847

Object constructors call `fillObjectFields` when a field inside the
constructor does not have a location, however when the field is from a
base type this does not process it. Now `fillObjectFields` also calls
itself for the base type to fix this but not sure if this is a good
solution as `fillObjectFields` is used in other places too.

(cherry picked from commit a625fab098)
2025-04-09 07:57:39 +02:00
ringabout
e2bf3a6f70 bump to windows 2025 (#24853)
(cherry picked from commit 052ceca3c1)
2025-04-09 07:55:26 +02:00
Miran
6f2dbc105e test stint more thoroughly (#24832)
(cherry picked from commit 10c9ebad93)
2025-04-09 07:55:20 +02:00
ringabout
63151568b4 fixes #24801; Invalid C codegen generated when destroying distinct seq types (#24835)
fixes #24801

Because distinct `seq` types match `proc `=destroy`*[T](x: var T)
{.inline, magic: "Destroy".}`. But the Nim compiler generates lifted seq
types for corresponding distinct types. So we skip the address for
distinct types.

Related to https://github.com/nim-lang/Nim/pull/22207 I had a hard time
finding the other place where generic destructors get replaced by
attachedDestructors

(cherry picked from commit 4352fa2ef0)
2025-04-04 10:18:00 +02:00
ringabout
4610c2b314 fixes #10625; setjmp on linux mangles ebp leading to early collection (#24787)
fixes #10625

(cherry picked from commit 7c5d005510)
2025-03-25 09:45:23 +01:00
ringabout
d01002d8f8 fixes #24770; Thread local not registed as GC root when =destroy exists (#24776)
fixes #24770

e.g. `seq[(ObjectWithDestructors, string)]`/ For refc, a seq with
elements that have destructors will have `hasAsgn` flags. The flag is
the criteria whether a seq is thought as `containsGarbageCollectedRef`.
i.e. whether to `registerTraverseProc` for the type.
The culprit seems to be that `searchTypeForAux` doesn't consider the
element type of sequence, even it contains a string that should belong
to `GarbageCollectedRef`.

With this PR:

It now generates

```
nimRegisterThreadLocalMarker(TM__mSF73dT1lSI7DG58StKHLQ_5);
```

in refc

(cherry picked from commit dfa482e292)
2025-03-13 12:24:29 +01:00
ringabout
bc2fa6fe32 fixes #24147; Copy hook causes an incompatible-pointer-types (#24149)
fixes #24147

(cherry picked from commit 5c843d3d60)
2025-03-11 08:58:37 +01:00
ringabout
41637db18f fixes ORC memory leaks; marks hooks with optQuirky (#24701)
closes https://github.com/nim-lang/Nim/pull/24686
closes #24693

```nim
# v.nim
import std/[json]

var test: seq[string]
var testData: JsonNode
try:
  ## Fails
  testData = parseJson("""[{"id": 1"}, {"id": "2"}]""")

  ## Works
  # testdata = parseJson("""[{"id": "1"}, {"id": "2"}]""")

  ## Fails
  # let stream = newStringStream("""[{"id": 1"}, {"id": "2"}]""")
  # testData = parseJson(stream, "input", false, false)
  # stream.close()

except:
  testData = %* []
for t in testData:
  test.add(t["id"].getStr())
echo $test
```

With this PR:

```
==66425== LEAK SUMMARY:
==66425==    definitely lost: 0 bytes in 0 blocks
==66425==    indirectly lost: 0 bytes in 0 blocks
==66425==      possibly lost: 0 bytes in 0 blocks
==66425==    still reachable: 16,512 bytes in 2 blocks
==66425==         suppressed: 0 bytes in 0 blocks
==66425== Reachable blocks (those to which a pointer was found) are not shown.
==66425== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==66425==
==66425== For lists of detected and suppressed errors, rerun with: -s
==66425== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
```

(cherry picked from commit f0b5bf359e)
2025-02-20 10:26:12 +01:00
ringabout
b7eefc31d8 implements quirky for functions (#24700)
ref https://github.com/nim-lang/Nim/pull/24686

With this PR

```nim
import std/streams

proc foo() =
  var name = newStringStream("2r2")
  raise newException(ValueError, "sh")

try:
  foo()
except:
 discard

echo 123
```
this example no longer leaks

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 510ac84518)
2025-02-18 17:51:21 +01:00
metagn
5df3bf467e retry thttpclient_ssl twice (#24467)
Flaky on linux_amd64

(cherry picked from commit 652edb229a)
2025-02-17 21:16:14 +01:00
metagn
ac44139084 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-02-17 21:16:13 +01:00
metagn
ac882ea696 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-02-17 17:11:42 +01:00
ringabout
56f9559c69 adds a ubuntu 24.04 matrix with gcc 14 for tests (#23673)
ref https://forum.nim-lang.org/t/11587

(cherry picked from commit 6336d2681b)
2025-02-17 15:37:45 +01:00
ringabout
c08c32a1ed fixes #5901 #21211; don't fold cast function types because of gcc 14 (#23683)
follow up https://github.com/nim-lang/Nim/pull/6265

fixes #5901
fixes #21211

It causes many problems with gcc14 if we fold the cast function types.
Let's check what it will break

(cherry picked from commit 2d1533f34f)
2025-02-17 13:25:35 +01:00
narimiran
03491904a0 update CI to Ubuntu 24.04 2025-02-17 09:27:37 +01:00
metagn
57f84c5376 track introduced locals in vmgen for eval check (#24674)
fixes #8758, fixes #10828, fixes #12172, fixes #21610, fixes #23803,
fixes #24633, fixes #24634, succeeds #24085

We simply track the symbol ID of every traversed `var`/`let` definition
in `vmgen`, then these symbols are always considered evaluable in the
current `vmgen` context. The set of symbols is reset before every
generation, but both tests worked properly without doing this including
the nested `const`, so maybe it's already done in some way I'm not
seeing.

(cherry picked from commit a5cc33c1d3)
2025-02-17 08:23:51 +01:00
ringabout
1df4debbf1 fixes bugs on the Nim manual (#24669)
ref https://en.cppreference.com/w/cpp/error/exception/what

> Pointer to a null-terminated string with explanatory information. The
pointer is guaranteed to be valid at least until the exception object
from which it is obtained is destroyed, or until a non-const member
function on the exception object is called.

The pointer is only valid before `CStdException as e` is destroyed

Old examples are broken on macOS arm64

```
/Users/blue/Desktop/nimony/test4.nim(38) test4
/Users/blue/Desktop/nimony/test4.nim(26) fn
/Users/blue/.choosenim/toolchains/nim-#devel/lib/std/assertions.nim(41) failedAssertImpl
/Users/blue/.choosenim/toolchains/nim-#devel/lib/std/assertions.nim(36) raiseAssert
/Users/blue/.choosenim/toolchains/nim-#devel/lib/system/fatal.nim(53) sysFatal
Error: unhandled exception: /Users/blue/Desktop/nimony/test4.nim(26, 3) `$b == "foo2"`  [AssertionDefect]
```

(cherry picked from commit e6f6c369ff)
2025-02-10 17:11:50 +01:00
metagn
1ff69eae17 don't mark captured field sym in template as fully used (#24660)
fixes #24657

(cherry picked from commit 647c6687f1)
2025-01-31 09:36:33 +01:00
metagn
4fa122eb44 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-27 09:30:11 +01:00
Tomohiro
53782b1404 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:51:04 +01:00
ringabout
cafe1284ac 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:13:03 +01:00
ringabout
e2ae7d5f43 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:12:26 +01:00
metagn
772ebe6715 disable sfml test on osx (#24615)
Tried installing sfml 2 in #24614 but didn't work

(cherry picked from commit d83ff81695)
2025-01-22 09:56:31 +01:00
ringabout
32c99651fc ci: update to ubuntu 22.04 (#24608)
(cherry picked from commit 41c447b5f4)
2025-01-22 06:58:51 +01:00
metagn
2eac7941ff 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-22 06:56:48 +01:00
metagn
cedcb7881d 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-22 06:45:40 +01:00
narimiran
117b913458 bump NimVersion to 2.0.15 2025-01-22 06:39:41 +01:00
narimiran
bf4de6a394 bump NimVersion to 2.0.14 2024-12-23 08:07:41 +01:00
ringabout
86f1a2785a remove zippy data from tarballs (#24551)
fixes https://github.com/nim-lang/nightlies/issues/95

(cherry picked from commit 63c884038d)
2024-12-23 06:59:22 +01:00
ringabout
c7d057d7f9 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)
2024-12-23 06:58:25 +01:00
Juan M Gómez
8f44c40b6b Adds skipParentCfg back. Bump nimble to a commit where it doesnt rely in the parent config (#24545)
(cherry picked from commit 8ce58fab26)
2024-12-20 15:51:57 +01:00
Juan M Gómez
76935b4c34 (cherry picked from commit 556f217b4c) 2024-12-20 15:49:40 +01:00
Juan M Gómez
30abe60cda Bumps nimble v0.16.4 (#24437)
(cherry picked from commit be4d19e562)
2024-12-20 15:48:29 +01:00
ringabout
14dfabb230 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)
2024-12-20 07:52:00 +01:00
ringabout
5fb4662ab1 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)
2024-12-20 05:33:40 +01:00
metagn
535556875e fix logic for dcEqIgnoreDistinct in sameType (#24197)
fixes #22523

There were 2 problems with the code in `sameType` for
`dcEqIgnoreDistinct`:

1. The code that skipped `{tyDistinct, tyGenericInst}` only ran if the
given types had different kinds. This is fixed by always performing this
skip.
2. The code block below that checks if `tyGenericInst`s have different
values still ran for `dcEqIgnoreDistinct` since it checks if the given
types are generic insts, not the skipped types (and also only the 1st
given type). This is fixed by only invoking this block for `dcEq`;
`dcEqOrDistinctOf` (which is unused) also skips the first given type.
Arguably there is another issue here that `skipGenericAlias` only ever
skips 1 type.

These combined fix the issue (`T` is `GenericInst(V, 1, distinct int)`
and `D[0]` is `GenericInst(D, 0, distinct int)`).

(cherry picked from commit b0e6d28782)
2024-12-20 05:30:27 +01:00
metagn
95fa7f0f12 make distinct conversions addressable in VM (#24124)
fixes #24097

For `nkConv` addresses where the conversion is between 2 types that are
equal between backends, treat assignments the same as assignments to the
argument of the conversion. In the VM this seems to be in `genAsgn` and
`genAsgnPatch`, as evidenced by the special logic for `nkDerefExpr` etc.

This doesn't handle ranges after #24037 because `sameBackendType` is
used and not `sameBackendTypeIgnoreRange`. This is so this is
backportable without #24037 and another PR can be opened that implements
it for ranges and adds tests as well. We can also merge
`sameBackendTypeIgnoreRange` with `sameBackendType` since it doesn't
seem like anything that uses it would be affected (only cycle checks and
the VM), but then we still have to add tests.

(cherry picked from commit 1fbb67ffe9)
2024-12-20 05:21:18 +01:00
bptato
6bcb078476 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)
2024-12-17 15:58:34 +01:00
metagn
5c58e7d201 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)
2024-12-17 15:58:33 +01:00
metagn
5327498547 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)
2024-12-17 14:38:42 +01:00
ringabout
d84d41dc95 fixes #24371; incorrect importc wrapper incompatible with gcc 14 on Windows (#24388)
fixes #24371

(cherry picked from commit 74df699ff1)
2024-12-17 14:38:32 +01:00
ringabout
693b35b59f fixes #23545; C compiler error when default initializing an object field function (#24375)
fixes #23545

(cherry picked from commit 815bbf0e73)
2024-12-17 14:38:23 +01:00
bptato
c1bb144fdc 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)
2024-12-17 14:35:25 +01:00
ringabout
1f38c3cea8 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)
2024-12-17 14:34:27 +01:00
metagn
f45ca4fdf4 only generate first field for default value of union (#24303)
fixes #20653

(cherry picked from commit 6df050d6d2)
2024-12-16 17:42:19 +01:00
metagn
5cbc7a6d1b fix regression with generic params in static type (#24075)
Caught in https://github.com/metagn/applicates, I'm not sure which
commit causes this but it's also in the 2.0 branch (but not 2.0.2), so
it's not any recent PRs.

If a proc has a static parameter with type `static Foo[T]`, then another
parameter with type `static Bar[T, U]`, the generic instantiation for
`Bar` doesn't match `U` which has type `tyGenericParam`, but matches `T`
since it has type `tyTypeDesc`. The reason is that `concreteType`
returns the type itself for `tyTypeDesc` if `c.isNoCall` (i.e. matching
a generic invocation), but returns `nil` for `tyGenericParam`. I'm
guessing `tyGenericParam` is received here because of #22618, but that
doesn't explain why `T` is still `tyTypeDesc`. I'm not sure.

Regardless, we can just copy the behavior for `tyTypeDesc` to
`tyGenericParam` and also return the type itself when `c.isNoCall`. This
feels like it defeats the purpose of `concreteType` but the way it's
used doesn't make sense without it (generic param can't match another
generic param?). Alternatively we could loosen the `if concrete == nil:
return isNone` checks in some places for specific conditions, whether
`c.isNoCall` or `c.inGenericContext == 0` (though this would need

(cherry picked from commit 24e5b21c90)
2024-12-16 15:11:47 +01:00
metagn
56e7c75e03 fix int32's that should be uint32 on BSD & OSX (#24078)
fixes #24076

As described in #24076, misannotating these types causes codegen errors.
Sources for the types are https://github.com/openbsd/src/blob/master/sys
for BSD and https://opensource.apple.com/source/Libinfo/Libinfo-391/ and
[_types.h](https://opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/sys/_types.h.auto.html)
for OSX.

(cherry picked from commit 7de4ace949)
2024-12-16 15:11:03 +01:00
metagn
d51236e9cc fix string literal assignment with different lengths on ARC (#24083)
fixes #24080

(cherry picked from commit cd22560af5)
2024-12-16 15:10:58 +01:00
metagn
4d0d848235 fix undeclared identifier in templates in generics (#24069)
fixes #13979

Fixes templates in generics that use identifiers that aren't defined
yet, giving an early `undeclared identifier` error, by just marking
template bodies as in a mixin context in `semgnrc`.

(cherry picked from commit bf865fa75a)
2024-12-16 15:10:46 +01:00
ringabout
8859f1ddf7 fixes #24034; fixes lent types after taking implicit address (#24035)
fixes #24034

(cherry picked from commit 11ead19bc1)
2024-12-16 15:09:57 +01:00
metagn
0e2b34ce35 fix subscript magic giving unresolved generic param type (#23988)
fixes #19737

As in the diff, `semResolvedCall` sets the return type of a call to a
proc to the type of the call. But in the case of the [subscript
magic](https://nim-lang.org/docs/system.html#%5B%5D%2CT%2CI), this type
is the first generic param which is also supposed to be the type of the
first argument, but this is invalid, the correct type is the element
type eventually given by `semSubscript`. Some lines above also [prevent
the subscript magics from instantiating their
params](dda638c1ba/compiler/semcall.nim (L699))
so this type ends up being an unresolved generic param.

Since the type of the node is not `nil`, `prepareOperand` doesn't try to
type it again, and this unresolved generic param type ends up being the
final type of the node. To prevent this, we just never set the type of
the node if we encountered a subscript magic.

Maybe we could also rename the generic parameters of the subscript
magics to stuff like `DummyT`, `DummyI` if we want this to be easier to
debug in the future.

(cherry picked from commit 04da0a6028)
2024-12-16 15:09:00 +01:00
metagn
ba516c8eb5 include generic bodies in allowMetaTypes (#23968)
fixes #19848

Not sure why this wasn't the case already. The `if cl.allowMetaTypes:
return` line below for `tyFromExpr` [was added 10 years
ago](d5798b43de).
Hopefully it was just negligence?

(cherry picked from commit 1befb8d4a3)
2024-12-16 15:07:47 +01:00
metagn
009a5b0684 bypass constraints for tyFromExpr in generic bodies (#23863)
fixes #19819, fixes #23339

Since #22029 `tyFromExpr` does not match anything in overloading, so
generic bodies can know which call expressions to delay until the type
can be evaluated. However generic type invocations also run overloading
to check for generic constraints even in generic bodies. To prevent them
from failing early from the overload not matching, pretend that
`tyFromExpr` matches. This mirrors the behavior of the compiler in more
basic cases like:

```nim
type
  Foo[T: int] = object
    x: T
  Bar[T] = object
    y: Foo[T]
```

Unfortunately this case doesn't respect the constraint (#21181, some
other bugs) but `tyFromExpr` should easily use the same principle when
it does.

(cherry picked from commit 31ee75f10e)
2024-12-16 15:06:10 +01:00
SirOlaf
c786415eef Set type of object constructor during annotateType (#23852)
Fix https://github.com/nim-lang/Nim/issues/23547

Tested locally with the included test, the test from constantine and the
original issue.

(cherry picked from commit f765898a75)
2024-12-16 15:06:00 +01:00
Yuriy Glukhov
33dc54c573 Check for nil in cstringArrayToSeq (#23747)
This fixes crashes in some specific network configurations (as
`cstringArrayToSeq` is used extensively in `nativesockets`).

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 2c83f94544)
2024-12-16 15:03:09 +01:00
Marius Andra
6a1d1a8c2b fixes 12381, HttpClient socket handle leak (#23575)
## Bug

Fixes https://github.com/nim-lang/Nim/issues/12381 - HttpClient socket
handle leak

To replicate the bug, run the following code in a loop:

```nim
import httpclient
while true:
    echo "New loop"
    var client = newHttpClient(timeout = 1000)
    try:
        let response = client.request("http://10.44.0.4/bla", httpMethod = HttpPost, body = "boo")
        echo "HTTP " & $response.status
    except CatchableError as e:
        echo "Error sending logs: " & $e.msg
    finally:
        echo "Finally"
        client.close()
```

Note the IP address as the hostname. I'm directly connecting to a
plausible local IP, but one that does not resolve, as I have everything
under 10.4.x.x.

The output looks like this to me:

```
New loop
Error sending logs: Operation timed out
Finally
New loop
Error sending logs: Operation timed out
Finally
New loop
...
```

In Nim 2.0.4, running the code above leaks the socket:

<img width="944" alt="Screenshot 2024-05-05 at 22 00 13"
src="https://github.com/nim-lang/Nim/assets/53387/ddac67db-d7df-45e6-b7a5-3d42f79775ea">

## Fix

With the added line of code, each old socket is cleanly removed:

<img width="938" alt="Screenshot 2024-05-05 at 21 54 18"
src="https://github.com/nim-lang/Nim/assets/53387/5b0b4b2d-d4f0-4e74-a9cf-74aec0c50d2e">

I believe the line below, `closeUnusedFds(ord(domain))` was supposed to
clean up the failed connection attempts, but it failed to do so for the
last one, assuming it succeeded. Yet it didn't. This fix makes sure
failed connections are closed immediately.

## Tests

I don't have a test with this PR. When testing locally, the
`connect(lastFd, ..)` call on line 2032 blocks for ~75 seconds, ignoring
the http timeout. I fear any test I could add would either 1) take way
too long, 2) one day run in an environment where my randomly chosen IP
is real, yielding in weird flakes.

The only bug i can imagine is if running `lastFd.close()` twice is a bad
idea. I tested by actually running it twice, and... no crash/op? So
seems safe? I'm hoping the CI run will be green, and this will be
enough. However I'm happy to take feedback on how I should test this,
and do the necessary changes.

~Edit: looks like a test does fail, so moving to a draft while I figure
this out.~ Attempt 2 fixed it.

(cherry picked from commit e6f66e4d13)
2024-12-16 15:02:56 +01:00
ringabout
0c426e7875 fixes #23295; don't expand constants for complex structures (#23297)
fixes #23295

(cherry picked from commit 39f2df1972)
2024-12-16 15:02:23 +01:00
ringabout
4e1b5ee702 fixes #18104; tranform one liner var decl before templates expansion (#23294)
fixes #18104

(cherry picked from commit 1e9a3c438b)
2024-12-16 15:01:45 +01:00
ringabout
3a334e09ea fixes #23233; Regression when using generic type with Table/OrderedTable (#23235)
fixes #23233

(cherry picked from commit 720021908d)
2024-12-16 14:59:51 +01:00
narimiran
dbe9c724a0 Revert "Bumps nimble v0.16.4 (#24437)"
This reverts commit 1778b8354a.
2024-12-16 14:02:04 +01:00
narimiran
9620d206b9 Revert "(cherry picked from commit 556f217b4c)"
This reverts commit 9e5cdc43a6.
2024-12-16 14:01:53 +01:00
Juan M Gómez
9e5cdc43a6 (cherry picked from commit 556f217b4c) 2024-12-16 08:07:55 +01:00
Juan M Gómez
1778b8354a Bumps nimble v0.16.4 (#24437)
(cherry picked from commit be4d19e562)
2024-12-13 19:22:23 +01:00
ringabout
f6f72722bb 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)
2024-12-12 12:27:10 +01:00
metagn
90993aeff6 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)
2024-12-09 09:11:30 +01:00
ringabout
15e5ddc675 fixes #24504; fixes ensureMove for refs (#24505)
fixes #24504

(cherry picked from commit d0288d3b57)
2024-12-08 19:18:30 +01:00
narimiran
9f43f9fa6e bump NimVersion to 2.0.13 2024-12-08 19:18:30 +01:00
narimiran
ce7c6f4f33 bump NimVersion to 2.0.12 2024-10-31 10:28:16 +01:00
ringabout
b0074121ec fixes #24379; better error messages for ill-formed type symbols from macros (#24380)
fixes #24379

(cherry picked from commit d61897459d)
2024-10-29 18:03:00 +01:00
narimiran
3713994ef1 two 2.0-specific fixes 2024-10-28 14:18:56 +01:00
metagn
75bd2d0688 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)
(cherry picked from commit 7ad7ee03e5c0adb6832cbae10a62de7b68ef6fa5)
2024-10-28 09:57:30 +01:00
ringabout
eedfcbeb30 fixes #22389; fixes #19840; don't fold paths containing addr (#23807)
fixes #22389;
fixes #19840

(cherry picked from commit 5c5e7a9b6e)
(cherry picked from commit 00e39185f1d59597d17b69bbccf8879e3427f928)
2024-10-28 09:56:55 +01:00
ringabout
fe72db98c1 fixes addr/hiddenAddr in strictdefs (#23477)
(cherry picked from commit 9b378296f6)
(cherry picked from commit 744b241e4b7cb8c8d9e21e8a7f078d17d9ef90d4)
2024-10-28 09:55:43 +01:00
ringabout
a70b4712fc 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)
2024-10-28 09:17:53 +01:00
ringabout
76d834c182 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)
2024-10-24 15:12:48 +02:00
metagn
72fcda1b35 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)
2024-10-23 08:22:05 +02:00
ringabout
fd9d2f5b82 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)
2024-10-23 08:12:50 +02:00
metagn
d3f7fb3100 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)
2024-10-23 08:12:50 +02:00
metagn
4acc7a5e18 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)
2024-10-23 08:12:50 +02:00
narimiran
e334aad202 cowstrings and ssostrings packages require Nim 2.2 2024-10-11 17:08:15 +02:00
Miran
67d7a7c124 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)
2024-10-11 15:22:53 +02:00
metagn
206bbbd940 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)
2024-10-11 14:19:38 +02:00
Juan M Gómez
cc4c9251f0 Bumps nimble to v0.16.2 (#24283)
(cherry picked from commit af23bc2941)
2024-10-11 14:18:16 +02:00
Miran
8754469f49 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)
2024-10-11 10:18:40 +02:00
metagn
e2ef322754 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)
2024-10-09 07:48:30 +02:00
metagn
4fe17a2d87 delay markUsed for converters until call is resolved (#24243)
fixes #24241

(cherry picked from commit 09043f409f)
2024-10-08 16:32:20 +02:00
Ryan McConnell
cc887c23f4 fixes 23823; array static overload - again (#23824)
#23823

(cherry picked from commit 22ba5abd63)
2024-10-05 18:42:55 +02:00
Ryan McConnell
acd09cec43 fixes #23755; array static inference during overload resolution (#23760)
---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 27abcdd57f)
2024-10-05 18:42:54 +02:00
ringabout
c8094176f1 fixes #24173; always bundle checksums (#24189)
fixes #24173

`cloneDependency` always has its logic to use existing deps

(cherry picked from commit 62a5bb4d0a)
2024-10-05 07:54:20 +02:00
Ryan McConnell
3c66401dee Changing generic weight of tyGenericParam (#22143)
This is in reference to a [feature
request](https://github.com/nim-lang/Nim/issues/22142) that I posted.

I'm making this PR to demonstrate the suggested change and expect that
this should be scrutinized

---------

Co-authored-by: Bung <crc32@qq.com>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 74fa8ed59a)
2024-10-04 10:01:48 +02:00
narimiran
ff46fcfd24 bump NimVersion to 2.0.11 2024-10-04 08:16:27 +02:00
narimiran
e941ee15be bump NimVersion to 2.0.10 2024-09-30 19:18:52 +02:00
metagn
5f119f0cdf allow C atomics on C++ with -d:nimUseCAtomics (#24207)
refs https://github.com/nim-lang/Nim/pull/24200#issuecomment-2382501282

Workaround for C++ Atomic[T] issues that doesn't require a compiler
change. Not tested or documented in case it's not meant to be officially
supported, locally tested `tatomics` and #24159 to work with it though,
can add these as tests if required.

(cherry picked from commit febc58e036)
2024-09-30 18:58:01 +02:00
metagn
0636bd2a04 fix cyclic node flag getting added to sink call [backport:2.0] (#24194)
Sorry I don't have a test case or issue for this. `injectdestructors` is
supposed to add a final bool argument to `=copy` and `=dup` to mark
cyclic types, as generated by `liftdestructors`. Hence this flag is
added after every call to `genCopy`, but `genCopy` can generate a
`=sink` call when passed the flag `IsExplicitSink` by `nkSinkAsgn`. This
creates a codegen error, saying the sink received an extra argument.
This is fixed by not adding the argument on the flag `IsExplicitSink`.

This is a followup to #20585 which is on the 2.0 branch, hence this is
marked backport.

(cherry picked from commit 7974a2208c)
2024-09-30 18:29:19 +02:00
metagn
2499336fef remove prev == nil requirement for typedesc params as type nodes (#24206)
fixes #24203

`semTypeNode` is called twice for RHS'es of type sections,
[here](b0e6d28782/compiler/semstmts.nim (L1612))
and
[here](b0e6d28782/compiler/semstmts.nim (L1646)).
Each time `prev` is `s.typ`, but the assertion expects `prev == nil`
which is false since `s.typ` is not nil the second time. To fix this,
the `prev == nil` part of the assertion is removed.

The reason this only happens for types like `seq[int]`, `(int, int)` etc
is because they don't have syms: `semTypeIdent` attempts to directly
[replace the typedesc param
itself](b0e6d28782/compiler/semtypes.nim (L1916))
with the sym of the base type of the resolved typedesc type if it
exists, which means `semTypeNode` doesn't receive the typedesc param sym
to perform the assert.

(cherry picked from commit 2a48182288)
2024-09-30 18:24:24 +02:00
ringabout
1ba16876f1 fixes #24167; {.push deprecated.} for templates (#24170)
fixes #24167

(cherry picked from commit 3b85c1a2e9)
2024-09-28 08:18:28 +02:00
metagn
3a180df0d8 fix inTypeofContext leaking after compiles raises exception [backport:2.0] (#24152)
fixes #24150, refs #22022

An exception is raised in the `semExprWithType` call, which means `dec
c.inTypeofContext` is never called, but `compiles` allows compilation to
continue. This means `c.inTypeofContext` is left perpetually nonzero,
which prevents `compileTime` evaluation for the rest of the program.

To fix this, `defer:` is used for the `dec c.inTypeofContext` call, as
is done for
[`instCounter`](d51d88700b/compiler/seminst.nim (L374))
in other parts of the compiler.

(cherry picked from commit a1777200c1)
2024-09-28 08:18:04 +02:00
metagn
9d65507d20 fix nil literal giving itself type untyped/typed [backport] (#24165)
fixes #24164, regression from #20091

The expression `nil` as the default value of template parameter `x:
untyped` is typechecked with expected type `untyped` since #20091. The
expected type is checked if it matches the `nil` literal with a match
better than a subtype match, and the type is set to it if it does.
However `untyped` matches with a generic match which is better, so the
`nil` literal has type `untyped`. This breaks type matching for the
literal. So if the expected type is `untyped` or `typed`, it is now
ignored and the `nil` literal just has the `nil` type.

(cherry picked from commit b9de2bb4f3)
2024-09-23 17:24:59 +02:00
Ryan McConnell
78003e9f7b Fix incorrect inheritance penalty for some objects (#24144)
This fixes a logic error in  #23870
The inheritance penalty should be -1 if there is no inheritance
relationship. Not sure how to write a test case for this one honestly.

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 37dba853c9)
2024-09-23 16:41:38 +02:00
metagn
27381cc602 make genericsOpenSym work at instantiation time, new behavior in openSym (#24111)
alternative to #24101

enabled in the context of the generic/template declarations capturing
the symbols, not the context of the instantiation of the
generics/templates. This was to be in line with where the compiler gives
the warnings and changes behavior in a potentially breaking way.

However `results` [depends on the old
behavior](71d404b314/results.nim (L1428)),
so that the callers of the macros provided by results always take
advantage of the opensym behavior. To accomodate this, we change the
behavior of the old experimental option that `results` uses,
`genericsOpenSym`, so that ignores the information of whether or not
symbols are intentionally opened and always gives the opensym behavior
as long as it's enabled at instantiation time. This should keep
`results` working as is. However this differs from the normal opensym
switch in that it doesn't generate `nnkOpenSym`.

Before it was just a generics-only version of `openSym` along with
`templateOpenSym` which was only for templates. So `templateOpenSym` is
removed along with this change, but no one appears to have used it.

(cherry picked from commit 0c3573e4a0)
2024-09-18 19:36:30 +02:00
metagn
dd9cb0425c fix segfault in effect tracking for sym node with nil type (#24114)
fixes #24112

Sym nodes in templates that could be open are [given `nil`
type](22d2cf2175/compiler/semtempl.nim (L274))
when `--experimentalOpenSym` is disabled so that they can be semchecked
to give a warning since #24007. The first nodes of object constructors
(in this case) and in type conversions don't replace their first node
(the symbol) with a typechecked one, they only call `semTypeNode` on it
and leave it as is.

Effect tracking checks if the type of a sym node has a destructor to
check if the node type should be replaced with the sym type. But this
causes a segfault when the type of the node is nil. To fix this, we
always set the node type to the sym type if the node type is nil.

Alternatively `semObjConstr` and `semConv` could be changed to set the
type of their first node to the found type but I'm not sure if this
would break anything. They could call `semExprWithType` on the first
node but `semTypeNode` would still have to be called (maybe call it
before?). This isn't a problem if the sym node has a type but is just
nested in `nkOpenSym` or `nkOpenSymChoice` which have nil type instead
(i.e. with openSym enabled), so maybe this still is the "most general"
solution, I don't know.

(cherry picked from commit 680a13a142)
2024-09-18 19:27:51 +02:00
metagn
894eee03a5 make var/pointer types not match if base type has to be converted (#24130)
split again from #24038, fixes
https://github.com/status-im/nimbus-eth2/pull/6554#issuecomment-2354977102

`var`/pointer types are no longer implicitly convertible to each other
if their element types either:

* require an int conversion or another conversion operation as long as
it's not to `openarray`,
* are subtypes with pointer indirection,

Previously any conversion below a subrange match would match if the
element type wasn't a pointer type, then it would error later in
`analyseIfAddressTaken`.

Different from #24038 in that the preview define that made subrange
matches also fail to match is removed for a simpler diff so that it can
be backported.

(cherry picked from commit 1660ddf98a)
2024-09-18 19:25:18 +02:00
ringabout
4b8b8fb9d7 fixes for 32bit system (#23980)
(cherry picked from commit a4dff1a03e)
2024-09-17 13:43:10 +02:00
metagn
3214174f06 opensym for templates + move behavior of opensymchoice to itself (#24007)
fixes #15314, fixes #24002

The OpenSym behavior first added to generics in #23091 now also applies
to templates, since templates can also capture symbols that are meant to
be replaced by local symbols if the context imports symbols with the
same name, as in the issue #24002. The experimental switch
`templateOpenSym` is added to enable this behavior for templates only,
and the experimental switch `openSym` is added to enable it for both
templates and generics, and the documentation now mainly mentions this
switch.

Additionally the logic for `nkOpenSymChoice` nodes that were previously
wrapped in `nkOpenSym` now apply to all `nkOpenSymChoice` nodes, and so
these nodes aren't wrapped in `nkOpenSym` anymore. This means
`nkOpenSym` can only have children of kind `nkSym` again, so it is more
in line with the structure of symchoice nodes. As for why they aren't
merged with `nkOpenSymChoice` nodes yet, we need some way to signal that
the node shouldn't become ambiguous if other options exist at
instantiation time, we already captured a symbol at the beginning and
another symbol can only replace it if it's closer in scope and
unambiguous.

(cherry picked from commit 770f8d5513)
2024-09-16 16:29:37 +02:00
Andreas Rumpf
8bb9823fde fixes #23445; fixes #23418 [backport] (#23699)
(cherry picked from commit 56c95758b2)
2024-09-16 12:30:27 +02:00
SirOlaf
40ee3a950e Fix #22826: Don't skip generic instances in type comparison (#22828)
Close #22826

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

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

---------

Co-authored-by: SirOlaf <>
(cherry picked from commit c13c48500b)
2024-09-16 12:30:27 +02:00
narimiran
74c4b23e0d backport ast.nim refactorings 2024-09-16 12:30:27 +02:00
Juan M Gómez
7180ce6faa bumps nimble to 0.16.1 (#24102)
(cherry picked from commit 6c35a36043)
2024-09-16 10:00:41 +02:00
metagn
fd1d008cce fix regression with uint constant losing abstract type (#24105)
fixes #24104, refs #23955

The line `result.typ = dstTyp` added in #23955 changes the type of
`result`, which was the type of `n` due to the argument passed to
`newIntNodeT`, to the abstract type skipped `dstTyp`. The line is
removed to just keep the type as abstract.

(cherry picked from commit 6d362e0ffe)
2024-09-16 10:00:18 +02:00
ringabout
8bc8347f02 bump checksums (#23975)
ref https://github.com/nim-lang/checksums/pull/16
ref https://github.com/nim-lang/Nim/pull/23970

(cherry picked from commit 0ffc0493a3)
2024-09-13 14:22:54 +02:00
ringabout
33bef682dd fixes cast expressions introduces unnecessary copies (#24004)
It speeds up
```nim
proc foo =
  let piece = cast[seq[char]](newSeqUninit[uint8](5220600386'i64))

foo()
```

Notes that `cast[ref](...)` is excluded because we need to keep the ref
alive if the parameter is something with pointer types (e.g.
`cast[ref](pointer)`or `cast[ref](makePointer(...))`)

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 4ef06a5cc5)
2024-09-13 13:43:53 +02:00
ringabout
bfd4b9b7a4 fixes #23945; type checking for whenvm expresssions (#23970)
fixes #23945

(cherry picked from commit dda638c1ba)
2024-09-13 13:43:45 +02:00
metagn
7d2fe8086f allow untyped arguments to fail to compile in overload mismatch error (#23984)
fixes #8697, fixes #9620, fixes #23265

When matching a `template` with an `untyped` argument fails because of a
mismatching typed argument, `presentFailedCandidates` tries to sem every
single argument to show their types, but trying to type the `untyped`
argument can fail if it's supposed to use an injected symbol, so we get
an unrelated error message like "undeclared identifier".

Instead we use `tryExpr` as the comment suggests, setting the type to
`untyped` if it fails to compile. We could also maybe check if an
`untyped` argument is expected in its place and not try to compile the
expression if it is but this would require a bit of reorganizing the
code here and IMO it's better to have the information of what type it
would be if it can be typed.

(cherry picked from commit 34719cad9d)
2024-09-13 13:43:38 +02:00
metagn
a78834c26c make all generic aliases tyAlias (#23978)
fixes #23977

The problem is that for *any* body of a generic declaration,
[semstmts](2e4d344b43/compiler/semstmts.nim (L1610-L1611))
sets the sym of its value to the generic type name, and
[semtypes](2e4d344b43/compiler/semtypes.nim (L2143))
just directly gives the referenced type *specifically* when the
expression is a generic body. I'm blaming `semtypes` here because it's
responsible for the type given but the exact opposite behavior
specifically written in makes me think generating an alias type here
maybe breaks something.

(cherry picked from commit 58813a3b2e)
2024-09-13 13:43:29 +02:00
metagn
7cbf0ee53c allow generic compileTime proc folding (#22022)
fixes #10753, fixes #22021, refs #19365 (was fixed by #22029, but more
faithful test added)

For whatever reason `compileTime` proc calls did not fold if the proc
was generic ([since this folding was
introduced](c25ffbf262 (diff-539da3a63df08fa987f1b0c67d26cdc690753843d110b6bf0805a685eeaffd40))).
I'm guessing the intention was for *unresolved* generic procs to not
fold, which is now the logic.

Non-magic `compileTime` procs also now don't fold at compile time in
`typeof` contexts to avoid possible runtime errors (only the important)
and prevent double/needless evaluation.

(cherry picked from commit f7c11a8978)
2024-09-13 13:43:23 +02:00
metagn
f86f2928a7 fix is with type/typedesc crashing the compiler (#23967)
fixes #22850

The `is` operator checks the type of the left hand side, and if it's
generic or if it's a `typedesc` type with no base type, it leaves it to
be evaluated later. But `typedesc` types with no base type precisely
describe the default typeclass `type`/`typeclass`, so this condition is
removed. Maybe at some point this represented an unresolved generic
type?

(cherry picked from commit 995081b56a)
2024-09-13 13:43:06 +02:00
ringabout
5f09bf11de fixes #23954; uint8 > 8 bit at compile-time (#23955)
fixes #23954

(cherry picked from commit 298ada3412)
2024-09-13 13:43:00 +02:00
Mark Leyva
25ce25bc42 fix #23817; Use __builtin_saddl_overflow variants for arm-none-eabi-gcc. (#23835)
Provides a fix for #23817.

With target `arm-none-eabi`, GCC defines `int32_t` to `long int`. Nim
uses `__builtin_sadd_overflow` for 32-bit targets, but this emits
warnings on GCC releases 13 and under, while generating an error on GCC
14. More info regarding this
[here](https://gcc.gnu.org/gcc-14/porting_to.html#c) and
[here](https://gcc.gnu.org/pipermail/gcc-cvs/2023-December/394351.html).

The proposed PR attempts to address this issue for these targets by
defining the `nimAddInt`, `nimSubInt`, and `nimMulInt` macros to use the
appropriate compiler intrinsics for this platform.

As for as we know, the LLVM toolchain for bare metal Arm does not define
`int32_t` as `long int` and has no need for this patch. Thus, we only
define the above macros for GCC targeting `arm-non-eabi`.

(cherry picked from commit c5b206d4ac)
2024-09-13 13:42:36 +02:00
ringabout
7503bed717 fixes #14522 #22085 #12700 #23132; no range check for uints (#23930)
fixes #14522
fixes #22085
fixes #12700
fixes #23132
closes https://github.com/nim-lang/Nim/pull/22343 (succeeded by this PR)
completes https://github.com/nim-lang/RFCs/issues/175

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

(cherry picked from commit f0e1eef65e)
2024-09-13 11:10:00 +02:00
ringabout
b7041b250c fixes #23894; succ/pred shouldn't raise OverflowDefect for unsigned integers (#23895)
fixes #23894

keeps it consistent with `inc`

(cherry picked from commit bd063113ec)
2024-09-13 11:09:45 +02:00
Buldram
06d00dfcf6 fixes #19171; have openArray converted from ptr UncheckedArray be mutable (#23882)
Makes `toOpenArray(x: ptr UncheckedArray)` always return a `var
openArray` regardless of if `x` is mutable.

(cherry picked from commit 925dc5c131)
2024-09-13 11:09:35 +02:00
metagn
baa8af92af fix generics treating symchoice symbols as uninstantiated (#23860)
fixes #23853

Since #22610 generics turns the `Name` in the `GT.Name` expression in
the test code into a sym choice. The problem is when the compiler tries
to instantiate `GT.Name` it also instantiates the sym choice symbols.
`Name` has type `template (E: type ExtensionField)` which contains the
unresolved generic type `ExtensionField`, which the compiler mistakes as
an uninstantiated node, when it's just part of the type of the template.
The compilation of the node itself and hence overloading will handle the
instantiation of the proc, so we avoid instantiating it in `semtypinst`,
similar to how the first nodes of call nodes aren't instantiated.

(cherry picked from commit 97f5474545)
2024-09-13 11:09:24 +02:00
ringabout
f09b612f64 fixes #20865; fixes #20987; Missing bounds check in array slicing (#23814)
fixes #20865
fixes #20987

(cherry picked from commit e53a2ed19b)
2024-09-13 11:09:04 +02:00
Mark Leyva
7d0cdfc79d fixes #5091; Ensure we don't wait on an exited process on Linux (#23743)
Fixes #5091.

Ensure we don't wait on an exited process on Linux

(cherry picked from commit 288d5c4ac3)
2024-09-13 11:00:07 +02:00
lit
ae117bd7bc fixes #23732, os.sleep(-1) now returns immediately (#23734)
fixes #23732

(cherry picked from commit 2a658c64d8)
2024-09-13 10:59:57 +02:00
ringabout
b79e603702 ref #20653; fixes chronos empty case branches (#23706)
ref #20653

```nim
  Error* = object
    case kind*: ErrorType
    of ErrorA:
      discard
    of ErrorB:
      discard
```
For an object variants without fields, it shouldn't generate empty
brackets for default values since there are no fields at all in case
branches.

(cherry picked from commit 948bb38335)
2024-09-13 10:56:05 +02:00
c-blake
da2ba43dca Fix non-exported memfiles.setFileSize to be able to shrink files on posix via memfiles.resize (#23717)
Fix non-exported `setFileSize` to take optional `oldSize` to (on posix)
shrink differently than it grows (`ftruncate` not `posix_fallocate`)
since it makes sense to assume the higher address space has already been
allocated there and include the old file size in the `proc resize` call.
Also, do not even try `setFileSize` in the first place unless the `open`
itself works by moving the call into the `if newFileSize != -1` branch.

Just cosmetics, also improve some old 2011 comments, note a logic diff
for callers using both `mappedSize` & `newFileSize` from windows branch
in case someone wants to fix that & simplify code formatting a little.

(cherry picked from commit 8037bbe327)
2024-09-13 10:55:55 +02:00
ringabout
b5ef14ceda fixes #22798; Duplicate libraries linker warning (i.e., '-lm') on macOS (#23292)
fixes #22798

Per
https://stackoverflow.com/questions/33675638/gcc-link-the-math-library-by-default-in-c-on-mac-os-x
and
https://stackoverflow.com/questions/30694042/c-std-library-dont-appear-to-be-linked-in-object-file

> There's no separate math library on OSX. While a lot of systems ship
functions in the standard C math.h header in a separate math library,
OSX does not do that, it's part of the libSystem library, which is
always linked in.

required by https://github.com/nim-lang/Nim/pull/23290

(cherry picked from commit de4c7dfdd9)
2024-09-13 10:24:01 +02:00
ringabout
dc62ee00df fixes #23635; tasks.toTask Doesn't Expect a Dot Expression (#23641)
fixes #23635

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit cc5ce72376)
2024-09-13 10:22:36 +02:00
ringabout
b6a8dcd922 fixes #22852; fixes #23435; fixes #23645; SIGSEGV when slicing string or seq[T] with index out of range (#23279)
follow up https://github.com/nim-lang/Nim/pull/23013

fixes #22852
fixes #23435
fixes #23645

reports rangeDefect correctly

```nim
/workspaces/Nim/test9.nim(1) test9
/workspaces/Nim/lib/system/indices.nim(116) []
/workspaces/Nim/lib/system/fatal.nim(53) sysFatal
Error: unhandled exception: value out of range: -2 notin 0 .. 9223372036854775807 [RangeDefect]
```

(cherry picked from commit c615828ccb)
2024-09-13 10:22:30 +02:00
Alexander Kernozhitsky
37965bd591 Handle arbitrarily long symlink target in expandSymlinks() (#23650)
For now, `expandSymlinks()` can handle only symlinks with lengths up to
1024.

We can improve this logic and retry inside a loop with increasing
lengths until we succeed.

The same approach is used in
[Go](377646589d/src/os/file_unix.go (L446)),
[Rust](785eb65377/library/std/src/sys/pal/unix/fs.rs (L1700))
and [Nim's
`getCurrentDir()`](https://github.com/nim-lang/Nim/blob/devel/lib/std/private/ospaths2.nim#L877),
so maybe it's a good idea to use the same logic in `expandSymlinks()`
also.

(cherry picked from commit 3bda5fc840)
2024-09-13 10:22:20 +02:00
ringabout
c2b4d8a968 fixes reifiedOpenArray; nkHiddenStdConv is PathKinds1 not PathKinds0 (#23633)
(cherry picked from commit 5cd141cebb)
2024-09-13 10:22:11 +02:00
ringabout
8d254a5945 fixes #24053; fixes #18288; relax reorder with push/pop pragmas restrictions; no crossing push/pop barriers (#24061)
fixes #24053;
fixes #18288

makes push pragmas depend on each node before it and nodes after it
depend on it

(cherry picked from commit c10f84b9d7)
2024-09-08 08:42:53 +02:00
ringabout
4856beae70 fixes #23973; fixes #23974; Memory corruption with lent and ORC (#23981)
fixes #23973;
fixes #23974

(cherry picked from commit 26107e931c)
2024-08-31 13:51:52 +02:00
ringabout
568a637f0f fixes semi-regression; discard check now skips nkHiddenSubConv (#23840)
follow up https://github.com/nim-lang/Nim/pull/23681

ref https://forum.nim-lang.org/t/11987

(cherry picked from commit 648f82c2ed)
2024-08-31 13:50:28 +02:00
ringabout
8b421d2203 fixes regression; block can have arbitrary exit points; too hard for a simple analysis (#23839)
follow up https://github.com/nim-lang/Nim/pull/23681

ref https://forum.nim-lang.org/t/11987
ref https://github.com/nim-lang/Nim/issues/23836#issuecomment-2227267251

(cherry picked from commit b7a275da1d)
2024-08-31 13:49:36 +02:00
Ryan McConnell
a5237a5053 Overload resultion with generic variables an inheritance (#23870)
The test case diff is self explanatory

(cherry picked from commit c1f91c26a5)
2024-08-31 13:49:16 +02:00
metagn
d0a8637872 fix noreturn/implicit discard check logic (#23681)
fixes #10440, fixes #13871, fixes #14665, fixes #19672, fixes #23677

The false positive in #23677 was caused by behavior in
`implicitlyDiscardable` where only the last node of `if`/`case`/`try`
etc expressions were considered, as in the final node of the final
branch (in this case `else`). To fix this we use the same iteration in
`implicitlyDiscardable` that we use in `endsInNoReturn`, with the
difference that for an `if`/`case`/`try` statement to be implicitly
discardable, all of its branches must be implicitly discardable.
`noreturn` calls are also considered implicitly discardable for this
reason, otherwise stuff like `if true: discardableCall() else: error()`
doesn't compile.

However `endsInNoReturn` also had bugs, one where `finally` was
considered in noreturn checking when it shouldn't, another where only
`nkIfStmt` was checked and not `nkIfExpr`, and the node given for the
error message was bad. So `endsInNoReturn` now skips over
`skipForDiscardable` which no longer contains
`nkIfStmt`/`nkCaseStmt`/`nkTryStmt`, stores the first encountered
returning node in a var parameter for the error message, and handles
`finally` and `nkIfExpr`.

Fixing #23677 already broke a line in `syncio` so some package code
might be affected.

(cherry picked from commit 42e8472ca6)
2024-08-31 13:45:23 +02:00
metagn
7821aa94eb remove bad type inference behavior for enum identifiers (#23588)
refs
https://github.com/nim-lang/Nim/issues/23586#issuecomment-2102113750

In #20091 a bad kind of type inference was mistakenly left in where if
an identifier `abc` had an expected type of an enum type `Enum`, and
`Enum` had a member called `abc`, the identifier would change to be that
enum member. This causes bugs where a local symbol can have the same
name as an enum member but have a different value. I had assumed this
behavior was removed since but it wasn't, and CI seems to pass having it
removed.

A separate PR needs to be made for the 2.0 branch because these lines
were moved around during a refactoring in #23123 which is not in 2.0.

(cherry picked from commit c101490a0c)
2024-08-31 13:44:58 +02:00
metagn
b1e5dd605a fix wrong subtype relation in tuples & infer some conversions (#23228)
fixes #18125

Previously a tuple type like `(T, int)` would match an expected tuple
type `(U, int)` if `T` is a subtype of `U`. This is wrong since the
codegen does not handle type conversions of individual tuple elements in
a type conversion of an entire tuple. For this reason the compiler
already does not accept `(float, int)` for a matched type `(int, int)`,
however the code that checked for which relations are unacceptable
checked for `< isSubtype` rather than `<= isSubtype`, so subtypes were
not included in the unacceptable relations.

Update: Now only considered unacceptable when inheritance is used, as in
[`paramTypesMatch`](3379d26629/compiler/sigmatch.nim (L2252-L2254)).
Ideally subtype relations that don't need conversions, like `nil`,
`seq[empty]`, `range[0..5]` etc would be their own relation
`isConcreteSubtype` (which would also allow us to differentiate with
`openArray[T]`), but this is too big of a refactor for now.

To compensate for this making things like `let x: (Parent, int) =
(Child(), 0)` not compile (they would crash codegen before anyway but
should still work in principle), type inference for tuple constructors
is updated such that they call `fitNode` on the fields and their
expected types, so a type conversion is generated for the individual
subtype element.

(cherry picked from commit cfd69bad1a)
2024-08-31 13:44:37 +02:00
Ryan McConnell
87ab9b8ac2 typRel and sumGeneric adjustments (#23137)
Filling in some more logic in `typeRel` that I came across when poking
the compiler in another PR. Some of the cases where `typeRel` returns an
"incorrect" result are actually common, but `sumGeneric` ends up
breaking the tie correctly. There isn't anything wrong with that
necessarily, but I assume that it's preferred these functions behave
just as well in isolation as they do when integrated.

I will be following up this description with specific examples.

(cherry picked from commit ccc7c45d71)
2024-08-31 13:41:38 +02:00
metagn
c18e599f53 ambiguous identifier resolution (#23123)
fixes #23002, fixes #22841, refs comments in #23097

When an identifier is ambiguous in scope (i.e. multiple imports contain
symbols with the same name), attempt resolving it through type inference
(by creating a symchoice). To do this efficiently, `qualifiedLookUp` had
to be broken up so that `semExpr` can access the ambiguous candidates
directly (now obtained directly via `lookUpCandidates`).

This fixes the linked issues, but an example like:

```nim
let on = 123

{.warning[ProveInit]: on.}
```

will still fail, since `on` is unambiguously the local `let` symbol here
(this is also true for `proc on` but `proc` symbols generate symchoices
anyway).

Type symbols are not considered to not confuse the type inference. This
includes the change in sigmatch, up to this point symchoices with
nonoverloadable symbols could be created, they just wouldn't be
considered during disambiguation. Now every proper symbol except types
are considered in disambiguation, so the correct symbols must be picked
during the creation of the symchoice node. I remember there being a
violating case of this in the compiler, but this was very likely fixed
by excluding type symbols as CI seems to have found no issues.

The pure enum ambiguity test was disabled because ambiguous pure enums
now behave like overloadable enums with this behavior, so we get a
longer error message for `echo amb` like `type mismatch: got <MyEnum |
OtherEnum> but expected T`

(cherry picked from commit b280100499)
2024-08-31 12:53:43 +02:00
Ryan McConnell
d1aa568de3 Param match relax (#23033)
---------

Co-authored-by: Nikolay Nikolov <nickysn@gmail.com>
Co-authored-by: Pylgos <43234674+Pylgos@users.noreply.github.com>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
Co-authored-by: Jason Beetham <beefers331@gmail.com>
(cherry picked from commit 94f7e9683f)
2024-08-31 12:47:25 +02:00
ringabout
352c82af89 Try to revert "disable presto" (#23987)
Reverts nim-lang/Nim#23958

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

ref https://github.com/nim-lang/Nim/pull/23958#issuecomment-2294848209

(cherry picked from commit eed9cb0d3f)
2024-08-29 06:31:14 +02:00
ringabout
22149422ee fixes LineTooLong hints on old compilers (#22412)
* fixes LineTooLong hints on old compilers

* fixes config/nim.cfg

(cherry picked from commit bf5d173bc6)
2024-08-29 06:23:13 +02:00
ringabout
d6f7625626 disable presto (#23958)
(cherry picked from commit 06b25bd2c4)
2024-08-19 09:25:29 +02:00
narimiran
3e8dfde2f9 Revert "bump NimVersion to 2.0.10"
This reverts commit 92e505577e.
2024-08-19 09:25:03 +02:00
ringabout
3f183f6769 fixes #23936; opcParseFloat accepts the wrong register as the first param [backport] (#23941)
fixes #23936
follow up https://github.com/nim-lang/Nim/pull/20527

(cherry picked from commit b215ec3735)
2024-08-19 09:23:43 +02:00
Alexander Kernozhitsky
1100f550dc [backport] fixes #23796; remove extra indirection for args in importc'ed functions in cpp (#23800)
fixes #23796

(cherry picked from commit 1dcc364cd2)
2024-08-19 09:23:35 +02:00
Juan M Gómez
02eb396f45 bump nimble to include the fix to nimble dump (#23918)
(cherry picked from commit 6126a0bf46)
2024-08-14 11:55:57 +02:00
metagn
796aa78562 opensym as node kind + fixed experimental switch (#23892)
refs https://github.com/nim-lang/Nim/pull/23873#discussion_r1687995060,
fixes #23386, fixes #23385, supersedes #23572

Turns the `nfOpenSym` node flag implemented in #23091 and extended in
containing either `nkSym` or `nkOpenSymChoice`. Since this affects
macros working on generic proc AST, the node kind is now only generated
when the experimental switch `genericsOpenSym` is enabled, and a new
node flag `nfDisabledOpenSym` is set to the `nkSym` or `nkOpenSymChoice`
when the switch is not enabled so that we can give a warning.

Now that the experimental switch has more reasonable semantics, we
define `nimHasGenericsOpenSym2`.

(cherry picked from commit 0c890ff9a7)
2024-08-14 09:36:57 +02:00
metagn
1cc1451ca3 don't treat template/macro/module as overloaded for opensym (#23939)
actually fixes #23865 following up #23873

In the handling of `nkIdent` in `semExpr`, the compiler looks for the
closest symbol with the name and [checks the symbol
kind](6126a0bf46/compiler/semexprs.nim (L3171))
to also consider the overloads if the symbol kind is overloadable. But
it treats the normally overloadable template/macro/module sym kinds the
same as non-overloadable symbols, just calling `semSym` on it. We need
to mirror this behavior in `semOpenSym`; we treat the captured symchoice
as a fresh identifier, so if the symbol we find is a
template/macro/module, we use that symbol immediately as opposed to
waiting for overloads.

(cherry picked from commit a64aa51fe9)
2024-08-14 09:36:56 +02:00
metagn
dd37bb88fe implement genericsOpenSym for symchoices (#23873)
fixes #23865

The node flag `nfOpenSym` implemented in #23091 for sym nodes is now
also implemented for open symchoices. This means the intended behavior
is still achieved when multiple overloads are in scope to be captured,
so the issue is fixed. The code for the flag is documented and moved
into a helper proc and the experimental switch is now enabled for the
compiler test suite.

(cherry picked from commit 469a6044c0)
2024-08-14 09:36:56 +02:00
metagn
a88bce6106 adapt semOpAux to opt-in symchoices (#23750)
fixes #23749, refs #22716

`semIndirectOp` is used here because of the callback expressions, in
this case `db.getProc(...)`, and `semIndirectOp` calls `semOpAux` to
type its arguments before overloading starts. Hence it can opt in to
symchoices since overloading will resolve them.

(cherry picked from commit 948fc29bb2)
2024-08-14 09:08:41 +02:00
metagn
8a4ee2b84f make expressions opt in to symchoices (#22716)
refs #22605

Sym choice nodes are now only allowed to pass through semchecking if
contexts ask for them to (with `efAllowSymChoice`). Otherwise they are
resolved or treated as ambiguous. The contexts that can receive
symchoices in this PR are:

* Call operands and addresses and emulations of such, which will subject
them to overload resolution which will resolve them or fail.
* Type conversion operands only for routine symchoices for type
disambiguation syntax (like `(proc (x: int): int)(foo)`), which will
resolve them or fail.
* Proc parameter default values both at the declaration and during
generic instantiation, which undergo type narrowing and so will resolve
them or fail.

This means unless these contexts mess up sym choice nodes should never
leave the semchecking stage. This serves as a blueprint for future
improvements to intermediate symbol resolution.

Some tangential changes are also in this PR:

1. The `AmbiguousEnum` hint is removed, it was always disabled by
default and since #22606 it only started getting emitted after the
symchoice was soundly resolved.
2. Proc setter syntax (`a.b = c` becoming `` `b=`(a, c) ``) used to
fully type check the RHS before passing the transformed call node to
proc overloading. Now it just passes the original node directly so proc
overloading can deal with its typechecking.

(cherry picked from commit 5f9038a5d7)
2024-08-14 09:08:41 +02:00
SirOlaf
7b834b94da Allocator: Always place free cells into the active chunk and add documentation (#23871)
Lets single threaded applications benefit from tracking foreign cells as
well.
After this, `SmallChunk` technically doesn't need to act as a linked
list anymore I think, gotta investigate that more though.
The likelihood of overflowing `chunk.free` also rises, so to work around
that it might make sense to check `foreignCells` instead of adjusting
free space or replace free with a counter for the local capacity.

For Nim compile I can observe a ~10mb reduction, and smaller ones for
other projects.

(cherry picked from commit 881fbb8f81)
2024-08-13 15:31:16 +02:00
SirOlaf
179ae267e9 Allocator: Track number of foreign cells a small chunk has access to (#23856)
Ref: https://github.com/nim-lang/Nim/issues/23788

There was a small leak in the above issue even after fixing the
segfault. The sizes of `free` and `acc` were changed to 32bit because
adding the `foreignCells` field will drastically increase the memory
usage for programs that hold onto memory for a long time if they stay as
64bit.

(cherry picked from commit fd1e62a7e2)
2024-08-13 15:31:16 +02:00
ringabout
5d872321b3 make -d:debugHeapLinks compile again (#23126)
I have made `realloc` absorb unused adjacent memory, which improves the
performance. I'm investigating whether `deallocOsPages` can be used to
improve memory comsumption.

(cherry picked from commit 53855a9fa3)
2024-08-13 15:23:19 +02:00
Andreas Rumpf
ff1881a4c1 fixes #22510 (#23100)
(cherry picked from commit 69d0b73d66)
2024-08-13 15:22:06 +02:00
Juan M Gómez
702f8342ff bump nimble to 0.16.0 (#23883)
(cherry picked from commit ccf90f5bcb)
2024-08-01 13:33:05 +02:00
narimiran
92e505577e bump NimVersion to 2.0.10 2024-07-17 14:44:53 +02:00
metagn
1ce954a0cf make routine implicitly gensym when other gensym symbol exists again (#23842)
fixes #23813, partially reverts #23392

Before #23392, if a `gensym` symbol was defined before a proc with the
same name in a template even with an `inject` annotation, the proc would
be `gensym`. After #23392 the proc was instead changed to be `inject` as
long as no `gensym` annotation was given. Now, to keep compatibility
with the old behavior, the behavior is changed back to infer the proc as
`gensym` when no `inject` annotation is given, however an explicit
`inject` annotation will still inject the proc. This is also documented
in the manual as the old behavior was undocumented and the new behavior
is slightly different.

(cherry picked from commit cd946084ab)
2024-07-16 13:00:15 +02:00
ringabout
76e6130f64 patches for #23129 (#23198)
fixes it in the normal situation

(cherry picked from commit 30cb6826c0)
2024-07-09 20:09:41 +02:00
ringabout
83455cf1d5 fixes #23129; fixes generated hooks raise unlisted Exception, which never raise (#23195)
fixes #23129

(cherry picked from commit 62c5b8b287)
2024-07-09 20:09:41 +02:00
ringabout
be99f2fed8 fixes #22286; enforce Non-var T destructors by nimPreviewNonVarDestructor (#22975)
fixes #22286
ref https://forum.nim-lang.org/t/10642

For backwards compatibilities, we might need to keep the changes under a
preview compiler flag. Let's see how many packags it break.

**TODO** in the following PRs

- [ ] Turn the `var T` destructors warning into an error with
`nimPreviewNonVarDestructor`

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 379299a5ac)
2024-07-09 20:09:41 +02:00
Juan M Gómez
cbcf6c5be6 Bumps nimble so the next Nim release includes the latest changes (#23808)
(cherry picked from commit 14f86b3965)
2024-07-09 08:19:26 +02:00
SirOlaf
e4db9bffba Adjust the correct chunk's free space in allocator (#23795)
Fixes #23788

(cherry picked from commit 3f5016f60e)
2024-07-09 08:19:16 +02:00
Alexander Kernozhitsky
ecc7e3d41d fixes #23790; roll back instCounter properly in case of exceptions (#23802)
fixes #23790

(cherry picked from commit 841d30a213)
2024-07-08 11:17:49 +02:00
narimiran
22896b3a95 bump NimVersion to 2.0.9 2024-07-08 11:17:49 +02:00
David Krause
eaf0e7ff60 Update mimetypes.nim; added avif & avifs (#23786)
Added avif and avifs to mimetypes
2024-07-03 22:47:42 +02:00
narimiran
5935c3bfa9 bump NimVersion to 2.0.8 2024-07-02 17:05:59 +02:00
ringabout
2114414099 fixes #19977; rework inlining of 'var openarray' iterators for C++ (#23258)
fixes #19977

(cherry picked from commit f7c6e04cfb)
2024-07-02 06:06:13 +02:00
Alexander Kernozhitsky
3788aa0a99 [backport] fixes #23748; do not skip materializing temporaries for proc arguments (#23769)
fixes #23748

(cherry picked from commit 4202b606b1)
2024-06-30 18:54:32 +02:00
Alexander Kernozhitsky
e98c98b46c Comment out flaky test in tests/stdlib/thttpclient (#23772)
```
$ curl -v http://example.com/404 |& grep 'HTTP/1.1'
> GET /404 HTTP/1.1
< HTTP/1.1 500 Internal Server Error
```

So, the test with http://example.com/404 should be disabled, I think.

(cherry picked from commit c88894bf76)
2024-06-30 07:28:27 +02:00
narimiran
51723bace8 getTemp has a different signature in Nim 2.0.x 2024-06-29 13:03:12 +02:00
Juan Carlos
a90e687d26 Document move limitations (#23763)
- See
https://github.com/nim-lang/Nim/issues/23759#issuecomment-2192123783

(cherry picked from commit 179897e55f)
2024-06-29 12:57:47 +02:00
Juan M Gómez
4b42170022 Bumps nimble to entryPoints commit (#23766)
(cherry picked from commit 9f74baa49d)
2024-06-29 12:57:17 +02:00
ringabout
2eff34f08a fixes commit hashes (#23520)
(cherry picked from commit 1185b93c6d)
2024-06-29 12:57:02 +02:00
ringabout
ba51e7c4d8 bundle atlas with sat (#23375)
pending https://github.com/nim-lang/atlas/pull/119
pending AtlasStableCommit updates

(cherry picked from commit 2a7ddcab2d)
2024-06-29 12:55:30 +02:00
ringabout
d259099ef0 fixes #23759; rework move for refc (#23764)
fixes #23759

(cherry picked from commit 56ed4e0bb9)
2024-06-29 12:38:52 +02:00
ringabout
915cd5b28b fixes #9940; genericAssign does not take care of the importC variables in refc [backport] (#23761)
fixes #9940

(cherry picked from commit 828cd58d8a)
2024-06-26 18:50:37 +02:00
Andreas Rumpf
16bbffcb77 fixes #23725; Size computations work better when they are correct (#23758)
[backport]

(cherry picked from commit 8096fa45bd)
2024-06-26 08:15:51 +02:00
ringabout
73af7c60a1 nrvo for embedded importc'ed types (#23708)
(cherry picked from commit 0b5a938f57)
2024-06-25 17:42:36 +02:00
narimiran
7bdcaada13 don't use unknown proc 2024-06-24 11:16:56 +02:00
ringabout
e77e129a05 fixes #23742; setLen(0) no longer allocates memory for uninitialized strs/seqs for refc (#23745)
fixes #23742

Before my PR, `setLen(0)` doesn't free buffer if `s != nil`, but it
allocated unnecessary memory for `strs`. This PR rectifies this
behavior. `setLen(0)` no longer allocates memory for uninitialized
strs/seqs

(cherry picked from commit 2bef08774f)
2024-06-24 08:29:11 +02:00
ringabout
d0b3b7e1a7 [backport] fixes #23711; C code contains backtick`gensym (#23716)
fixes #23711

(cherry picked from commit 646bd99d46)
2024-06-24 08:28:29 +02:00
metagn
2735fd2bf5 ignore uninstantiated static on match to base type [backport:2.0] (#23731)
fixes #23730

Since #23188 the compiler errors when matching a type variable to an
uninstantiated static value. However sometimes an uninstantiated static
value is given even when only a type match is being performed to the
base type of the static type, in the given issue this case is:

```nim
proc foo[T: SomeInteger](x: T): int = int(x)
proc bar(x: static int): array[foo(x), int] = discard
discard bar(123)
```

To deal with this issue we only error when matching against a type
variable constrained to `static`.

Not sure if the `q.typ.kind == tyGenericParam and
q.typ.genericConstraint == tyStatic` check is necessary, the code above
for deciding whether the variable becomes `skConst` doesn't use it.

(cherry picked from commit 128090c593)
2024-06-24 08:26:49 +02:00
Andreas Rumpf
8d1f03e1da fixes a long standing bug with varargs type inference [backport] (#23720)
(cherry picked from commit 5996b12355)
2024-06-24 08:26:19 +02:00
ringabout
d83eb88eb9 disable dnsclient because it is fragile (#23728)
```
  Unhandled exception: /home/runner/work/Nim/Nim/pkgstemp/dnsclient/tests/test1.nim(28, 3) `rr.strings == @["dnsclient.nim"]`  [AssertionDefect]
  [FAILED] query TXT
  [OK] query MX
  [OK] query CNAME
  [OK] query SRV
  Error: execution of an external program failed: '/home/runner/work/Nim/Nim/pkgstemp/dnsclient/tests/test1'
         Tip: 2 messages have been suppressed, use --verbose to show them.
  tools.nim(36)            doCmd

      Error:  Execution failed with exit code 1
          ... Command: /home/runner/work/Nim/Nim/bin/nim c --noNimblePath -d:NimblePkgVersion=0.3.4 --hints:off -r --path:. /home/runner/work/Nim/Nim/pkgstemp/dnsclient/tests/test1
```

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

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

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

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

---------

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

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

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

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

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

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

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

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

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

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

Tested with `gcc version 14.0.1 20240412` locally

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

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

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

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

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

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

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

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

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

---------

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

It should somehow handle default fields in the future

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

fix #23518

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

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

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

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

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

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

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

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

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

it will not behave the same as

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

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

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

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

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

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

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

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

Therefore, the demo above will fail.

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

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

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

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

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

---

In all, that's this PR.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

The experimental switch name is arbitrary and could be changed.

---------

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

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

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

Still possible that this has unintended consequences.

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

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

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

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

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

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

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

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

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

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

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

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

fixes #22939
fixes #16890

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

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

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

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

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

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

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

Tested with:

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

Refer to the discussion in #23125.

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

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

# Cherry-picking to Nim 1.6

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

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

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

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

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

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

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

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

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

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

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

Otherwise it gives implicit results or bad codegen

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

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

---------

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

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

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

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

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

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

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

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

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

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

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

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

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

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

---------

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

The fix follows the suggestions made in #23125.

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

Before:

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

of false:
  nil
```

After:

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

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

```nim
import macros

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

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

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

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

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

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

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

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

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

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

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

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

---------

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

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

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

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

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

---------

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

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

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

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

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

---------

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

fixes #22913
fixes #12985 differently

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

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

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

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

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

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

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

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

---------

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

fixes #22673

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

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

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

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

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

…eDefault` warnings

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

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

It might be more efficient in some cases

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

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

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

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

---------

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

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

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

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

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

fixes #22790

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

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

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

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

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

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

---------

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

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

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

---------

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

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

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

---------

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

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

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

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

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

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

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

Likewise, the index checking is probably not needed.

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

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

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

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

---------

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

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

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

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

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

Merge after #21842.

---------

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

---------

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

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

---------

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

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

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

---------

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

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

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

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

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

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

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

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

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

* adds guard

* adds guard

* removes unnecessary test

* refactor: extracts containsGenericInvocationWithForward

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

fixes #14509

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

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

fixes #22613

* merge branches

* add a test case

* fixes status

* remove outdated comments

* move collectBranchFields into the global scope

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

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

* update grammar

* fix test

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

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

* fix #21737

* Update lambdalifting.nim

* remove containsCallKinds

* simplify

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

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

avoid platform-dependendent error handling strategies

* more fixes

* space

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

fixes #18710

* fix test messages

* use discard instead of continue

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

---------

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

fixes #22525

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

---------

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

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

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

* add test

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

* fix openarray

* fixes openarray

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

* follow suggestions

* mitigate for #4121

* improve error message

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

* Run for all call kinds and ignore typedesc

* Testcase

---------

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

* use new flag tfImplicitStatic

* fix

* fix #14193

* correct tfUnresolved add condition

* clean test

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

* fix innerClosure too earlier, make condition shorter

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

* in error messages

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

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

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

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

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

* fix comparision expression

* Remove splitDrive from searchExtPos

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

* fallback to isGeneric

* change to closer error

* Update t20883.nim

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

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

* add a test

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

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

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

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

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

(cherry picked from commit 642ac0c1c3)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

`--info:nimVer` will return just:

```
2.1.1
```

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

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

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

* Apply suggestions from code review

* Apply suggestions from code review

* change the URL of inim

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

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

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

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

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

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

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

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

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

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

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

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

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

---------

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

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

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

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

* Handle `try` stmt again and add tests

* Fix unreachable code warning

* Remove unreachable code in semexprs again

* Check `it.len` before skip

* Move import of assertions

---------

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

fixes #15760

* add test

* fix getType(typedesc) test

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

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

fixes #19865

* add test

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

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

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

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

* fix template gensym test

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

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

* Add test

---------

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

fixes #22524

* very ugly fixes, but fix #15730

* nil cstring len works, more test lines

* fix high

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

* Update lib/system/sets.nim

---------

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

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

* Add in a bounds check when accessing generic types

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

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

* fixes

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

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

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

Besides, according to the Nim manual

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

At least, destruction of cursor fields might cause troubles.

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

---------

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

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

* Fix tester to ignore version cache param

* fix case of people using -d:nimTestsNimdocFixup

* rsttester needed the same fix

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

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

* fixes the test

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

* Apply suggestions from code review

* Update tests/align/talign.nim

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

* apply code review

* update tests

---------

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

* fixes vm

* fixes nimscript

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

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

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

(cherry picked from commit da368885da)
2023-08-11 10:47:54 +02:00
narimiran
d1db4c29fa bump NimVersion to 2.0.1 2023-08-11 10:47:05 +02:00
narimiran
a488067a41 bump NimVersion to 2.0.0 2023-07-31 21:22:28 +02:00
745 changed files with 13309 additions and 18769 deletions

View File

@@ -71,6 +71,5 @@ body:
which should give more context on a compiler crash.
- If it's a regression, you can help us by identifying which version introduced the bug,
see [Bisecting for regressions](https://nim-lang.github.io/Nim/intern.html#bisecting-for-regressions),
or at least try known past releases (e.g. `choosenim 2.0.0`). The Nim repo also supports online bisecting
via making a comment, which contains a code block starting by `!nim c`, `!nim js` etc. , see [nimrun-action](https://github.com/juancarlospaco/nimrun-action).
or at least try known past releases (eg `choosenim 1.2.0`).
- [Please, consider a Donation for the Nim project.](https://nim-lang.org/donate.html)

View File

@@ -5,27 +5,19 @@ on:
types: created
jobs:
bisects:
if: |
github.event_name == 'issue_comment' && startsWith(github.event.comment.body, '!nim ') && github.event.issue.pull_request == null && github.event.comment.author_association != 'NONE'
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, windows-latest, macos-latest]
name: ${{ matrix.platform }}-bisects
runs-on: ${{ matrix.platform }}
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- uses: jiro4989/setup-nim-action@v1
with:
nim-version: 'devel'
# nimrun-action requires Nim installed.
- uses: jiro4989/setup-nim-action@v1
with:
nim-version: 'devel'
- uses: juancarlospaco/nimrun-action@nim
if: |
runner.os == 'Linux' && contains(github.event.comment.body, '-d:linux' ) ||
runner.os == 'Windows' && contains(github.event.comment.body, '-d:windows') ||
runner.os == 'macOS' && contains(github.event.comment.body, '-d:osx' ) ||
runner.os == 'Linux' && !contains(github.event.comment.body, '-d:linux') && !contains(github.event.comment.body, '-d:windows') && !contains(github.event.comment.body, '-d:osx')
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends -yq valgrind
- uses: juancarlospaco/nimrun-action@nim
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -10,14 +10,14 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04]
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
uses: actions/checkout@v3
with:
fetch-depth: 2
@@ -60,7 +60,7 @@ jobs:
run: nim c -r -d:release ci/action.nim
- name: 'Checkout minimize'
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
repository: 'nim-lang/ci_bench'
path: minimize

View File

@@ -2,7 +2,8 @@ name: Nim Docs CI
on:
push:
paths:
- 'compiler/**.nim'
- 'compiler/docgen.nim'
- 'compiler/renderverbatim.nim'
- 'config/nimdoc.cfg'
- 'doc/**.rst'
- 'doc/**.md'
@@ -17,7 +18,8 @@ on:
pull_request:
# Run only on changes on these files.
paths:
- 'compiler/**.nim'
- 'compiler/docgen.nim'
- 'compiler/renderverbatim.nim'
- 'config/nimdoc.cfg'
- 'doc/**.rst'
- 'doc/**.md'
@@ -41,11 +43,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-11
os: macos-13
name: ${{ matrix.target }}
runs-on: ${{ matrix.os }}
@@ -53,7 +55,7 @@ jobs:
steps:
- name: 'Checkout'
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 2

76
.github/workflows/ci_gcc14.yml vendored Normal file
View File

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

@@ -17,7 +17,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, macos-11]
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 }})'
@@ -28,7 +28,7 @@ jobs:
NIM_TESTAMENT_BATCH: ${{ matrix.batch }}
steps:
- name: 'Checkout'
uses: actions/checkout@v4
uses: actions/checkout@v3
with:
fetch-depth: 2
@@ -48,6 +48,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,20 +11,20 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04]
os: [ubuntu-22.04]
cpu: [amd64]
name: '${{ matrix.os }}'
runs-on: ${{ matrix.os }}
steps:
- name: 'Checkout'
uses: actions/checkout@v4
uses: actions/checkout@v3
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,23 +29,23 @@ jobs:
# vmImage: 'ubuntu-18.04'
# CPU: i386
OSX_amd64:
vmImage: 'macOS-11'
vmImage: 'macOS-13'
CPU: amd64
OSX_amd64_cpp:
vmImage: 'macOS-11'
vmImage: 'macOS-13'
CPU: amd64
NIM_COMPILE_TO_CPP: true
Windows_amd64_batch0_3:
vmImage: 'windows-2019'
vmImage: 'windows-2025'
CPU: amd64
# see also: `NIM_TEST_PACKAGES`
NIM_TESTAMENT_BATCH: "0_3"
Windows_amd64_batch1_3:
vmImage: 'windows-2019'
vmImage: 'windows-2025'
CPU: amd64
NIM_TESTAMENT_BATCH: "1_3"
Windows_amd64_batch2_3:
vmImage: 'windows-2019'
vmImage: 'windows-2025'
CPU: amd64
NIM_TESTAMENT_BATCH: "2_3"
@@ -73,17 +73,19 @@ jobs:
- task: NodeTool@0
inputs:
versionSpec: '20.x'
displayName: 'Install node.js 20.x'
versionSpec: '16.x'
displayName: 'Install node.js 16.x'
condition: and(succeeded(), eq(variables['skipci'], 'false'))
- bash: |
set -e
. ci/funs.sh
echo_run sudo apt-fast update -qq
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,12 +102,12 @@ 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
@@ -130,6 +132,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

@@ -5,16 +5,12 @@
- `-d:nimStrictDelete` becomes the default. An index error is produced when the index passed to `system.delete` was out of bounds. Use `-d:nimAuditDelete` to mimic the old behavior for backwards compatibility.
- The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/<version>` instead of `Nim httpclient/<version>` which was incorrect according to the HTTP spec.
- Methods now support implementations based on a VTable by using `--experimental:vtables`. Methods are then confined to be in the same module where their type has been defined.
- With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default.
## Standard library additions and changes
[//]: # "Changes:"
- Changed `std/osfiles.copyFile` to allow to specify `bufferSize` instead of a hardcoded one.
- Changed `std/osfiles.copyFile` to use `POSIX_FADV_SEQUENTIAL` hints for kernel-level aggressive sequential read-aheads.
- `std/htmlparser` has been moved to a nimble package, use `nimble` or `atlas` to install it.
[//]: # "Additions:"
@@ -23,24 +19,115 @@
slots when enlarging a sequence.
- Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value.
- Added Viewport API for the JavaScript targets in the `dom` module.
- Added `toSinglyLinkedRing` and `toDoublyLinkedRing` to `std/lists` to convert from `openArray`s.
- ORC: To be enabled via `nimOrcStats` there is a new API called `GC_orcStats` that can be used to query how many
objects the cyclic collector did free. If the number is zero that is a strong indicator that you can use `--mm:arc`
instead of `--mm:orc`.
- A `$` template is provided for `Path` in `std/paths`.
[//]: # "Deprecations:"
- Deprecates `system.newSeqUninitialized`, which is replaced by `newSeqUninit`.
[//]: # "Removals:"
## Language changes
- `noInit` can be used in types and fields to disable member initializers in the C++ backend.
- C++ custom constructors initializers see https://nim-lang.org/docs/manual_experimental.htm#constructor-initializer
- `member` can be used to attach a procedure to a C++ type.
- C++ `constructor` now reuses `result` instead creating `this`.
- The experimental option `--experimental:openSym` has been added to allow
captured symbols in generic routine and template bodies respectively to be
replaced by symbols injected locally by templates/macros at instantiation
time. `bind` may be used to keep the captured symbols over the injected ones
regardless of enabling the option, but other methods like renaming the
captured symbols should be used instead so that the code is not affected by
context changes.
Since this change may affect runtime behavior, the experimental switch
`openSym` needs to be enabled; and a warning is given in the case where an
injected symbol would replace a captured symbol not bound by `bind` and
the experimental switch isn't enabled.
```nim
const value = "captured"
template foo(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
body
proc old[T](): string =
foo(123):
return value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
echo old[int]() # "captured"
template oldTempl(): string =
block:
foo(123):
value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
echo oldTempl() # "captured"
{.experimental: "openSym".}
proc bar[T](): string =
foo(123):
return value
assert bar[int]() == "injected" # previously it would be "captured"
proc baz[T](): string =
bind value
foo(123):
return value
assert baz[int]() == "captured"
template barTempl(): string =
block:
foo(123):
value
assert barTempl() == "injected" # previously it would be "captured"
template bazTempl(): string =
bind value
block:
foo(123):
value
assert bazTempl() == "captured"
```
This option also generates a new node kind `nnkOpenSym` which contains
exactly 1 `nnkSym` node. In the future this might be merged with a slightly
modified `nnkOpenSymChoice` node but macros that want to support the
experimental feature should still handle `nnkOpenSym`, as the node kind would
simply not be generated as opposed to being removed.
Another experimental switch `genericsOpenSym` exists that enables this behavior
at instantiation time, meaning templates etc can enable it specifically when
they are being called. However this does not generate `nnkOpenSym` nodes
(unless the other switch is enabled) and so doesn't reflect the regular
behavior of the switch.
```nim
const value = "captured"
template foo(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
{.push experimental: "genericsOpenSym".}
body
{.pop.}
proc bar[T](): string =
foo(123):
return value
echo bar[int]() # "injected"
template barTempl(): string =
block:
var res: string
foo(123):
res = value
res
assert barTempl() == "injected"
```
## Compiler changes
- `--nimcache` using a relative path as the argument in a config file is now relative to the config file instead of the current directory.
## Tool changes

View File

@@ -72,7 +72,7 @@
- `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and
`sink` for optimization purposes.
- The experimental `nimPreviewDotLikeOps` switch is going to be removed or deprecated because it didn't fullfill its promises.
- The experimental `nimPreviewDotLikeOps` switch is going to be removed or deprecated because it didn't fulfill its promises.
- The `{.this.}` pragma, deprecated since 0.19, has been removed.
- `nil` literals can no longer be directly assigned to variables or fields of `distinct` pointer types. They must be converted instead.
@@ -205,7 +205,7 @@
proc prc(): int =
123
iterator iter(): int {.closure.} =
iterator iter(): int =
yield 123
proc takesProc[T: proc](x: T) = discard

View File

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

View File

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

View File

@@ -74,7 +74,7 @@ proc aliases*(obj, field: PNode): AliasKind =
# x[i] -> x[i]: maybe; Further analysis could make this return true when i is a runtime-constant
# x[i] -> x[j]: maybe; also returns maybe if only one of i or j is a compiletime-constant
template collectImportantNodes(result, n) =
var result: seq[PNode] = @[]
var result: seq[PNode]
var n = n
while true:
case n.kind

View File

@@ -10,9 +10,7 @@
## Simple alias analysis for the HLO and the code generators.
import
ast, astalgo, types, trees
import std/intsets
ast, astalgo, types, trees, intsets
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -116,8 +114,6 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
# use expensive type check:
if isPartOf(a.sym.typ, b.sym.typ) != arNo:
result = arMaybe
else:
result = arNo
of nkBracketExpr:
result = isPartOf(a[0], b[0])
if a.len >= 2 and b.len >= 2:
@@ -153,7 +149,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
result = isPartOf(a[1], b[1])
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isPartOf(a[0], b[0])
else: result = arNo
else: discard
# Calls return a new location, so a default of ``arNo`` is fine.
else:
# go down recursively; this is quite demanding:
@@ -169,7 +165,6 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
of DerefKinds:
# a* !<| b[] iff
result = arNo
if isPartOf(a.typ, b.typ) != arNo:
result = isPartOf(a, b[0])
if result == arNo: result = arMaybe
@@ -191,9 +186,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
if isPartOf(a.typ, b.typ) != arNo:
result = isPartOf(a[0], b)
if result == arNo: result = arMaybe
else:
result = arNo
else: result = arNo
else: discard
of nkObjConstr:
result = arNo
for i in 1..<b.len:
@@ -211,6 +204,4 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
of nkBracket:
if b.len > 0:
result = isPartOf(a, b[0])
else:
result = arNo
else: result = arNo
else: discard

View File

@@ -10,10 +10,8 @@
# abstract syntax tree + symbol table
import
lineinfos, options, ropes, idents, int128, wordrecg
import std/[tables, hashes]
from std/strutils import toLowerAscii
lineinfos, hashes, options, ropes, idents, int128, tables, wordrecg
from strutils import toLowerAscii
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -229,11 +227,12 @@ type
nkModuleRef # for .rod file support: A (moduleId, itemId) pair
nkReplayAction # for .rod file support: A replay action
nkNilRodNode # for .rod file support: a 'nil' PNode
nkOpenSym # container for captured sym that can be overriden by local symbols
TNodeKinds* = set[TNodeKind]
type
TSymFlag* = enum # 51 flags!
TSymFlag* = enum # 52 flags!
sfUsed, # read access of sym (for warnings) or simply used
sfExported, # symbol is exported from module
sfFromGeneric, # symbol is instantiation of a generic; this is needed
@@ -316,8 +315,8 @@ type
# an infinite loop, this flag is used as a sentinel to stop it.
sfVirtual # proc is a C++ virtual function
sfByCopy # param is marked as pass bycopy
sfMember # proc is a C++ member of a type
sfCodegenDecl # type, proc, global or proc param is marked as codegenDecl
sfWasGenSym # symbol was 'gensym'ed
TSymFlags* = set[TSymFlag]
@@ -350,7 +349,6 @@ const
sfBase* = sfDiscriminant
sfCustomPragma* = sfRegister # symbol is custom pragma template
sfTemplateRedefinition* = sfExportc # symbol is a redefinition of an earlier template
sfCppMember* = { sfVirtual, sfMember, sfConstructor } # proc is a C++ member, meaning it will be attached to the type definition
const
# getting ready for the future expr/stmt merge
@@ -520,6 +518,9 @@ type
nfFirstWrite # this node is a first write
nfHasComment # node has a comment
nfSkipFieldChecking # node skips field visable checking
nfDisabledOpenSym # temporary: node should be nkOpenSym but cannot
# because openSym experimental switch is disabled
# gives warning instead
TNodeFlags* = set[TNodeFlag]
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 47)
@@ -927,7 +928,7 @@ type
# for variables a slot index for the evaluator
offset*: int32 # offset of record field
disamb*: int32 # disambiguation number; the basic idea is that
# `<procname>__<module>_<disamb>` is unique
# `<procname>__<module>_<disamb>`
loc*: TLoc
annex*: PLib # additional fields (seldom used, so we use a
# reference to another object to save space)
@@ -939,7 +940,6 @@ type
# it won't cause problems
# for skModule the string literal to output for
# deprecated modules.
instantiatedFrom*: PSym # for instances, the generic symbol where it came from.
when defined(nimsuggest):
allUsages*: seq[TLineInfo]
@@ -962,7 +962,7 @@ type
kind*: TTypeKind # kind of type
callConv*: TCallingConvention # for procs
flags*: TTypeFlags # flags of the type
sons: TTypeSeq # base types, etc.
sons*: TTypeSeq # base types, etc.
n*: PNode # node for types:
# for range types a nkRange node
# for record types a nkRecord node
@@ -1043,8 +1043,6 @@ proc comment*(n: PNode): string =
if nfHasComment in n.flags and not gconfig.useIc:
# IC doesn't track comments, see `packed_ast`, so this could fail
result = gconfig.comments[n.nodeId]
else:
result = ""
proc `comment=`*(n: PNode, a: string) =
let id = n.nodeId
@@ -1095,7 +1093,8 @@ const
nfIsRef, nfIsPtr, nfPreventCg, nfLL,
nfFromTemplate, nfDefaultRefsParam,
nfExecuteOnReload, nfLastRead,
nfFirstWrite, nfSkipFieldChecking}
nfFirstWrite, nfSkipFieldChecking,
nfDisabledOpenSym}
namePos* = 0
patternPos* = 1 # empty except for term rewriting macros
genericParamsPos* = 2
@@ -1111,7 +1110,7 @@ const
nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
nkCommand, nkCallStrLit, nkHiddenCallConv}
nkIdentKinds* = {nkIdent, nkSym, nkAccQuoted, nkOpenSymChoice,
nkClosedSymChoice}
nkClosedSymChoice, nkOpenSym}
nkPragmaCallKinds* = {nkExprColonExpr, nkCall, nkCallStrLit}
nkLiterals* = {nkCharLit..nkTripleStrLit}
@@ -1139,6 +1138,7 @@ proc getPIdent*(a: PNode): PIdent {.inline.} =
of nkSym: a.sym.name
of nkIdent: a.ident
of nkOpenSymChoice, nkClosedSymChoice: a.sons[0].sym.name
of nkOpenSym: getPIdent(a.sons[0])
else: nil
const
@@ -1166,7 +1166,7 @@ proc idGeneratorFromModule*(m: PSym): IdGenerator =
proc idGeneratorForPackage*(nextIdWillBe: int32): IdGenerator =
result = IdGenerator(module: PackageModuleId, symId: nextIdWillBe - 1'i32, typeId: 0, disambTable: initCountTable[PIdent]())
proc nextSymId(x: IdGenerator): ItemId {.inline.} =
proc nextSymId*(x: IdGenerator): ItemId {.inline.} =
assert(not x.sealed)
inc x.symId
result = ItemId(module: x.module, item: x.symId)
@@ -1231,7 +1231,6 @@ proc getDeclPragma*(n: PNode): PNode =
case n.kind
of routineDefs:
if n[pragmasPos].kind != nkEmpty: result = n[pragmasPos]
else: result = nil
of nkTypeDef:
#[
type F3*{.deprecated: "x3".} = int
@@ -1251,8 +1250,6 @@ proc getDeclPragma*(n: PNode): PNode =
]#
if n[0].kind == nkPragmaExpr:
result = n[0][1]
else:
result = nil
else:
# support as needed for `nkIdentDefs` etc.
result = nil
@@ -1261,19 +1258,16 @@ proc getDeclPragma*(n: PNode): PNode =
proc extractPragma*(s: PSym): PNode =
## gets the pragma node of routine/type/var/let/const symbol `s`
if s.kind in routineKinds:
result = s.ast[pragmasPos]
if s.kind in routineKinds: # bug #24167
if s.ast[pragmasPos] != nil and s.ast[pragmasPos].kind != nkEmpty:
result = s.ast[pragmasPos]
else:
result = nil
elif s.kind in {skType, skVar, skLet, skConst}:
if s.ast != nil and s.ast.len > 0:
if s.ast[0].kind == nkPragmaExpr and s.ast[0].len > 1:
# s.ast = nkTypedef / nkPragmaExpr / [nkSym, nkPragma]
result = s.ast[0][1]
else:
result = nil
else:
result = nil
else:
result = nil
assert result == nil or result.kind == nkPragma
proc skipPragmaExpr*(n: PNode): PNode =
@@ -1466,6 +1460,9 @@ proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
result.typ = sym.typ
result.info = info
proc newOpenSym*(n: PNode): PNode {.inline.} =
result = newTreeI(nkOpenSym, n.info, n)
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
result = newNode(kind)
result.intVal = intVal
@@ -1474,7 +1471,42 @@ proc newIntNode*(kind: TNodeKind, intVal: Int128): PNode =
result = newNode(kind)
result.intVal = castToInt64(intVal)
proc lastSon*(n: Indexable): Indexable = n.sons[^1]
proc lastSon*(n: Indexable): Indexable {.inline.} = n.sons[^1]
template setLastSon*(n: PNode, s: PNode) = n.sons[^1] = s
template firstSon*(n: PNode): PNode = n.sons[0]
template secondSon*(n: PNode): PNode = n.sons[1]
template hasSon*(n: PNode): bool = n.len > 0
template has2Sons*(n: PNode): bool = n.len > 1
proc replaceFirstSon*(n, newson: PNode) {.inline.} =
n.sons[0] = newson
proc replaceSon*(n: PNode; i: int; newson: PNode) {.inline.} =
n.sons[i] = newson
proc last*(n: PType): PType {.inline.} = n.sons[^1]
proc elementType*(n: PType): PType {.inline.} = n.sons[^1]
proc skipModifier*(n: PType): PType {.inline.} = n.sons[^1]
proc indexType*(n: PType): PType {.inline.} = n.sons[0]
proc baseClass*(n: PType): PType {.inline.} = n.sons[0]
proc base*(t: PType): PType {.inline.} =
result = t.sons[0]
proc returnType*(n: PType): PType {.inline.} = n.sons[0]
proc setReturnType*(n, r: PType) {.inline.} = n.sons[0] = r
proc setIndexType*(n, idx: PType) {.inline.} = n.sons[0] = idx
proc firstParamType*(n: PType): PType {.inline.} = n.sons[1]
proc firstGenericParam*(n: PType): PType {.inline.} = n.sons[1]
proc typeBodyImpl*(n: PType): PType {.inline.} = n.sons[^1]
proc genericHead*(n: PType): PType {.inline.} = n.sons[0]
proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
## Used throughout the compiler code to test whether a type tree contains or
@@ -1482,7 +1514,7 @@ proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
## last child nodes of a type tree need to be searched. This is a really hot
## path within the compiler!
result = t
while result.kind in kinds: result = lastSon(result)
while result.kind in kinds: result = last(result)
proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode =
let kind = skipTypes(typ, abstractVarRange).kind
@@ -1503,7 +1535,7 @@ proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode =
result = newNode(nkIntLit)
of tyStatic: # that's a pre-existing bug, will fix in another PR
result = newNode(nkIntLit)
else: raiseAssert $kind
else: doAssert false, $kind
result.intVal = intVal
result.typ = typ
@@ -1541,31 +1573,116 @@ proc `$`*(s: PSym): string =
else:
result = "<nil>"
iterator items*(t: PType): PType =
when false:
iterator items*(t: PType): PType =
for i in 0..<t.sons.len: yield t.sons[i]
iterator pairs*(n: PType): tuple[i: int, n: PType] =
for i in 0..<n.sons.len: yield (i, n.sons[i])
when true:
proc len*(n: PType): int {.inline.} =
result = n.sons.len
proc sameTupleLengths*(a, b: PType): bool {.inline.} =
result = a.sons.len == b.sons.len
iterator tupleTypePairs*(a, b: PType): (int, PType, PType) =
for i in 0 ..< a.sons.len:
yield (i, a.sons[i], b.sons[i])
iterator underspecifiedPairs*(a, b: PType; start = 0; without = 0): (PType, PType) =
# XXX Figure out with what typekinds this is called.
for i in start ..< min(a.sons.len, b.sons.len) + without:
yield (a.sons[i], b.sons[i])
proc signatureLen*(t: PType): int {.inline.} =
result = t.sons.len
proc paramsLen*(t: PType): int {.inline.} =
result = t.sons.len - 1
proc genericParamsLen*(t: PType): int {.inline.} =
assert t.kind == tyGenericInst
result = t.sons.len - 2 # without 'head' and 'body'
proc genericInvocationParamsLen*(t: PType): int {.inline.} =
assert t.kind == tyGenericInvocation
result = t.sons.len - 1 # without 'head'
proc kidsLen*(t: PType): int {.inline.} =
result = t.sons.len
proc genericParamHasConstraints*(t: PType): bool {.inline.} = t.sons.len > 0
proc hasElementType*(t: PType): bool {.inline.} = t.sons.len > 0
proc isEmptyTupleType*(t: PType): bool {.inline.} = t.sons.len == 0
proc isSingletonTupleType*(t: PType): bool {.inline.} = t.sons.len == 1
proc genericConstraint*(t: PType): PType {.inline.} = t.sons[0]
iterator genericInstParams*(t: PType): (bool, PType) =
for i in 1..<t.sons.len-1:
yield (i!=1, t.sons[i])
iterator genericInstParamPairs*(a, b: PType): (int, PType, PType) =
for i in 1..<min(a.sons.len, b.sons.len)-1:
yield (i-1, a.sons[i], b.sons[i])
iterator genericInvocationParams*(t: PType): (bool, PType) =
for i in 1..<t.sons.len:
yield (i!=1, t.sons[i])
iterator genericInvocationAndBodyElements*(a, b: PType): (PType, PType) =
for i in 1..<a.sons.len:
yield (a.sons[i], b.sons[i-1])
iterator genericInvocationParamPairs*(a, b: PType): (bool, PType, PType) =
for i in 1..<a.sons.len:
if i >= b.sons.len:
yield (false, nil, nil)
else:
yield (true, a.sons[i], b.sons[i])
iterator genericBodyParams*(t: PType): (int, PType) =
for i in 0..<t.sons.len-1:
yield (i, t.sons[i])
iterator userTypeClassInstParams*(t: PType): (bool, PType) =
for i in 1..<t.sons.len-1:
yield (i!=1, t.sons[i])
iterator ikids*(t: PType): (int, PType) =
for i in 0..<t.sons.len: yield (i, t.sons[i])
const
FirstParamAt* = 1
FirstGenericParamAt* = 1
iterator paramTypes*(t: PType): (int, PType) =
for i in FirstParamAt..<t.sons.len: yield (i, t.sons[i])
iterator paramTypePairs*(a, b: PType): (PType, PType) =
for i in FirstParamAt..<a.sons.len: yield (a.sons[i], b.sons[i])
template paramTypeToNodeIndex*(x: int): int = x
iterator kids*(t: PType): PType =
for i in 0..<t.sons.len: yield t.sons[i]
iterator pairs*(n: PType): tuple[i: int, n: PType] =
for i in 0..<n.sons.len: yield (i, n.sons[i])
iterator signature*(t: PType): PType =
# yields return type + parameter types
for i in 0..<t.sons.len: yield t.sons[i]
proc newType*(kind: TTypeKind, idgen: IdGenerator; owner: PSym, sons: seq[PType] = @[]): PType =
let id = nextTypeId idgen
proc newType*(kind: TTypeKind, id: ItemId; owner: PSym): PType =
result = PType(kind: kind, owner: owner, size: defaultSize,
align: defaultAlignment, itemId: id,
uniqueId: id, sons: sons)
uniqueId: id)
when false:
if result.itemId.module == 55 and result.itemId.item == 2:
echo "KNID ", kind
writeStackTrace()
template newType*(kind: TTypeKind, id: IdGenerator; owner: PSym, parent: PType): PType =
newType(kind, id, owner, parent.sons)
proc setSons*(dest: PType; sons: seq[PType]) {.inline.} = dest.sons = sons
when false:
proc newType*(prev: PType, sons: seq[PType]): PType =
result = prev
result.sons = sons
proc mergeLoc(a: var TLoc, b: TLoc) =
if a.k == low(typeof(a.k)): a.k = b.k
@@ -1595,17 +1712,13 @@ proc assignType*(dest, src: PType) =
newSons(dest, src.len)
for i in 0..<src.len: dest[i] = src[i]
proc copyType*(t: PType, idgen: IdGenerator, owner: PSym): PType =
result = newType(t.kind, idgen, owner)
proc copyType*(t: PType, id: ItemId, owner: PSym): PType =
result = newType(t.kind, id, owner)
assignType(result, t)
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,
align: defaultAlignment, itemId: t.itemId,
uniqueId: t.uniqueId)
assignType(result, t)
result.sym = t.sym # backend-info should not be copied
result = copyType(t, t.itemId, t.owner)
proc copySym*(s: PSym; idgen: IdGenerator): PSym =
result = newSym(s.kind, s.name, idgen, s.owner, s.info, s.options)
@@ -1635,13 +1748,19 @@ proc createModuleAlias*(s: PSym, idgen: IdGenerator, newIdent: PIdent, info: TLi
result.loc = s.loc
result.annex = s.annex
proc initStrTable*(): TStrTable =
result = TStrTable(counter: 0)
newSeq(result.data, StartSize)
proc initStrTable*(x: var TStrTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc initIdTable*(): TIdTable =
result = TIdTable(counter: 0)
newSeq(result.data, StartSize)
proc newStrTable*: TStrTable =
initStrTable(result)
proc initIdTable*(x: var TIdTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc newIdTable*: TIdTable =
initIdTable(result)
proc resetIdTable*(x: var TIdTable) =
x.counter = 0
@@ -1649,23 +1768,23 @@ proc resetIdTable*(x: var TIdTable) =
setLen(x.data, 0)
setLen(x.data, StartSize)
proc initObjectSet*(): TObjectSet =
result = TObjectSet(counter: 0)
newSeq(result.data, StartSize)
proc initObjectSet*(x: var TObjectSet) =
x.counter = 0
newSeq(x.data, StartSize)
proc initIdNodeTable*(): TIdNodeTable =
result = TIdNodeTable(counter: 0)
newSeq(result.data, StartSize)
proc initIdNodeTable*(x: var TIdNodeTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc initNodeTable*(): TNodeTable =
result = TNodeTable(counter: 0)
newSeq(result.data, StartSize)
proc initNodeTable*(x: var TNodeTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc skipTypes*(t: PType, kinds: TTypeKinds; maxIters: int): PType =
result = t
var i = maxIters
while result.kind in kinds:
result = lastSon(result)
result = last(result)
dec i
if i == 0: return nil
@@ -1674,7 +1793,7 @@ proc skipTypesOrNil*(t: PType, kinds: TTypeKinds): PType =
result = t
while result != nil and result.kind in kinds:
if result.len == 0: return nil
result = lastSon(result)
result = last(result)
proc isGCedMem*(t: PType): bool {.inline.} =
result = t.kind in {tyString, tyRef, tySequence} or
@@ -1709,6 +1828,9 @@ proc rawAddSon*(father, son: PType; propagateHasAsgn = true) =
father.sons.add(son)
if not son.isNil: propagateToOwner(father, son, propagateHasAsgn)
proc rawAddSonNoPropagationOfTypeFlags*(father, son: PType) =
father.sons.add(son)
proc addSonNilAllowed*(father, son: PNode) =
father.sons.add(son)
@@ -1840,7 +1962,6 @@ proc hasNilSon*(n: PNode): bool =
result = false
proc containsNode*(n: PNode, kinds: TNodeKinds): bool =
result = false
if n == nil: return
case n.kind
of nkEmpty..nkNilLit: result = n.kind in kinds
@@ -1941,13 +2062,15 @@ proc skipGenericOwner*(s: PSym): PSym =
## Generic instantiations are owned by their originating generic
## symbol. This proc skips such owners and goes straight to the owner
## of the generic itself (the module or the enclosing proc).
result = if s.kind in skProcKinds and sfFromGeneric in s.flags and s.owner.kind != skModule:
result = if s.kind == skModule:
s
elif s.kind in skProcKinds and sfFromGeneric in s.flags and s.owner.kind != skModule:
s.owner.owner
else:
s.owner
proc originatingModule*(s: PSym): PSym =
result = s.owner
result = s
while result.kind != skModule: result = result.owner
proc isRoutine*(s: PSym): bool {.inline.} =
@@ -1993,7 +2116,7 @@ proc toVar*(typ: PType; kind: TTypeKind; idgen: IdGenerator): PType =
## returned. Otherwise ``typ`` is simply returned as-is.
result = typ
if typ.kind != kind:
result = newType(kind, idgen, typ.owner)
result = newType(kind, nextTypeId(idgen), typ.owner)
rawAddSon(result, typ)
proc toRef*(typ: PType; idgen: IdGenerator): PType =
@@ -2001,7 +2124,7 @@ proc toRef*(typ: PType; idgen: IdGenerator): PType =
## returned. Otherwise ``typ`` is simply returned as-is.
result = typ
if typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject:
result = newType(tyRef, idgen, typ.owner)
result = newType(tyRef, nextTypeId(idgen), typ.owner)
rawAddSon(result, typ)
proc toObject*(typ: PType): PType =
@@ -2009,7 +2132,7 @@ proc toObject*(typ: PType): PType =
## cases should be a ``tyObject``).
## Otherwise ``typ`` is simply returned as-is.
let t = typ.skipTypes({tyAlias, tyGenericInst})
if t.kind == tyRef: t.lastSon
if t.kind == tyRef: t.elementType
else: typ
proc toObjectFromRefPtrGeneric*(typ: PType): PType =
@@ -2026,7 +2149,7 @@ proc toObjectFromRefPtrGeneric*(typ: PType): PType =
result = typ
while true:
case result.kind
of tyGenericBody: result = result.lastSon
of tyGenericBody: result = result.last
of tyRef, tyPtr, tyGenericInst, tyGenericInvocation, tyAlias: result = result[0]
# automatic dereferencing is deep, refs #18298.
else: break
@@ -2042,8 +2165,6 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool =
if base.sym != nil and {sfCompileToCpp, sfImportc} * base.sym.flags != {}:
result = true
else:
result = false
proc isInfixAs*(n: PNode): bool =
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.id == ord(wAs)
@@ -2109,8 +2230,8 @@ proc isSinkParam*(s: PSym): bool {.inline.} =
proc isSinkType*(t: PType): bool {.inline.} =
t.kind == tySink or tfHasOwned in t.flags
proc newProcType*(info: TLineInfo; idgen: IdGenerator; owner: PSym): PType =
result = newType(tyProc, idgen, owner)
proc newProcType*(info: TLineInfo; id: ItemId; owner: PSym): PType =
result = newType(tyProc, id, owner)
result.n = newNodeI(nkFormalParams, info)
rawAddSon(result, nil) # return type
# result.n[0] used to be `nkType`, but now it's `nkEffectList` because
@@ -2161,7 +2282,7 @@ proc toHumanStr*(kind: TTypeKind): string =
## strips leading `tk`
result = toHumanStrImpl(kind, 2)
proc skipHiddenAddr*(n: PNode): PNode {.inline.} =
proc skipAddr*(n: PNode): PNode {.inline.} =
(if n.kind == nkHiddenAddr: n[0] else: n)
proc isNewStyleConcept*(n: PNode): bool {.inline.} =
@@ -2177,7 +2298,3 @@ const
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
nkTypeOfExpr, nkMixinStmt, nkBindStmt}
proc isTrue*(n: PNode): bool =
n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
n.kind == nkIntLit and n.intVal != 0

View File

@@ -12,11 +12,10 @@
# the data structures here are used in various places of the compiler.
import
ast, options, lineinfos, ropes, idents, rodutils,
ast, hashes, intsets, options, lineinfos, ropes, idents, rodutils,
msgs
import std/[hashes, intsets]
import std/strutils except addf
import strutils except addf
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -110,7 +109,7 @@ type
data*: TIIPairSeq
proc initIITable*(x: var TIITable)
proc initIiTable*(x: var TIITable)
proc iiTableGet*(t: TIITable, key: int): int
proc iiTablePut*(t: var TIITable, key, val: int)
@@ -198,7 +197,6 @@ proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym =
result = nil
proc sameIgnoreBacktickGensymInfo(a, b: string): bool =
result = false
if a[0] != b[0]: return false
var alen = a.len - 1
while alen > 0 and a[alen] != '`': dec(alen)
@@ -228,11 +226,10 @@ proc getNamedParamFromList*(list: PNode, ident: PIdent): PSym =
## Named parameters are special because a named parameter can be
## gensym'ed and then they have '\`<number>' suffix that we need to
## ignore, see compiler / evaltempl.nim, snippet:
## ```nim
## ```
## result.add newIdentNode(getIdent(c.ic, x.name.s & "\`gensym" & $x.id),
## if c.instLines: actual.info else: templ.info)
## ```
result = nil
for i in 1..<list.len:
let it = list[i].sym
if it.name.id == ident.id or
@@ -330,10 +327,8 @@ proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
maxRecDepth: int): Rope =
var sonsRope: Rope
if n == nil:
result = ""
sonsRope = rope("null")
elif containsOrIncl(marker, n.id):
result = ""
sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope(
strutils.toHex(cast[int](n), sizeof(n) * 2))]
else:
@@ -370,7 +365,7 @@ proc treeToYamlAux(conf: ConfigRef; n: PNode, marker: var IntSet, indent: int,
if conf != nil:
result.addf(",$N$1\"info\": $2", [istr, lineInfoToStr(conf, n.info)])
case n.kind
of nkCharLit..nkUInt64Lit:
of nkCharLit..nkInt64Lit:
result.addf(",$N$1\"intVal\": $2", [istr, rope(n.intVal)])
of nkFloatLit, nkFloat32Lit, nkFloat64Lit:
result.addf(",$N$1\"floatVal\": $2",
@@ -409,7 +404,7 @@ proc symToYaml(conf: ConfigRef; n: PSym, indent: int = 0, maxRecDepth: int = - 1
var marker = initIntSet()
result = symToYamlAux(conf, n, marker, indent, maxRecDepth)
import std/tables
import tables
const backrefStyle = "\e[90m"
const enumStyle = "\e[34m"
@@ -895,7 +890,7 @@ proc initTabIter*(ti: var TTabIter, tab: TStrTable): PSym =
result = nextIter(ti, tab)
iterator items*(tab: TStrTable): PSym =
var it: TTabIter
var it: TTabIter = default(TTabIter)
var s = initTabIter(it, tab)
while s != nil:
yield s
@@ -1059,16 +1054,7 @@ proc iiTablePut(t: var TIITable, key, val: int) =
iiTableRawInsert(t.data, key, val)
inc(t.counter)
proc isAddrNode*(n: PNode): bool =
case n.kind
of nkAddr, nkHiddenAddr: true
of nkCallKinds:
if n[0].kind == nkSym and n[0].sym.magic == mAddr: true
else: false
else: false
proc listSymbolNames*(symbols: openArray[PSym]): string =
result = ""
for sym in symbols:
if result.len > 0:
result.add ", "

View File

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

View File

@@ -87,11 +87,5 @@ const populationCount: array[uint8, uint8] = block:
arr
proc bitSetCard*(x: TBitSet): BiggestInt =
result = 0
for it in x:
result.inc int(populationCount[it])
proc bitSetToWord*(s: TBitSet; size: int): BiggestUInt =
result = 0
for j in 0..<size:
if j < s.len: result = result or (BiggestUInt(s[j]) shl (j * 8))

View File

@@ -38,7 +38,6 @@ template less(a, b): bool = cmp(a, b) < 0
template eq(a, b): bool = cmp(a, b) == 0
proc getOrDefault*[Key, Val](b: BTree[Key, Val], key: Key): Val =
result = default(Val)
var x = b.root
while x.isInternal:
for j in 0..<x.entries:

View File

@@ -47,7 +47,6 @@ proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
# cannot analyse the location; assume the worst
return true
result = false
if le != nil:
for i in 1..<ri.len:
let r = ri[i]
@@ -84,12 +83,16 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
if typ[0] != nil:
var flags: TAssignmentFlags = {}
if typ[0].kind in {tyOpenArray, tyVarargs}:
# perhaps generate no temp if the call doesn't have side effects
flags.incl needTempForOpenArray
if isInvalidReturnType(p.config, typ):
if params.len != 0: pl.add(", ")
# beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
# Great, we can use 'd':
if d.k == locNone: d = getTemp(p, typ[0], needsInit=true)
if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
elif d.k notin {locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var:
discard "resetLoc(p, d)"
@@ -97,7 +100,8 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
pl.add(");\n")
line(p, cpsStmts, pl)
else:
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true)
pl.add(addrLoc(p.config, tmp))
pl.add(");\n")
line(p, cpsStmts, pl)
@@ -115,26 +119,30 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
excl d.flags, lfSingleUse
else:
if d.k == locNone and p.splitDecls == 0:
d = getTempCpp(p, typ[0], pl)
getTempCpp(p, typ[0], d, pl)
else:
if d.k == locNone: d = getTemp(p, typ[0])
var list = initLoc(locCall, d.lode, OnUnknown)
if d.k == locNone: getTemp(p, typ[0], d)
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
elif isHarmlessStore(p, canRaise, d):
if d.k == locNone: d = getTemp(p, typ[0])
if d.k == locNone: getTemp(p, typ[0], d)
assert(d.t != nil) # generate an assignment to d:
var list = initLoc(locCall, d.lode, OnUnknown)
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
genAssignment(p, d, list, flags) # no need for deep copying
if canRaise: raiseExit(p)
else:
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
var list = initLoc(locCall, d.lode, OnUnknown)
var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true)
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, tmp, list, {}) # no need for deep copying
genAssignment(p, tmp, list, flags) # no need for deep copying
if canRaise: raiseExit(p)
genAssignment(p, d, tmp, {})
else:
@@ -142,27 +150,37 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
line(p, cpsStmts, pl)
if canRaise: raiseExit(p)
proc genBoundsCheck(p: BProc; arr, a, b: TLoc)
proc genBoundsCheck(p: BProc; arr, a, b: TLoc; arrTyp: PType)
proc reifiedOpenArray(n: PNode): bool {.inline.} =
var x = n
while x.kind in {nkAddr, nkHiddenAddr, nkHiddenStdConv, nkHiddenDeref}:
x = x[0]
while true:
case x.kind
of {nkAddr, nkHiddenAddr, nkHiddenDeref}:
x = x[0]
of nkHiddenStdConv:
x = x[1]
else:
break
if x.kind == nkSym and x.sym.kind == skParam:
result = false
else:
result = true
proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareForMutation = false): (Rope, Rope) =
var a = initLocExpr(p, q[1])
var b = initLocExpr(p, q[2])
var c = initLocExpr(p, q[3])
var a, b, c: TLoc
initLocExpr(p, q[1], a)
initLocExpr(p, q[2], b)
initLocExpr(p, q[3], c)
# bug #23321: In the function mapType, ptrs (tyPtr, tyVar, tyLent, tyRef)
# are mapped into ctPtrToArray, the dereference of which is skipped
# in the `genDeref`. We need to skip these ptrs here
let ty = skipTypes(a.t, abstractVar+{tyPtr, tyRef})
# but first produce the required index checks:
if optBoundsCheck in p.options:
genBoundsCheck(p, a, b, c)
genBoundsCheck(p, a, b, c, ty)
if prepareForMutation:
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
let ty = skipTypes(a.t, abstractVar+{tyPtr})
let dest = getTypeDesc(p.module, destType)
let lengthExpr = "($1)-($2)+1" % [rdLoc(c), rdLoc(b)]
case ty.kind
@@ -194,14 +212,13 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
if atyp.kind in {tyVar} and not compileToCpp(p.module):
result = ("(($5) ? (($4*)(*$1)$3+($2)) : NIM_NIL)" %
[rdLoc(a), rdLoc(b), dataField(p, ty.kind == tyString), dest, dataFieldAccessor(p, "*" & rdLoc(a))],
[rdLoc(a), rdLoc(b), dataField(p), dest, dataFieldAccessor(p, "*" & rdLoc(a))],
lengthExpr)
else:
result = ("(($5) ? (($4*)$1$3+($2)) : NIM_NIL)" %
[rdLoc(a), rdLoc(b), dataField(p, ty.kind == tyString), dest, dataFieldAccessor(p, rdLoc(a))],
[rdLoc(a), rdLoc(b), dataField(p), dest, dataFieldAccessor(p, rdLoc(a))],
lengthExpr)
else:
result = ("", "")
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
@@ -221,9 +238,9 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
let (x, y) = genOpenArraySlice(p, q, formalType, n.typ[0])
result.add x & ", " & y
else:
var a = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n)
let typKind = skipTypes(a.t, abstractVar+{tyStatic}).kind
case typKind
var a: TLoc
initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a)
case skipTypes(a.t, abstractVar+{tyStatic}).kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(n):
if a.t.kind in {tyVar, tyLent}:
@@ -241,11 +258,11 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
var t: TLoc
t.r = "(*$1)" % [a.rdLoc]
result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" %
[a.rdLoc, lenExpr(p, t, typKind == tyString), dataField(p, typKind == tyString),
[a.rdLoc, lenExpr(p, t), dataField(p),
dataFieldAccessor(p, "*" & a.rdLoc)]
else:
result.add "($4) ? ($1$3) : NIM_NIL, $2" %
[a.rdLoc, lenExpr(p, a, typKind == tyString), dataField(p, typKind == tyString), dataFieldAccessor(p, a.rdLoc)]
[a.rdLoc, lenExpr(p, a), dataField(p), dataFieldAccessor(p, a.rdLoc)]
of tyArray:
result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))]
of tyPtr, tyRef:
@@ -254,7 +271,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
var t: TLoc
t.r = "(*$1)" % [a.rdLoc]
result.add "($4) ? ((*$1)$3) : NIM_NIL, $2" %
[a.rdLoc, lenExpr(p, t, typKind == tyString), dataField(p, typKind == tyString),
[a.rdLoc, lenExpr(p, t), dataField(p),
dataFieldAccessor(p, "*" & a.rdLoc)]
of tyArray:
result.add "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))]
@@ -268,17 +285,18 @@ proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc =
# Also don't regress for non ARC-builds, too risky.
if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
getSize(p.config, a.lode.typ) < 1024:
result = getTemp(p, a.lode.typ, needsInit=false)
getTemp(p, a.lode.typ, result, needsInit=false)
genAssignment(p, result, a, {})
else:
result = a
proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc =
result = getTemp(p, a.lode.typ, needsInit=false)
getTemp(p, a.lode.typ, result, needsInit=false)
genAssignment(p, result, a, {})
proc genArgStringToCString(p: BProc, n: PNode; result: var Rope; needsTmp: bool) {.inline.} =
var a = initLocExpr(p, n[0])
var a: TLoc
initLocExpr(p, n[0], a)
appcg(p.module, result, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc])
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; needsTmp = false) =
@@ -288,27 +306,42 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
var n = if n.kind != nkHiddenAddr: n else: n[0]
openArrayLoc(p, param.typ, n, result)
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and
(optByRef notin param.options or not p.module.compileToCpp):
a = initLocExpr(p, n)
initLocExpr(p, n, a)
if n.kind in {nkCharLit..nkNilLit}:
addAddrLoc(p.config, literalsNeedsTmp(p, a), result)
else:
addAddrLoc(p.config, withTmpIfNeeded(p, a, needsTmp), result)
elif p.module.compileToCpp and param.typ.kind in {tyVar} and
n.kind == nkHiddenAddr:
a = initLocExprSingleUse(p, n[0])
# bug #23748: we need to introduce a temporary here. The expression type
# will be a reference in C++ and we cannot create a temporary reference
# 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.flags.incl tfVarIsPtr
initLocExprSingleUse(p, n, a)
a = withTmpIfNeeded(p, a, needsTmp)
if needsIndirect: a.flags.incl lfIndirect
# if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
# means '*T'. See posix.nim for lots of examples that do that in the wild.
let callee = call[0]
if callee.kind == nkSym and
{sfImportc, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportc} and
{lfHeader, lfNoDecl} * callee.sym.loc.flags != {}:
{lfHeader, lfNoDecl} * callee.sym.loc.flags != {} and
needsIndirect:
addAddrLoc(p.config, a, result)
else:
addRdLoc(a, result)
else:
a = initLocExprSingleUse(p, n)
initLocExprSingleUse(p, n, a)
if param.typ.kind in abstractPtrs:
let typ = skipTypes(param.typ, abstractPtrs)
if typ.sym != nil and sfImportc in typ.sym.flags:
a.r = "(($1) ($2))" %
[getTypeDesc(p.module, param.typ), rdCharLoc(a)]
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
#assert result != nil
@@ -317,13 +350,12 @@ proc genArgNoParam(p: BProc, n: PNode; result: var Rope; needsTmp = false) =
if n.kind == nkStringToCString:
genArgStringToCString(p, n, result, needsTmp)
else:
a = initLocExprSingleUse(p, n)
initLocExprSingleUse(p, n, a)
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
import aliasanalysis
proc potentialAlias(n: PNode, potentialWrites: seq[PNode]): bool =
result = false
for p in potentialWrites:
if p.aliases(n) != no or n.aliases(p) != no:
return true
@@ -379,21 +411,23 @@ proc genParams(p: BProc, ri: PNode, typ: PType; result: var Rope) =
# We must generate temporaries in cases like #14396
# to keep the strict Left-To-Right evaluation
var needTmp = newSeq[bool](ri.len - 1)
var potentialWrites: seq[PNode] = @[]
var potentialWrites: seq[PNode]
for i in countdown(ri.len - 1, 1):
if ri[i].skipTrivialIndirections.kind == nkSym:
needTmp[i - 1] = potentialAlias(ri[i], potentialWrites)
else:
#if not ri[i].typ.isCompileTimeOnly:
var potentialReads: seq[PNode] = @[]
var potentialReads: seq[PNode]
getPotentialReads(ri[i], potentialReads)
for n in potentialReads:
if not needTmp[i - 1]:
needTmp[i - 1] = potentialAlias(n, potentialWrites)
getPotentialWrites(ri[i], false, potentialWrites)
if ri[i].kind in {nkHiddenAddr, nkAddr}:
# Optimization: don't use a temp, if we would only take the address anyway
needTmp[i - 1] = false
when false:
# this optimization is wrong, see bug #23748
if ri[i].kind in {nkHiddenAddr, nkAddr}:
# Optimization: don't use a temp, if we would only take the address anyway
needTmp[i - 1] = false
var oldLen = result.len
for i in 1..<ri.len:
@@ -417,8 +451,9 @@ proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
res = res & "_actual".rope
proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op: TLoc
# this is a hotspot in the compiler
var op = initLocExpr(p, ri[0])
initLocExpr(p, ri[0], op)
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInstOwned)
assert(typ.kind == tyProc)
@@ -440,7 +475,8 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
const PatProc = "$1.ClE_0? $1.ClP_0($3$1.ClE_0):(($4)($1.ClP_0))($2)"
const PatIter = "$1.ClP_0($3$1.ClE_0)" # we know the env exists
var op = initLocExpr(p, ri[0])
var op: TLoc
initLocExpr(p, ri[0], op)
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInstOwned)
@@ -465,7 +501,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
# Great, we can use 'd':
if d.k == locNone:
d = getTemp(p, typ[0], needsInit=true)
getTemp(p, typ[0], d, needsInit=true)
elif d.k notin {locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var:
discard "resetLoc(p, d)"
@@ -473,15 +509,17 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
genCallPattern()
if canRaise: raiseExit(p)
else:
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true)
pl.add(addrLoc(p.config, tmp))
genCallPattern()
if canRaise: raiseExit(p)
genAssignment(p, d, tmp, {}) # no need for deep copying
elif isHarmlessStore(p, canRaise, d):
if d.k == locNone: d = getTemp(p, typ[0])
if d.k == locNone: getTemp(p, typ[0], d)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
if tfIterator in typ.flags:
list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
else:
@@ -489,9 +527,11 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
genAssignment(p, d, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
else:
var tmp: TLoc = getTemp(p, typ[0])
var tmp: TLoc
getTemp(p, typ[0], tmp)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
if tfIterator in typ.flags:
list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
else:
@@ -659,7 +699,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro
inc j
inc i
of '\'':
var idx, stars: int = 0
var idx, stars: int
if scanCppGenericSlot(pat, i, idx, stars):
var t = resolveStarsInCppType(typ, idx, stars)
if t == nil: result.add("void")
@@ -673,7 +713,8 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro
result.add(substr(pat, start, i - 1))
proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op = initLocExpr(p, ri[0])
var op: TLoc
initLocExpr(p, ri[0], op)
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
assert(typ.kind == tyProc)
@@ -695,9 +736,10 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
d.r = pl
excl d.flags, lfSingleUse
else:
if d.k == locNone: d = getTemp(p, typ[0])
if d.k == locNone: getTemp(p, typ[0], d)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:
@@ -717,7 +759,8 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
# generates a crappy ObjC call
var op = initLocExpr(p, ri[0])
var op: TLoc
initLocExpr(p, ri[0], op)
var pl = "["
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
@@ -759,22 +802,24 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
# beware of 'result = p(result)'. We always allocate a temporary:
if d.k in {locTemp, locNone}:
# We already got a temp. Great, special case it:
if d.k == locNone: d = getTemp(p, typ[0], needsInit=true)
if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
pl.add("Result: ")
pl.add(addrLoc(p.config, d))
pl.add("];\n")
line(p, cpsStmts, pl)
else:
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true)
pl.add(addrLoc(p.config, tmp))
pl.add("];\n")
line(p, cpsStmts, pl)
genAssignment(p, d, tmp, {}) # no need for deep copying
else:
pl.add("]")
if d.k == locNone: d = getTemp(p, typ[0])
if d.k == locNone: getTemp(p, typ[0], d)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc = initLoc(locCall, ri, OnUnknown)
var list: TLoc
initLoc(list, locCall, ri, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:

File diff suppressed because it is too large Load Diff

View File

@@ -94,48 +94,6 @@ proc genStringLiteralV2Const(m: BModule; n: PNode; isConst: bool; result: var Ro
pureLit = m.tmpBase & rope(id)
result.addf "{$1, (NimStrPayload*)&$2}", [rope(n.strVal.len), pureLit]
# ------ Version 3: destructor based strings and seqs -----------------------
# strings are enhanced by interned strings
proc toConstLenV3(len: int): string =
result = rope((len shl 1) or 1)
proc genStringLiteralDataOnlyV3(m: BModule, s: string; result: Rope; isConst: bool) =
# TODO: fixme: perhaps use makeCString for clarity for C
m.s[cfsStrData].addf("static $4 NIM_CHAR $1[$2] = $3;$n",
[result, rope(s.len), makeCCharArray(s),
rope(if isConst: "const" else: "")])
proc genStringLiteralV3(m: BModule; n: PNode; isConst: bool; result: var Rope) =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
if id == m.labels:
let pureLit = getTempName(m)
genStringLiteralDataOnlyV3(m, n.strVal, pureLit, isConst)
let tmp = getTempName(m)
result.add tmp
cgsym(m, "NimStringV3")
# string literal not found in the cache:
m.s[cfsStrData].addf("static $4 NimStringV3 $1 = {$2, (NIM_CHAR*)&$3};$n",
[tmp, toConstLenV3(n.strVal.len), pureLit, rope(if isConst: "const" else: "")])
else:
let tmp = getTempName(m)
result.add tmp
m.s[cfsStrData].addf("static $4 NimStringV3 $1 = {$2, (NIM_CHAR*)&$3};$n",
[tmp, toConstLenV3(n.strVal.len), m.tmpBase & rope(id),
rope(if isConst: "const" else: "")])
proc genStringLiteralV3Const(m: BModule; n: PNode; isConst: bool; result: var Rope) =
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
var pureLit: Rope
if id == m.labels:
pureLit = getTempName(m)
cgsym(m, "NimStringV3")
# string literal not found in the cache:
genStringLiteralDataOnlyV3(m, n.strVal, pureLit, isConst)
else:
pureLit = m.tmpBase & rope(id)
result.addf "{$1, (NIM_CHAR*)&$2}", [toConstLenV3(n.strVal.len), pureLit]
# ------ Version selector ---------------------------------------------------
proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo;
@@ -146,10 +104,6 @@ proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo;
let tmp = getTempName(m)
genStringLiteralDataOnlyV2(m, s, tmp, isConst)
result.add tmp
of 3:
let tmp = getTempName(m)
genStringLiteralDataOnlyV3(m, s, tmp, isConst)
result.add tmp
else:
localError(m.config, info, "cannot determine how to produce code for string literal")
@@ -160,6 +114,5 @@ proc genStringLiteral(m: BModule; n: PNode; result: var Rope) =
case detectStrVersion(m)
of 0, 1: genStringLiteralV1(m, n, result)
of 2: genStringLiteralV2(m, n, isConst = true, result)
of 3: genStringLiteralV3(m, n, isConst = true, result)
else:
localError(m.config, n.info, "cannot determine how to produce code for string literal")

View File

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

View File

@@ -18,7 +18,7 @@ proc registerTraverseProc(p: BProc, v: PSym) =
var traverseProc = ""
if p.config.selectedGC in {gcMarkAndSweep, gcHooks, gcRefc} and
optOwnedRefs notin p.config.globalOptions and
containsGarbageCollectedRef(v.loc.t):
containsManagedMemory(v.loc.t):
# we register a specialized marked proc here; this has the advantage
# that it works out of the box for thread local storage then :-)
traverseProc = genTraverseProcForGlobal(p.module, v, v.info)
@@ -50,7 +50,6 @@ proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
result = true
proc inExceptBlockLen(p: BProc): int =
result = 0
for x in p.nestedTryStmts:
if x.inExcept: result.inc
@@ -72,6 +71,7 @@ template startBlock(p: BProc, start: FormatStr = "{$n",
proc endBlock(p: BProc)
proc genVarTuple(p: BProc, n: PNode) =
var tup, field: TLoc
if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple")
# if we have a something that's been captured, use the lowering instead:
@@ -83,7 +83,7 @@ proc genVarTuple(p: BProc, n: PNode) =
# check only the first son
var forHcr = treatGlobalDifferentlyForHCR(p.module, n[0].sym)
let hcrCond = if forHcr: getTempName(p.module) else: ""
var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]] = @[]
var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]]
# determine if the tuple is constructed at top-level scope or inside of a block (if/while/block)
let isGlobalInBlock = forHcr and p.blocks.len > 2
# do not close and reopen blocks if this is a 'global' but inside of a block (if/while/block)
@@ -95,7 +95,7 @@ proc genVarTuple(p: BProc, n: PNode) =
startBlock(p)
genLineDir(p, n)
var tup = initLocExpr(p, n[^1])
initLocExpr(p, n[^1], tup)
var t = tup.t.skipTypes(abstractInst)
for i in 0..<n.len-2:
let vn = n[i]
@@ -108,7 +108,7 @@ proc genVarTuple(p: BProc, n: PNode) =
else:
assignLocalVar(p, vn)
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[^1]))
var field = initLoc(locExpr, vn, tup.storage)
initLoc(field, locExpr, vn, tup.storage)
if t.kind == tyTuple:
field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
else:
@@ -169,7 +169,7 @@ proc endBlock(p: BProc, blockEnd: Rope) =
proc endBlock(p: BProc) =
let topBlock = p.blocks.len - 1
let frameLen = p.blocks[topBlock].frameLen
var blockEnd: Rope = ""
var blockEnd: Rope
if frameLen > 0:
blockEnd.addf("FR_.len-=$1;$n", [frameLen.rope])
if p.blocks[topBlock].label.len != 0:
@@ -244,7 +244,8 @@ proc genGotoState(p: BProc, n: PNode) =
# switch (x.state) {
# case 0: goto STATE0;
# ...
var a: TLoc = initLocExpr(p, n[0])
var a: TLoc
initLocExpr(p, n[0], a)
lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
p.flags.incl beforeRetNeeded
lineF(p, cpsStmts, "case -1:$n", [])
@@ -263,13 +264,13 @@ proc genGotoState(p: BProc, n: PNode) =
proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc
d = initLoc(locExpr, n, OnUnknown)
initLoc(d, locExpr, n, OnUnknown)
if n[0].kind == nkClosure:
a = initLocExpr(p, n[0][1])
initLocExpr(p, n[0][1], a)
d.r = "(((NI*) $1)[1] < 0)" % [rdLoc(a)]
else:
a = initLocExpr(p, n[0])
initLocExpr(p, n[0], a)
# the environment is guaranteed to contain the 'state' field at offset 1:
d.r = "((((NI*) $1.ClE_0)[1]) < 0)" % [rdLoc(a)]
@@ -289,22 +290,14 @@ proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Rope) =
#echo "New code produced for ", v.name.s, " ", p.config $ value.info
genBracedInit(p, value, isConst = false, v.typ, result)
proc genCppParamsForCtor(p: BProc; call: PNode): string =
result = ""
proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope) =
var params = newRopeAppender()
var argsCounter = 0
let typ = skipTypes(call[0].typ, abstractInst)
let typ = skipTypes(value[0].typ, abstractInst)
assert(typ.kind == tyProc)
for i in 1..<call.len:
for i in 1..<value.len:
assert(typ.len == typ.n.len)
#if it's a type we can just generate here another initializer as we are in an initializer context
if call[i].kind == nkCall and call[i][0].kind == nkSym and call[i][0].sym.kind == skType:
if argsCounter > 0: result.add ","
result.add genCppInitializer(p.module, p, call[i][0].sym.typ)
else:
genOtherArg(p, call, i, typ, result, argsCounter)
proc genCppVarForCtor(p: BProc; call: PNode; decl: var Rope) =
let params = genCppParamsForCtor(p, call)
genOtherArg(p, value, i, typ, params, argsCounter)
if params.len == 0:
decl = runtimeFormat("$#;\n", [decl])
else:
@@ -348,7 +341,7 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
# Only do this for complex types that may need a call to `objectInit`
if sfThread in v.flags and emulatedThreadVars(p.config) and
isComplexValueType(v.typ):
loc = initLocExprSingleUse(p.module.preInitProc, vn)
initLocExprSingleUse(p.module.preInitProc, vn, loc)
genObjectInit(p.module.preInitProc, cpsInit, v.typ, loc, constructObj)
# Alternative construction using default constructor (which may zeromem):
# if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
@@ -366,10 +359,10 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
var decl = localVarDecl(p, vn)
var tmp: TLoc
if isCppCtorCall:
genCppVarForCtor(p, value, decl)
genCppVarForCtor(p, v, vn, value, decl)
line(p, cpsStmts, decl)
else:
tmp = initLocExprSingleUse(p, value)
initLocExprSingleUse(p, value, tmp)
lineF(p, cpsStmts, "$# = $#;\n", [decl, tmp.rdLoc])
return
assignLocalVar(p, vn)
@@ -415,7 +408,8 @@ proc genSingleVar(p: BProc, a: PNode) =
proc genClosureVar(p: BProc, a: PNode) =
var immediateAsgn = a[2].kind != nkEmpty
var v: TLoc = initLocExpr(p, a[0])
var v: TLoc
initLocExpr(p, a[0], v)
genLineDir(p, a)
if immediateAsgn:
loadInto(p, a[0], a[2], v)
@@ -450,7 +444,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
a: TLoc
lelse: TLabel
if not isEmptyType(n.typ) and d.k == locNone:
d = getTemp(p, n.typ)
getTemp(p, n.typ, d)
genLineDir(p, n)
let lend = getLabel(p)
for it in n.sons:
@@ -458,7 +452,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
if d.k == locTemp and isEmptyType(n.typ): d.k = locNone
if it.len == 2:
startBlock(p)
a = initLocExprSingleUse(p, it[0])
initLocExprSingleUse(p, it[0], a)
lelse = getLabel(p)
inc(p.labels)
lineF(p, cpsStmts, "if (!$1) goto $2;$n",
@@ -526,7 +520,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
# wrapped inside stmt lists by inject destructors won't be recognised
let n = n.flattenStmts()
var casePos = -1
var arraySize: int = 0
var arraySize: int
for i in 0..<n.len:
let it = n[i]
if it.kind == nkCaseStmt:
@@ -560,7 +554,8 @@ proc genComputedGoto(p: BProc; n: PNode) =
genStmts(p, n[j])
let caseStmt = n[casePos]
var a: TLoc = initLocExpr(p, caseStmt[0])
var a: TLoc
initLocExpr(p, caseStmt[0], a)
# first goto:
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
@@ -598,7 +593,8 @@ proc genComputedGoto(p: BProc; n: PNode) =
else:
genStmts(p, it)
var a: TLoc = initLocExpr(p, caseStmt[0])
var a: TLoc
initLocExpr(p, caseStmt[0], a)
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
endBlock(p)
@@ -626,7 +622,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
else:
p.breakIdx = startBlock(p, "while (1) {$n")
p.blocks[p.breakIdx].isLoop = true
a = initLocExpr(p, t[0])
initLocExpr(p, t[0], a)
if (t[0].kind != nkIntLit) or (t[0].intVal == 0):
lineF(p, cpsStmts, "if (!$1) goto ", [rdLoc(a)])
assignLabel(p.blocks[p.breakIdx], p.s(cpsStmts))
@@ -645,7 +641,7 @@ proc genBlock(p: BProc, n: PNode, d: var TLoc) =
# bug #4505: allocate the temp in the outer scope
# so that it can escape the generated {}:
if d.k == locNone:
d = getTemp(p, n.typ)
getTemp(p, n.typ, d)
d.flags.incl(lfEnforceDeref)
preserveBreakIdx:
p.breakIdx = startBlock(p)
@@ -665,13 +661,14 @@ proc genParForStmt(p: BProc, t: PNode) =
preserveBreakIdx:
let forLoopVar = t[0].sym
var rangeA, rangeB: TLoc
assignLocalVar(p, t[0])
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
#discard mangleName(forLoopVar)
let call = t[1]
assert(call.len == 4 or call.len == 5)
var rangeA = initLocExpr(p, call[1])
var rangeB = initLocExpr(p, call[2])
initLocExpr(p, call[1], rangeA)
initLocExpr(p, call[2], rangeB)
# $n at the beginning because of #9710
if call.len == 4: # procName(a, b, annotation)
@@ -688,7 +685,8 @@ proc genParForStmt(p: BProc, t: PNode) =
rangeA.rdLoc, rangeB.rdLoc,
call[3].getStr.rope])
else: # `||`(a, b, step, annotation)
var step: TLoc = initLocExpr(p, call[3])
var step: TLoc
initLocExpr(p, call[3], step)
lineF(p, cpsStmts, "$n#pragma omp $5$n" &
"for ($1 = $2; $1 <= $3; $1 += $4)",
[forLoopVar.loc.rdLoc,
@@ -758,7 +756,8 @@ proc raiseInstr(p: BProc; result: var Rope) =
proc genRaiseStmt(p: BProc, t: PNode) =
if t[0].kind != nkEmpty:
var a: TLoc = initLocExprSingleUse(p, t[0])
var a: TLoc
initLocExprSingleUse(p, t[0], a)
finallyActions(p)
var e = rdLoc(a)
discard getTypeDesc(p.module, t[0].typ)
@@ -788,12 +787,12 @@ template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
var x, y: TLoc
for i in 0..<b.len - 1:
if b[i].kind == nkRange:
x = initLocExpr(p, b[i][0])
y = initLocExpr(p, b[i][1])
initLocExpr(p, b[i][0], x)
initLocExpr(p, b[i][1], y)
lineCg(p, cpsStmts, rangeFormat,
[rdCharLoc(e), rdCharLoc(x), rdCharLoc(y), labl])
else:
x = initLocExpr(p, b[i])
initLocExpr(p, b[i], x)
lineCg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl])
proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
@@ -835,7 +834,8 @@ template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
template genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
rangeFormat, eqFormat: FormatStr) =
var a: TLoc = initLocExpr(p, t[0])
var a: TLoc
initLocExpr(p, t[0], a)
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, t.len-1, a)
fixLabel(p, lend)
@@ -845,8 +845,8 @@ proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
var x: TLoc
for i in 0..<b.len - 1:
assert(b[i].kind != nkRange)
x = initLocExpr(p, b[i])
var j: int = 0
initLocExpr(p, b[i], x)
var j: int
case b[i].kind
of nkStrLit..nkTripleStrLit:
j = int(hashString(p.config, b[i].strVal) and high(branches))
@@ -869,7 +869,8 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
var bitMask = math.nextPowerOfTwo(strings) - 1
var branches: seq[Rope]
newSeq(branches, bitMask + 1)
var a: TLoc = initLocExpr(p, t[0]) # first pass: generate ifs+goto:
var a: TLoc
initLocExpr(p, t[0], a) # fist pass: generate ifs+goto:
var labId = p.labels
for i in 1..<t.len:
inc(p.labels)
@@ -905,7 +906,6 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n")
proc branchHasTooBigRange(b: PNode): bool =
result = false
for it in b:
# last son is block
if (it.kind == nkRange) and
@@ -913,7 +913,6 @@ proc branchHasTooBigRange(b: PNode): bool =
return true
proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
result = 0
for i in 1..<n.len:
var branch = n[i]
var stmtBlock = lastSon(branch)
@@ -949,7 +948,8 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
var splitPoint = ifSwitchSplitPoint(p, n)
# generate if part (might be empty):
var a: TLoc = initLocExpr(p, n[0])
var a: TLoc
initLocExpr(p, n[0], a)
var lend = if splitPoint > 0: genIfForCaseUntil(p, n, d,
rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
eqFormat = "if ($1 == $2) goto $3;$n",
@@ -982,7 +982,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
proc genCase(p: BProc, t: PNode, d: var TLoc) =
genLineDir(p, t)
if not isEmptyType(t.typ) and d.k == locNone:
d = getTemp(p, t.typ)
getTemp(p, t.typ, d)
case skipTypes(t[0].typ, abstractVarRange).kind
of tyString:
genStringCase(p, t, tyString, d)
@@ -1033,7 +1033,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
p.module.includeHeader("<exception>")
if not isEmptyType(t.typ) and d.k == locNone:
d = getTemp(p, t.typ)
getTemp(p, t.typ, d)
genLineDir(p, t)
inc(p.labels, 2)
@@ -1198,7 +1198,7 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) =
expr(p, body, d)
if not isEmptyType(t.typ) and d.k == locNone:
d = getTemp(p, t.typ)
getTemp(p, t.typ, d)
genLineDir(p, t)
cgsym(p.module, "popCurrentExceptionEx")
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
@@ -1276,7 +1276,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
p.flags.incl nimErrorFlagAccessed
if not isEmptyType(t.typ) and d.k == locNone:
d = getTemp(p, t.typ)
getTemp(p, t.typ, d)
expr(p, t[0], d)
@@ -1383,7 +1383,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
# propagateCurrentException();
#
if not isEmptyType(t.typ) and d.k == locNone:
d = getTemp(p, t.typ)
getTemp(p, t.typ, d)
let quirkyExceptions = p.config.exc == excQuirky or
(t.kind == nkHiddenTryStmt and sfSystemModule in p.module.module.flags)
if not quirkyExceptions:
@@ -1392,7 +1392,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
p.flags.incl noSafePoints
genLineDir(p, t)
cgsym(p.module, "Exception")
var safePoint: Rope = ""
var safePoint: Rope
if not quirkyExceptions:
safePoint = getTempName(p.module)
linefmt(p, cpsLocals, "#TSafePoint $1;$n", [safePoint])
@@ -1457,8 +1457,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
if optTinyRtti in p.config.globalOptions:
let checkFor = $getObjDepth(t[i][j].typ)
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)",
[memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
else:
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
@@ -1496,7 +1495,8 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
of nkSym:
var sym = it.sym
if sym.kind in {skProc, skFunc, skIterator, skMethod}:
var a: TLoc = initLocExpr(p, it)
var a: TLoc
initLocExpr(p, it, a)
res.add($rdLoc(a))
elif sym.kind == skType:
res.add($getTypeDesc(p.module, sym.typ))
@@ -1508,7 +1508,8 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
res.add($getTypeDesc(p.module, it.typ))
else:
discard getTypeDesc(p.module, skipTypes(it.typ, abstractPtrs))
var a: TLoc = initLocExpr(p, it)
var a: TLoc
initLocExpr(p, it, a)
res.add($a.rdLoc)
if isAsmStmt and hasGnuAsm in CC[p.config.cCompiler].props:
@@ -1610,10 +1611,11 @@ when false:
expr(p, call, d)
proc asgnFieldDiscriminant(p: BProc, e: PNode) =
var a, tmp: TLoc
var dotExpr = e[0]
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr[0]
var a = initLocExpr(p, e[0])
var tmp: TLoc = getTemp(p, a.t)
initLocExpr(p, e[0], a)
getTemp(p, a.t, tmp)
expr(p, e[1], tmp)
if p.inUncheckedAssignSection == 0:
let field = dotExpr[1].sym
@@ -1631,8 +1633,9 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
else:
let le = e[0]
let ri = e[1]
var a: TLoc = initLoc(locNone, le, OnUnknown)
var a: TLoc
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), dkVar)
initLoc(a, locNone, le, OnUnknown)
a.flags.incl(lfEnforceDeref)
a.flags.incl(lfPrepareForMutation)
genLineDir(p, le) # it can be a nkBracketExpr, which may raise
@@ -1644,7 +1647,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
loadInto(p, le, ri, a)
proc genStmts(p: BProc, t: PNode) =
var a: TLoc = default(TLoc)
var a: TLoc
let isPush = p.config.hasHint(hintExtendedContext)
if isPush: pushInfoContext(p.config, t.info)

View File

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

View File

@@ -11,9 +11,8 @@
# ------------------------- Name Mangling --------------------------------
import sighashes, modulegraphs, std/strscans
import sighashes, modulegraphs, strscans
import ../dist/checksums/src/checksums/md5
import std/sequtils
type
TypeDescKind = enum
@@ -25,7 +24,7 @@ type
dkResult #skResult
dkConst #skConst
dkOther #skType, skTemp, skLet and skForVar so far
proc descKindFromSymKind(kind: TSymKind): TypeDescKind =
case kind
of skParam: dkParam
@@ -34,7 +33,7 @@ proc descKindFromSymKind(kind: TSymKind): TypeDescKind =
of skResult: dkResult
of skConst: dkConst
else: dkOther
proc isKeyword(w: PIdent): bool =
# Nim and C++ share some keywords
# it's more efficient to test the whole Nim keywords range
@@ -55,13 +54,31 @@ proc mangleField(m: BModule; name: PIdent): string =
if isKeyword(name):
result.add "_0"
proc mangleProc(m: BModule; s: PSym; makeUnique: bool): string =
result = "_Z" # Common prefix in Itanium ABI
result.add encodeSym(m, s, makeUnique)
if s.typ.len > 1: #we dont care about the return param
for i in 1..<s.typ.len:
if s.typ[i].isNil: continue
result.add encodeType(m, s.typ[i])
if result in m.g.mangledPrcs:
result = mangleProc(m, s, true)
else:
m.g.mangledPrcs.incl(result)
proc fillBackendName(m: BModule; s: PSym) =
if s.loc.r == "":
var result = s.name.s.mangle.rope
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_u"
result.addInt s.itemId.item # s.disamb #
var result: Rope
if not m.compileToCpp and s.kind in routineKinds and optCDebug in m.g.config.globalOptions and
m.g.config.symbolFiles == disabledSf:
result = mangleProc(m, s, false).rope
else:
result = s.name.s.mangle.rope
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_u"
result.addInt s.itemId.item # s.disamb #
if m.hcrOn:
result.add '_'
result.add(idOrSig(s, m.module.name.s.mangle, m.sigConflicts, m.config))
@@ -207,12 +224,8 @@ proc mapType(conf: ConfigRef; typ: PType; isParam: bool): TCTypeKind =
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
of tyStatic:
if typ.n != nil: result = mapType(conf, lastSon typ, isParam)
else:
result = ctVoid
doAssert(false, "mapType: " & $typ.kind)
else:
result = ctVoid
doAssert(false, "mapType: " & $typ.kind)
else: doAssert(false, "mapType: " & $typ.kind)
else: doAssert(false, "mapType: " & $typ.kind)
proc mapReturnType(conf: ConfigRef; typ: PType): TCTypeKind =
@@ -257,9 +270,15 @@ proc isInvalidReturnType(conf: ConfigRef; typ: PType, isProc = true): bool =
{tyVar, tyLent, tyRef, tyPtr})
of ctStruct:
let t = skipTypes(rettype, typedescInst)
if rettype.isImportedCppType or t.isImportedCppType: return false
result = containsGarbageCollectedRef(t) or
(t.kind == tyObject and not isObjLackingTypeField(t))
if rettype.isImportedCppType or t.isImportedCppType or
(typ.callConv == ccCDecl and conf.selectedGC in {gcArc, gcAtomicArc, gcOrc}):
# prevents nrvo for cdecl procs; # bug #23401
result = false
else:
result = containsGarbageCollectedRef(t) or
(t.kind == tyObject and not isObjLackingTypeField(t)) or
(getSize(conf, rettype) == szUnknownSize and (t.sym == nil or sfImportc notin t.sym.flags))
else: result = false
const
@@ -311,9 +330,6 @@ proc getSimpleTypeDesc(m: BModule; typ: PType): Rope =
result = typeNameOrLiteral(m, typ, "void*")
of tyString:
case detectStrVersion(m)
of 3:
cgsym(m, "NimStringV3")
result = typeNameOrLiteral(m, typ, "NimStringV3")
of 2:
cgsym(m, "NimStrPayload")
cgsym(m, "NimStringV2")
@@ -330,9 +346,7 @@ proc getSimpleTypeDesc(m: BModule; typ: PType): Rope =
of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ[0])
of tyStatic:
if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ)
else:
result = ""
internalError(m.config, "tyStatic for getSimpleTypeDesc")
else: internalError(m.config, "tyStatic for getSimpleTypeDesc")
of tyGenericInst, tyAlias, tySink, tyOwned:
result = getSimpleTypeDesc(m, lastSon typ)
else: result = ""
@@ -468,7 +482,7 @@ proc multiFormat*(frmt: var string, chars : static openArray[char], args: openAr
var num = 0
while i < frmt.len:
if frmt[i] == c:
inc(i)
inc(i)
case frmt[i]
of c:
res.add(c)
@@ -481,11 +495,11 @@ proc multiFormat*(frmt: var string, chars : static openArray[char], args: openAr
if i >= frmt.len or frmt[i] notin {'0'..'9'}: break
num = j
if j > high(arg) + 1:
raiseAssert "invalid format string: " & frmt
doAssert false, "invalid format string: " & frmt
else:
res.add(arg[j-1])
else:
raiseAssert "invalid format string: " & frmt
doAssert false, "invalid format string: " & frmt
var start = i
while i < frmt.len:
if frmt[i] != c: inc(i)
@@ -497,12 +511,12 @@ proc multiFormat*(frmt: var string, chars : static openArray[char], args: openAr
template cgDeclFrmt*(s: PSym): string =
s.constraint.strVal
proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params: var string,
proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, params: var string,
check: var IntSet, declareEnvironment=true;
weakDep=false;) =
let t = prc.typ
let isCtor = sfConstructor in prc.flags
if isCtor or (name[0] == '~' and sfMember in prc.flags): #destructors cant have void
if isCtor:
rettype = ""
elif t[0] == nil or isInvalidReturnType(m.config, t):
rettype = "void"
@@ -511,8 +525,8 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params
rettype = getTypeDescAux(m, t[0], check, dkResult)
else:
rettype = runtimeFormat(rettype.replace("'0", "$1"), [getTypeDescAux(m, t[0], check, dkResult)])
var types, names, args: seq[string] = @[]
if not isCtor:
var types, names, args: seq[string]
if not isCtor:
var this = t.n[1].sym
fillParamName(m, this)
fillLoc(this.loc, locParam, t.n[1],
@@ -525,7 +539,7 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params
types.add getTypeDescWeak(m, this.typ, check, dkParam)
let firstParam = if isCtor: 1 else: 2
for i in firstParam..<t.n.len:
for i in firstParam..<t.n.len:
if t.n[i].kind != nkSym: internalError(m.config, t.n.info, "genMemberProcParams")
var param = t.n[i].sym
var descKind = dkParam
@@ -559,7 +573,6 @@ proc genMemberProcParams(m: BModule; prc: PSym, superCall, rettype, name, params
multiFormat(params, @['\'', '#'], [types, names])
multiFormat(superCall, @['\'', '#'], [types, names])
multiFormat(name, @['\'', '#'], [types, names]) #so we can ~'1 on members
if params == "()":
if types.len == 0:
params = "(void)"
@@ -653,28 +666,13 @@ proc mangleRecFieldName(m: BModule; field: PSym): Rope =
result = rope(mangleField(m, field.name))
if result == "": internalError(m.config, field.info, "mangleRecFieldName")
proc hasCppCtor(m: BModule; typ: PType): bool =
proc hasCppCtor(m: BModule; typ: PType): bool =
result = false
if m.compileToCpp and typ != nil and typ.itemId in m.g.graph.memberProcsPerType:
for prc in m.g.graph.memberProcsPerType[typ.itemId]:
if sfConstructor in prc.flags:
return true
proc genCppParamsForCtor(p: BProc; call: PNode): string
proc genCppInitializer(m: BModule, prc: BProc; typ: PType): string =
#To avoid creating a BProc per test when called inside a struct nil BProc is allowed
result = "{}"
if typ.itemId in m.g.graph.initializersPerType:
let call = m.g.graph.initializersPerType[typ.itemId]
if call != nil:
var p = prc
if p == nil:
p = BProc(module: m)
result = "{" & genCppParamsForCtor(p, call) & "}"
if prc == nil:
assert p.blocks.len == 0, "BProc belongs to a struct doesnt have blocks"
proc genRecordFieldsAux(m: BModule; n: PNode,
rectype: PType,
check: var IntSet; result: var Rope; unionPrefix = "") =
@@ -739,10 +737,8 @@ proc genRecordFieldsAux(m: BModule; n: PNode,
else:
# don't use fieldType here because we need the
# tyGenericInst for C++ template support
let noInit = sfNoInit in field.flags or (field.typ.sym != nil and sfNoInit in field.typ.sym.flags)
if not noInit and (fieldType.isOrHasImportedCppType() or hasCppCtor(m, field.owner.typ)):
var initializer = genCppInitializer(m, nil, fieldType)
result.addf("\t$1$3 $2$4;$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias, initializer])
if fieldType.isOrHasImportedCppType() or hasCppCtor(m, field.owner.typ):
result.addf("\t$1$3 $2{};$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias])
else:
result.addf("\t$1$3 $2;$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias])
else: internalError(m.config, n.info, "genRecordFieldsAux()")
@@ -754,31 +750,31 @@ proc getRecordFields(m: BModule; typ: PType, check: var IntSet): Rope =
genRecordFieldsAux(m, typ.n, typ, check, result)
if typ.itemId in m.g.graph.memberProcsPerType:
let procs = m.g.graph.memberProcsPerType[typ.itemId]
var isDefaultCtorGen, isCtorGen: bool = false
var isDefaultCtorGen, isCtorGen: bool
for prc in procs:
var header: Rope = ""
var header: Rope
if sfConstructor in prc.flags:
isCtorGen = true
if prc.typ.n.len == 1:
isDefaultCtorGen = true
if lfNoDecl in prc.loc.flags: continue
genMemberProcHeader(m, prc, header, false, true)
result.addf "$1;$n", [header]
if isCtorGen and not isDefaultCtorGen:
var ch: IntSet
var ch: IntSet = default(IntSet)
result.addf "$1() = default;$n", [getTypeDescAux(m, typ, ch, dkOther)]
proc fillObjectFields*(m: BModule; typ: PType) =
# sometimes generic objects are not consistently merged. We patch over
# this fact here.
var check = initIntSet()
discard getRecordFields(m, typ, check)
if typ.baseClass != nil:
fillObjectFields(m, typ.baseClass.skipTypes(skipPtrs))
proc mangleDynLibProc(sym: PSym): Rope
proc getRecordDescAux(m: BModule; typ: PType, name, baseType: Rope,
check: var IntSet, hasField:var bool): Rope =
result = ""
check: var IntSet, hasField:var bool): Rope =
if typ.kind == tyObject:
if typ[0] == nil:
if lacksMTypeField(typ):
@@ -819,8 +815,8 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope,
structOrUnion = "#pragma pack(push, 1)\L" & structOrUnion(typ)
else:
structOrUnion = structOrUnion(typ)
var baseType: string = ""
if typ[0] != nil:
var baseType: string
if typ[0] != nil:
baseType = getTypeDescAux(m, typ[0].skipTypes(skipPtrs), check, dkField)
if typ.sym == nil or sfCodegenDecl notin typ.sym.flags:
result = structOrUnion & " " & name
@@ -876,7 +872,7 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
# Make sure the index refers to one of the generic params of the type.
# XXX: we should catch this earlier and report it as a semantic error.
if idx >= typ.len:
raiseAssert "invalid apostrophe type parameter index"
doAssert false, "invalid apostrophe type parameter index"
result = typ[idx]
for i in 1..stars:
@@ -910,7 +906,6 @@ 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 = "" # todo move `result = getTypePre(m, t, sig)` here ?
defer: # defer is the simplest in this case
if isImportedType(t) and not m.typeABICache.containsOrIncl(sig):
addAbiCheck(m, t, result)
@@ -991,7 +986,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
of tyProc:
result = getTypeName(m, origTyp, sig)
m.typeCache[sig] = result
var rettype, desc: Rope = ""
var rettype, desc: Rope
genProcParams(m, t, rettype, desc, check, true, true)
if not isImportedType(t):
if t.callConv != ccClosure: # procedure vars may need a closure!
@@ -1068,7 +1063,7 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
while i < cppName.len:
if cppName[i] == '\'':
var chunkEnd = i-1
var idx, stars: int = 0
var idx, stars: int
if scanCppGenericSlot(cppName, i, idx, stars):
result.add cppName.substr(chunkStart, chunkEnd)
chunkStart = i
@@ -1132,8 +1127,8 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
result = ""
# fixes bug #145:
excl(check, t.id)
proc getTypeDesc(m: BModule; typ: PType; kind = dkParam): Rope =
var check = initIntSet()
result = getTypeDescAux(m, typ, check, kind)
@@ -1148,7 +1143,7 @@ proc getClosureType(m: BModule; t: PType, kind: TClosureTypeKind): Rope =
assert t.kind == tyProc
var check = initIntSet()
result = getTempName(m)
var rettype, desc: Rope = ""
var rettype, desc: Rope
genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf)
if not isImportedType(t):
if t.callConv != ccClosure or kind != clFull:
@@ -1178,19 +1173,11 @@ proc isReloadable(m: BModule; prc: PSym): bool =
proc isNonReloadable(m: BModule; prc: PSym): bool =
return m.hcrOn and sfNonReloadable in prc.flags
proc parseVFunctionDecl(val: string; name, params, retType, superCall: var string; isFnConst, isOverride, isMemberVirtual: var bool; isCtor: bool, isFunctor=false) =
var afterParams: string = ""
proc parseVFunctionDecl(val: string; name, params, retType, superCall: var string; isFnConst, isOverride: var bool; isCtor: bool) =
var afterParams: string
if scanf(val, "$*($*)$s$*", name, params, afterParams):
if name.strip() == "operator" and params == "": #isFunctor?
parseVFunctionDecl(afterParams, name, params, retType, superCall, isFnConst, isOverride, isMemberVirtual, isCtor, true)
return
isFnConst = afterParams.find("const") > -1
isOverride = afterParams.find("override") > -1
isMemberVirtual = name.find("virtual ") > -1
if isMemberVirtual:
name = name.replace("virtual ", "")
if isFunctor:
name = "operator ()"
if isCtor:
discard scanf(afterParams, ":$s$*", superCall)
else:
@@ -1199,28 +1186,28 @@ proc parseVFunctionDecl(val: string; name, params, retType, superCall: var strin
params = "(" & params & ")"
proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false, isFwdDecl : bool = false) =
assert sfCppMember * prc.flags != {}
assert {sfVirtual, sfConstructor} * prc.flags != {}
let isCtor = sfConstructor in prc.flags
let isVirtual = not isCtor
var check = initIntSet()
fillBackendName(m, prc)
fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown)
var memberOp = "#." #only virtual
var typ: PType
if isCtor:
typ = prc.typ[0]
typ = prc.typ.sons[0]
else:
typ = prc.typ[1]
typ = prc.typ.sons[1]
if typ.kind == tyPtr:
typ = typ[0]
memberOp = "#->"
var typDesc = getTypeDescWeak(m, typ, check, dkParam)
let asPtrStr = rope(if asPtr: "_PTR" else: "")
var name, params, rettype, superCall: string = ""
var isFnConst, isOverride, isMemberVirtual: bool = false
parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, superCall, isFnConst, isOverride, isMemberVirtual, isCtor)
genMemberProcParams(m, prc, superCall, rettype, name, params, check, true, false)
let isVirtual = sfVirtual in prc.flags or isMemberVirtual
var fnConst, override: string = ""
var name, params, rettype, superCall: string
var isFnConst, isOverride: bool
parseVFunctionDecl(prc.constraint.strVal, name, params, rettype, superCall, isFnConst, isOverride, isCtor)
genMemberProcParams(m, prc, superCall, rettype, params, check, true, false)
var fnConst, override: string
if isCtor:
name = typDesc
if isFnConst:
@@ -1228,28 +1215,28 @@ proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool =
if isFwdDecl:
if isVirtual:
rettype = "virtual " & rettype
if isOverride:
if isOverride:
override = " override"
superCall = ""
else:
if not isCtor:
if isVirtual:
prc.loc.r = "$1$2(@)" % [memberOp, name]
elif superCall != "":
superCall = " : " & superCall
name = "$1::$2" % [typDesc, name]
result.add "N_LIB_PRIVATE "
result.addf("$1$2($3, $4)$5$6$7$8",
[rope(CallingConvToStr[prc.typ.callConv]), asPtrStr, rettype, name,
params, fnConst, override, superCall])
proc genProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false) =
# using static is needed for inline procs
var check = initIntSet()
fillBackendName(m, prc)
fillLoc(prc.loc, locProc, prc.ast[namePos], OnUnknown)
var rettype, params: Rope = ""
var rettype, params: Rope
genProcParams(m, prc.typ, rettype, params, check, true, false)
# handle the 2 options for hotcodereloading codegen - function pointer
# (instead of forward declaration) or header for function body with "_actual" postfix
@@ -1450,7 +1437,7 @@ proc genObjectInfo(m: BModule; typ, origType: PType, name: Rope; info: TLineInfo
else:
genTypeInfoAuxBase(m, typ, origType, name, rope("0"), info)
var tmp = getNimNode(m)
if not isImportedType(typ):
if (not isImportedType(typ)) or tfCompleteStruct in typ.flags:
genObjectFields(m, typ, origType, typ.n, tmp, info)
m.s[cfsTypeInit3].addf("$1.node = &$2;$n", [tiNameForHcr(m, name), tmp])
var t = typ[0]
@@ -1489,7 +1476,7 @@ proc genEnumInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) =
genTypeInfoAux(m, typ, typ, name, info)
var nodePtrs = getTempName(m) & "_" & $typ.n.len
genTNimNodeArray(m, nodePtrs, rope(typ.n.len))
var enumNames, specialCases: Rope = ""
var enumNames, specialCases: Rope
var firstNimNode = m.typeNodes
var hasHoles = false
for i in 0..<typ.n.len:
@@ -1534,9 +1521,9 @@ proc genArrayInfo(m: BModule; typ: PType, name: Rope; info: TLineInfo) =
proc fakeClosureType(m: BModule; owner: PSym): PType =
# we generate the same RTTI as for a tuple[pointer, ref tuple[]]
result = newType(tyTuple, m.idgen, owner)
result.rawAddSon(newType(tyPointer, m.idgen, owner))
var r = newType(tyRef, m.idgen, owner)
result = newType(tyTuple, nextTypeId m.idgen, owner)
result.rawAddSon(newType(tyPointer, nextTypeId m.idgen, owner))
var r = newType(tyRef, nextTypeId m.idgen, owner)
let obj = createObj(m.g.graph, m.idgen, owner, owner.info, final=false)
r.rawAddSon(obj)
result.rawAddSon(r)
@@ -1568,7 +1555,6 @@ proc genTypeInfo2Name(m: BModule; t: PType): Rope =
result = it.sym.name.s
else:
var p = m.owner
result = ""
if p != nil and p.kind == skPackage:
result.add p.name.s & "."
result.add m.name.s & "."
@@ -1579,6 +1565,10 @@ proc genTypeInfo2Name(m: BModule; t: PType): Rope =
proc isTrivialProc(g: ModuleGraph; s: PSym): bool {.inline.} = getBody(g, s).len == 0
proc makePtrType(baseType: PType; idgen: IdGenerator): PType =
result = newType(tyPtr, nextTypeId idgen, baseType.owner)
addSonSkipIntLit(result, baseType, idgen)
proc generateRttiDestructor(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator; theProc: PSym): PSym =
# the wrapper is roughly like:
@@ -1590,7 +1580,7 @@ proc generateRttiDestructor(g: ModuleGraph; typ: PType; owner: PSym; kind: TType
dest.typ = getSysType(g, info, tyPointer)
result.typ = newProcType(info, idgen, owner)
result.typ = newProcType(info, nextTypeId(idgen), owner)
result.typ.addParam dest
var n = newNodeI(nkProcDef, info, bodyPos+1)
@@ -1606,7 +1596,7 @@ proc generateRttiDestructor(g: ModuleGraph; typ: PType; owner: PSym; kind: TType
))
)
else:
let addrOf = newNodeIT(nkAddr, info, theProc.typ[1])
let addrOf = newNodeIT(nkHiddenAddr, info, theProc.typ[1])
addrOf.add newDeref(newTreeIT(
nkCast, info, castType, newNodeIT(nkType, info, castType),
newSymNode(dest)
@@ -1681,13 +1671,6 @@ proc genDisplay(m: BModule; t: PType, depth: int): Rope =
result.add seqs[0]
result.add "}"
proc genVTable(seqs: seq[PSym]): string =
result = "{"
for i in 0..<seqs.len:
if i > 0: result.add ", "
result.add "(void *) " & seqs[i].loc.r
result.add "}"
proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLineInfo) =
cgsym(m, "TNimTypeV2")
m.s[cfsStrData].addf("N_LIB_PRIVATE TNimTypeV2 $1;$n", [name])
@@ -1724,14 +1707,6 @@ proc genTypeInfoV2OldImpl(m: BModule; t, origType: PType, name: Rope; info: TLin
m.s[cfsVars].addf("static $1 $2[$3] = $4;$n", [getTypeDesc(m, getSysType(m.g.graph, unknownLineInfo, tyUInt32), dkVar), objDisplayStore, rope(objDepth+1), objDisplay])
addf(typeEntry, "$1.display = $2;$n", [name, rope(objDisplayStore)])
let dispatchMethods = toSeq(getMethodsPerType(m.g.graph, t))
if dispatchMethods.len > 0:
let vTablePointerName = getTempName(m)
m.s[cfsVars].addf("static void* $1[$2] = $3;$n", [vTablePointerName, rope(dispatchMethods.len), genVTable(dispatchMethods)])
for i in dispatchMethods:
genProcPrototype(m, i)
addf(typeEntry, "$1.vTable = $2;$n", [name, vTablePointerName])
m.s[cfsTypeInit3].add typeEntry
if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions:
@@ -1773,16 +1748,8 @@ proc genTypeInfoV2Impl(m: BModule; t, origType: PType, name: Rope; info: TLineIn
add(typeEntry, ", .traceImpl = (void*)")
genHook(m, t, info, attachedTrace, typeEntry)
let dispatchMethods = toSeq(getMethodsPerType(m.g.graph, t))
if dispatchMethods.len > 0:
addf(typeEntry, ", .flags = $1", [rope(flags)])
for i in dispatchMethods:
genProcPrototype(m, i)
addf(typeEntry, ", .vTable = $1};$n", [genVTable(dispatchMethods)])
m.s[cfsVars].add typeEntry
else:
addf(typeEntry, ", .flags = $1};$n", [rope(flags)])
m.s[cfsVars].add typeEntry
addf(typeEntry, ", .flags = $1};$n", [rope(flags)])
m.s[cfsVars].add typeEntry
if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions:
discard genTypeInfoV1(m, t, info)
@@ -1820,16 +1787,16 @@ proc genTypeInfoV2(m: BModule; t: PType; info: TLineInfo): Rope =
return prefixTI.rope & result & ")".rope
m.g.typeInfoMarkerV2[sig] = (str: result, owner: owner)
if m.compileToCpp or m.hcrOn:
if m.compileToCpp:
genTypeInfoV2OldImpl(m, t, origType, result, info)
else:
genTypeInfoV2Impl(m, t, origType, result, info)
result = prefixTI.rope & result & ")".rope
proc openArrayToTuple(m: BModule; t: PType): PType =
result = newType(tyTuple, m.idgen, t.owner)
let p = newType(tyPtr, m.idgen, t.owner)
let a = newType(tyUncheckedArray, m.idgen, t.owner)
result = newType(tyTuple, nextTypeId m.idgen, t.owner)
let p = newType(tyPtr, nextTypeId m.idgen, t.owner)
let a = newType(tyUncheckedArray, nextTypeId m.idgen, t.owner)
a.add t.lastSon
p.add a
result.add p
@@ -1969,14 +1936,17 @@ proc genTypeInfo*(config: ConfigRef, m: BModule; t: PType; info: TLineInfo): Rop
else:
result = genTypeInfoV1(m, t, info)
proc genTypeSection(m: BModule, n: PNode) =
proc genTypeSection(m: BModule, n: PNode) =
var intSet = initIntSet()
for i in 0..<n.len:
if len(n[i]) == 0: continue
if n[i][0].kind != nkPragmaExpr: continue
for p in 0..<n[i][0].len:
if (n[i][0][p].kind != nkSym): continue
if sfExportc in n[i][0][p].sym.flags:
discard getTypeDescAux(m, n[i][0][p].typ, intSet, descKindFromSymKind(n[i][0][p].sym.kind))
if (n[i][0][p].kind notin {nkSym, nkPostfix}): continue
var s = n[i][0][p]
if s.kind == nkPostfix:
s = n[i][0][p][1]
if {sfExportc, sfCompilerProc} * s.sym.flags == {sfExportc}:
discard getTypeDescAux(m, s.typ, intSet, descKindFromSymKind(s.sym.kind))
if m.g.generatedHeader != nil:
discard getTypeDescAux(m.g.generatedHeader, n[i][0][p].typ, intSet, descKindFromSymKind(n[i][0][p].sym.kind))
discard getTypeDescAux(m.g.generatedHeader, s.typ, intSet, descKindFromSymKind(s.sym.kind))

View File

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

View File

@@ -10,15 +10,13 @@
## This module implements the C code generator.
import
ast, astalgo, trees, platform, magicsys, extccomp, options,
ast, astalgo, hashes, trees, platform, magicsys, extccomp, options, intsets,
nversion, nimsets, msgs, bitsets, idents, types,
ccgutils, ropes, wordrecg, treetab, cgmeth,
ccgutils, os, ropes, math, wordrecg, treetab, cgmeth,
rodutils, renderer, cgendata, aliases,
lowerings, ndi, lineinfos, pathutils, transf,
lowerings, tables, sets, ndi, lineinfos, pathutils, transf,
injectdestructors, astmsgs, modulepaths, backendpragmas
from expanddefaults import caseObjDefaultBranch
import pipelineutils
when defined(nimPreviewSlimSystem):
@@ -27,10 +25,16 @@ when defined(nimPreviewSlimSystem):
when not defined(leanCompiler):
import spawn, semparallel
import std/strutils except `%`, addf # collides with ropes.`%`
import strutils except `%`, addf # collides with ropes.`%`
from ic / ic import ModuleBackendFlag
import std/[dynlib, math, tables, sets, os, intsets, hashes]
import dynlib
const
# we use some ASCII control characters to insert directives that will be converted to real code in a postprocessing pass
postprocessDirStart = '\1'
postprocessDirSep = '\31'
postprocessDirEnd = '\23'
when not declared(dynlib.libCandidates):
proc libCandidates(s: string, dest: var seq[string]) =
@@ -63,10 +67,12 @@ proc findPendingModule(m: BModule, s: PSym): BModule =
var ms = getModule(s)
result = m.g.modules[ms.position]
proc initLoc(k: TLocKind, lode: PNode, s: TStorageLoc, flags: TLocFlags = {}): TLoc =
result = TLoc(k: k, storage: s, lode: lode,
r: "", flags: flags
)
proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc, flags: TLocFlags = {}) =
result.k = k
result.storage = s
result.lode = lode
result.r = ""
result.flags = flags
proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, r: Rope, s: TStorageLoc) {.inline.} =
# fills the loc if it is not already initialized
@@ -121,7 +127,7 @@ proc getModuleDllPath(m: BModule, module: int): Rope =
proc getModuleDllPath(m: BModule, s: PSym): Rope =
result = getModuleDllPath(m.g.modules[s.itemId.module])
import std/macros
import macros
proc cgFormatValue(result: var string; value: string) =
result.add value
@@ -266,24 +272,28 @@ proc safeLineNm(info: TLineInfo): int =
result = toLinenumber(info)
if result < 0: result = 0 # negative numbers are not allowed in #line
proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
proc genPostprocessDir(field1, field2, field3: string): string =
result = postprocessDirStart & field1 & postprocessDirSep & field2 & postprocessDirSep & field3 & postprocessDirEnd
proc genCLineDir(r: var Rope, fileIdx: FileIndex, line: int; conf: ConfigRef) =
assert line >= 0
if optLineDir in conf.options and line > 0:
r.addf("\n#line $2 $1\n",
[rope(makeSingleLineCString(filename)), rope(line)])
if fileIdx == InvalidFileIdx:
r.add(rope("\n#line " & $line & " \"generated_not_to_break_here\"\n"))
else:
r.add(rope("\n#line " & $line & " FX_" & $fileIdx.int32 & "\n"))
proc genCLineDir(r: var Rope, filename: string, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex) =
proc genCLineDir(r: var Rope, fileIdx: FileIndex, line: int; p: BProc; info: TLineInfo; lastFileIndex: FileIndex) =
assert line >= 0
if optLineDir in p.config.options and line > 0:
if lastFileIndex == info.fileIndex:
r.addf("\n#line $1\n", [rope(line)])
if fileIdx == InvalidFileIdx:
r.add(rope("\n#line " & $line & " \"generated_not_to_break_here\"\n"))
else:
r.addf("\n#line $2 $1\n",
[rope(makeSingleLineCString(filename)), rope(line)])
r.add(rope("\n#line " & $line & " FX_" & $fileIdx.int32 & "\n"))
proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
if optLineDir in conf.options:
genCLineDir(r, toFullPath(conf, info), info.safeLineNm, conf)
genCLineDir(r, info.fileIndex, info.safeLineNm, conf)
proc freshLineInfo(p: BProc; info: TLineInfo): bool =
if p.lastLineInfo.line != info.line or
@@ -291,17 +301,14 @@ proc freshLineInfo(p: BProc; info: TLineInfo): bool =
p.lastLineInfo.line = info.line
p.lastLineInfo.fileIndex = info.fileIndex
result = true
else:
result = false
proc genCLineDir(r: var Rope, p: BProc, info: TLineInfo; conf: ConfigRef) =
if optLineDir in conf.options:
let lastFileIndex = p.lastLineInfo.fileIndex
if freshLineInfo(p, info):
genCLineDir(r, toFullPath(conf, info), info.safeLineNm, p, info, lastFileIndex)
genCLineDir(r, info.fileIndex, info.safeLineNm, p, info, lastFileIndex)
proc genLineDir(p: BProc, t: PNode) =
if p == p.module.preInitProc: return
let line = t.info.safeLineNm
if optEmbedOrigSrc in p.config.globalOptions:
@@ -309,16 +316,11 @@ proc genLineDir(p: BProc, t: PNode) =
let lastFileIndex = p.lastLineInfo.fileIndex
let freshLine = freshLineInfo(p, t.info)
if freshLine:
genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p, t.info, lastFileIndex)
genCLineDir(p.s(cpsStmts), t.info.fileIndex, line, p, t.info, lastFileIndex)
if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx:
if freshLine:
if lastFileIndex == t.info.fileIndex:
linefmt(p, cpsStmts, "nimln_($1);",
[line])
else:
linefmt(p, cpsStmts, "nimlf_($1, $2);",
[line, quotedFilename(p.config, t.info)])
line(p, cpsStmts, genPostprocessDir("nimln", $line, $t.info.fileIndex.int32))
proc accessThreadLocalVar(p: BProc, s: PSym)
proc emulatedThreadVars(conf: ConfigRef): bool {.inline.}
@@ -348,12 +350,9 @@ proc addRdLoc(a: TLoc; result: var Rope) =
proc lenField(p: BProc): Rope {.inline.} =
result = rope(if p.module.compileToCpp: "len" else: "Sup.len")
proc lenExpr(p: BProc; a: TLoc; isString = false): Rope =
proc lenExpr(p: BProc; a: TLoc): Rope =
if optSeqDestructors in p.config.globalOptions:
if isString and p.config.isDefined("nimSeqsV3"):
result = ropecg(p.module, "(#nimStrLenV3($1))", [rdLoc(a)])
else:
result = rdLoc(a) & ".len"
result = rdLoc(a) & ".len"
else:
result = "($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)]
@@ -363,18 +362,12 @@ proc dataFieldAccessor(p: BProc, sym: Rope): Rope =
else:
result = sym
proc dataField(p: BProc; isString: bool = false): Rope =
# TODO: revisit this after unify strings and seqs
proc dataField(p: BProc): Rope =
if optSeqDestructors in p.config.globalOptions:
if isString and p.config.isDefined("nimSeqsV3"):
result = rope".p"
else:
result = rope".p->data"
result = rope".p->data"
else:
result = rope"->data"
proc genProcPrototype(m: BModule, sym: PSym)
include ccgliterals
include ccgtypes
@@ -413,6 +406,8 @@ proc rdCharLoc(a: TLoc): Rope =
type
TAssignmentFlag = enum
needToCopy
needToCopySinkParam
needTempForOpenArray
TAssignmentFlags = set[TAssignmentFlag]
proc genObjConstr(p: BProc, e: PNode, d: var TLoc)
@@ -444,7 +439,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
of frEmbedded:
if optTinyRtti in p.config.globalOptions:
var tmp: TLoc = default(TLoc)
var tmp: TLoc
if mode == constructRefObj:
let objType = t.skipTypes(abstractInst+{tyRef})
rawConstExpr(p, newNodeIT(nkType, a.lode.info, objType), tmp)
@@ -486,19 +481,14 @@ proc resetLoc(p: BProc, loc: var TLoc) =
assert loc.r != ""
let atyp = skipTypes(loc.t, abstractInst)
if p.config.isDefined("nimSeqsV3") and typ.kind == tyString:
if atyp.kind in {tyVar, tyLent}:
linefmt(p, cpsStmts, "$1->rawlen = 0; $1->p = NIM_NIL;$n", [rdLoc(loc)])
else:
linefmt(p, cpsStmts, "$1.rawlen = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
if atyp.kind in {tyVar, tyLent}:
linefmt(p, cpsStmts, "$1->len = 0; $1->p = NIM_NIL;$n", [rdLoc(loc)])
else:
if atyp.kind in {tyVar, tyLent}:
linefmt(p, cpsStmts, "$1->len = 0; $1->p = NIM_NIL;$n", [rdLoc(loc)])
else:
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
elif not isComplexValueType(typ):
if containsGcRef:
var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack)
var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.lode, OnStack)
nilLoc.r = rope("NIM_NIL")
genRefAssign(p, loc, nilLoc)
else:
@@ -515,32 +505,21 @@ proc resetLoc(p: BProc, loc: var TLoc) =
else:
# array passed as argument decayed into pointer, bug #7332
# so we use getTypeDesc here rather than rdLoc(loc)
let tyDesc = getTypeDesc(p.module, loc.t, descKindFromSymKind mapTypeChooser(loc))
if p.module.compileToCpp and isOrHasImportedCppType(typ):
if lfIndirect in loc.flags:
#C++ cant be just zeroed. We need to call the ctors
var tmp = getTemp(p, loc.t)
linefmt(p, cpsStmts,"#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
[addrLoc(p.config, loc), addrLoc(p.config, tmp), tyDesc])
else:
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
[addrLoc(p.config, loc), tyDesc])
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
[addrLoc(p.config, loc),
getTypeDesc(p.module, loc.t, descKindFromSymKind mapTypeChooser(loc))])
# XXX: We can be extra clever here and call memset only
# on the bytes following the m_type field?
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
let typ = loc.t
let typKind = skipTypes(typ, abstractInst + {tyStatic}).kind
if optSeqDestructors in p.config.globalOptions and typKind in {tyString, tySequence}:
if typKind == tyString and p.config.isDefined("nimSeqsV3"):
linefmt(p, cpsStmts, "$1.rawlen = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
else:
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}:
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
elif not isComplexValueType(typ):
if containsGarbageCollectedRef(loc.t):
var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack)
var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.lode, OnStack)
nilLoc.r = rope("NIM_NIL")
genRefAssign(p, loc, nilLoc)
else:
@@ -567,15 +546,17 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
if not immediateAsgn:
constructLoc(p, v.loc)
proc getTemp(p: BProc, t: PType, needsInit=false): TLoc =
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
inc(p.labels)
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
storage: OnStack, flags: {})
result.r = "T" & rope(p.labels) & "_"
if p.module.compileToCpp and isOrHasImportedCppType(t):
linefmt(p, cpsLocals, "$1 $2$3;$n", [getTypeDesc(p.module, t, dkVar), result.r,
genCppInitializer(p.module, p, t)])
linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, dkVar), result.r])
else:
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, dkVar), result.r])
result.k = locTemp
result.lode = lodeTyp t
result.storage = OnStack
result.flags = {}
constructLoc(p, result, not needsInit)
when false:
# XXX Introduce a compiler switch in order to detect these easily.
@@ -586,21 +567,25 @@ proc getTemp(p: BProc, t: PType, needsInit=false): TLoc =
echo "ENORMOUS TEMPORARY! ", p.config $ p.lastLineInfo
writeStackTrace()
proc getTempCpp(p: BProc, t: PType, value: Rope): TLoc =
proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) =
inc(p.labels)
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
storage: OnStack, flags: {})
result.r = "T" & rope(p.labels) & "_"
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, dkVar), result.r, value])
result.k = locTemp
result.lode = lodeTyp t
result.storage = OnStack
result.flags = {}
proc getIntTemp(p: BProc): TLoc =
proc getIntTemp(p: BProc, result: var TLoc) =
inc(p.labels)
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp,
storage: OnStack, lode: lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt),
flags: {})
result.r = "T" & rope(p.labels) & "_"
linefmt(p, cpsLocals, "NI $1;$n", [result.r])
result.k = locTemp
result.storage = OnStack
result.lode = lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt)
result.flags = {}
proc localVarDecl(p: BProc; n: PNode): Rope =
result = ""
let s = n.sym
if s.loc.k == locNone:
fillLocalName(p, s)
@@ -628,10 +613,7 @@ proc assignLocalVar(p: BProc, n: PNode) =
# this need not be fulfilled for inline procs; they are regenerated
# for each module that uses them!
let nl = if optLineDir in p.config.options: "" else: "\n"
var decl = localVarDecl(p, n)
if p.module.compileToCpp and isOrHasImportedCppType(n.typ):
decl.add genCppInitializer(p.module, p, n.typ)
decl.add ";" & nl
let decl = localVarDecl(p, n) & (if p.module.compileToCpp and isOrHasImportedCppType(n.typ): "{};" else: ";") & nl
line(p, cpsLocals, decl)
include ccgthreadvars
@@ -665,17 +647,17 @@ proc genGlobalVarDecl(p: BProc, n: PNode; td, value: Rope; decl: var Rope) =
else:
decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r])
proc genCppVarForCtor(p: BProc; call: PNode; decl: var Rope)
proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope)
proc callGlobalVarCppCtor(p: BProc; v: PSym; vn, value: PNode) =
let s = vn.sym
fillBackendName(p.module, s)
fillLoc(s.loc, locGlobalVar, vn, OnHeap)
var decl: Rope = ""
var decl: Rope
let td = getTypeDesc(p.module, vn.sym.typ, dkVar)
genGlobalVarDecl(p, vn, td, "", decl)
decl.add " " & $s.loc.r
genCppVarForCtor(p, value, decl)
genCppVarForCtor(p, v, vn, value, decl)
p.module.s[cfsVars].add decl
proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
@@ -753,19 +735,19 @@ proc genVarPrototype(m: BModule, n: PNode)
proc requestConstImpl(p: BProc, sym: PSym)
proc genStmts(p: BProc, t: PNode)
proc expr(p: BProc, n: PNode, d: var TLoc)
proc genProcPrototype(m: BModule, sym: PSym)
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc)
proc intLiteral(i: BiggestInt; result: var Rope)
proc genLiteral(p: BProc, n: PNode; result: var Rope)
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; argsCounter: var int)
proc raiseExit(p: BProc)
proc initLocExpr(p: BProc, e: PNode, flags: TLocFlags = {}): TLoc =
result = initLoc(locNone, e, OnUnknown, flags)
proc initLocExpr(p: BProc, e: PNode, result: var TLoc, flags: TLocFlags = {}) =
initLoc(result, locNone, e, OnUnknown, flags)
expr(p, e, result)
proc initLocExprSingleUse(p: BProc, e: PNode): TLoc =
result = initLoc(locNone, e, OnUnknown)
proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
initLoc(result, locNone, e, OnUnknown)
if e.kind in nkCallKinds and (e[0].kind != nkSym or e[0].sym.magic == mNone):
# We cannot check for tfNoSideEffect here because of mutable parameters.
discard "bug #8202; enforce evaluation order for nested calls for C++ too"
@@ -856,7 +838,8 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
var p = newProc(nil, m)
p.options.excl optStackTrace
p.flags.incl nimErrorFlagDisabled
var dest: TLoc = initLoc(locTemp, lib.path, OnStack)
var dest: TLoc
initLoc(dest, locTemp, lib.path, OnStack)
dest.r = getTempName(m)
appcg(m, m.s[cfsDynLibInit],"$1 $2;$n",
[getTypeDesc(m, lib.path.typ, dkVar), rdLoc(dest)])
@@ -891,10 +874,11 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
inc(m.labels, 2)
if isCall:
let n = lib.path
var a: TLoc = initLocExpr(m.initProc, n[0])
var a: TLoc
initLocExpr(m.initProc, n[0], a)
var params = rdLoc(a) & "("
for i in 1..<n.len-1:
a = initLocExpr(m.initProc, n[i])
initLocExpr(m.initProc, n[i], a)
params.add(rdLoc(a))
params.add(", ")
let load = "\t$1 = ($2) ($3$4));$n" %
@@ -1030,7 +1014,6 @@ proc containsResult(n: PNode): bool =
if containsResult(n[i]): return true
proc easyResultAsgn(n: PNode): PNode =
result = nil
case n.kind
of nkStmtList, nkStmtListExpr:
var i = 0
@@ -1049,7 +1032,7 @@ proc easyResultAsgn(n: PNode): PNode =
type
InitResultEnum = enum Unknown, InitSkippable, InitRequired
proc allPathsAsgnResult(n: PNode): InitResultEnum =
proc allPathsAsgnResult(p: BProc; n: PNode): InitResultEnum =
# Exceptions coming from calls don't have not be considered here:
#
# proc bar(): string = raise newException(...)
@@ -1064,7 +1047,7 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
# echo "a was not written to"
#
template allPathsInBranch(it) =
let a = allPathsAsgnResult(it)
let a = allPathsAsgnResult(p, it)
case a
of InitRequired: return InitRequired
of InitSkippable: discard
@@ -1076,14 +1059,20 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
case n.kind
of nkStmtList, nkStmtListExpr:
for it in n:
result = allPathsAsgnResult(it)
result = allPathsAsgnResult(p, it)
if result != Unknown: return result
of nkAsgn, nkFastAsgn, nkSinkAsgn:
if n[0].kind == nkSym and n[0].sym.kind == skResult:
if not containsResult(n[1]): result = InitSkippable
if not containsResult(n[1]):
if allPathsAsgnResult(p, n[1]) == InitRequired:
result = InitRequired
else:
result = InitSkippable
else: result = InitRequired
elif containsResult(n):
result = InitRequired
else:
result = allPathsAsgnResult(p, n[1])
of nkReturnStmt:
if n.len > 0:
if n[0].kind == nkEmpty and result != InitSkippable:
@@ -1092,7 +1081,7 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
# initialized. This avoids cases like #9286 where this heuristic lead to
# wrong code being generated.
result = InitRequired
else: result = allPathsAsgnResult(n[0])
else: result = allPathsAsgnResult(p, n[0])
of nkIfStmt, nkIfExpr:
var exhaustive = false
result = InitSkippable
@@ -1118,9 +1107,9 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
of nkWhileStmt:
# some dubious code can assign the result in the 'while'
# condition and that would be fine. Everything else isn't:
result = allPathsAsgnResult(n[0])
result = allPathsAsgnResult(p, n[0])
if result == Unknown:
result = allPathsAsgnResult(n[1])
result = allPathsAsgnResult(p, n[1])
# we cannot assume that the 'while' loop is really executed at least once:
if result == InitSkippable: result = Unknown
of harmless:
@@ -1145,9 +1134,21 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
allPathsInBranch(n[0])
for i in 1..<n.len:
if n[i].kind == nkFinally:
result = allPathsAsgnResult(n[i].lastSon)
result = allPathsAsgnResult(p, n[i].lastSon)
else:
allPathsInBranch(n[i].lastSon)
of nkCallKinds:
if canRaiseDisp(p, n[0]):
result = InitRequired
else:
for i in 0..<n.safeLen:
allPathsInBranch(n[i])
of nkRaiseStmt:
result = InitRequired
of nkChckRangeF, nkChckRange64, nkChckRange:
# TODO: more checks might need to be covered like overflow, indexDefect etc.
# bug #22852
result = InitRequired
else:
for i in 0..<n.safeLen:
allPathsInBranch(n[i])
@@ -1155,7 +1156,7 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
proc getProcTypeCast(m: BModule, prc: PSym): Rope =
result = getTypeDesc(m, prc.loc.t)
if prc.typ.callConv == ccClosure:
var rettype, params: Rope = ""
var rettype, params: Rope
var check = initIntSet()
genProcParams(m, prc.typ, rettype, params, check)
result = "$1(*)$2" % [rettype, params]
@@ -1173,15 +1174,14 @@ proc isNoReturn(m: BModule; s: PSym): bool {.inline.} =
proc genProcAux*(m: BModule, prc: PSym) =
var p = newProc(prc, m)
var header = newRopeAppender()
let isCppMember = m.config.backend == backendCpp and sfCppMember * prc.flags != {}
if isCppMember:
if m.config.backend == backendCpp and {sfVirtual, sfConstructor} * prc.flags != {}:
genMemberProcHeader(m, prc, header)
else:
genProcHeader(m, prc, header)
var returnStmt: Rope = ""
assert(prc.ast != nil)
var procBody = transformBody(m.g.graph, m.idgen, prc, {})
var procBody = transformBody(m.g.graph, m.idgen, prc, dontUseCache)
if sfInjectDestructors in prc.flags:
procBody = injectDestructorCalls(m.g.graph, m.idgen, prc, procBody)
@@ -1197,14 +1197,15 @@ proc genProcAux*(m: BModule, prc: PSym) =
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
var decl = localVarDecl(p, resNode)
var a: TLoc = initLocExprSingleUse(p, val)
var a: TLoc
initLocExprSingleUse(p, val, a)
linefmt(p, cpsStmts, "$1 = $2;$n", [decl, rdLoc(a)])
else:
# declare the result symbol:
assignLocalVar(p, resNode)
assert(res.loc.r != "")
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
allPathsAsgnResult(procBody) == InitSkippable:
allPathsAsgnResult(p, procBody) == InitSkippable:
# In an ideal world the codegen could rely on injectdestructors doing its job properly
# and then the analysis step would not be required.
discard "result init optimized out"
@@ -1212,7 +1213,6 @@ proc genProcAux*(m: BModule, prc: PSym) =
initLocalVar(p, res, immediateAsgn=false)
returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)])
elif sfConstructor in prc.flags:
resNode.sym.loc.flags.incl lfIndirect
fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap)
else:
fillResult(p.config, resNode, prc.typ)
@@ -1224,7 +1224,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
# global is either 'nil' or points to valid memory and so the RC operation
# succeeds without touching not-initialized memory.
if sfNoInit in prc.flags: discard
elif allPathsAsgnResult(procBody) == InitSkippable: discard
elif allPathsAsgnResult(p, procBody) == InitSkippable: discard
else:
resetLoc(p, res.loc)
if skipTypes(res.typ, abstractInst).kind == tyArray:
@@ -1240,13 +1240,13 @@ proc genProcAux*(m: BModule, prc: PSym) =
prc.info = tmpInfo
var generatedProc: Rope = ""
var generatedProc: Rope
generatedProc.genCLineDir prc.info, m.config
if isNoReturn(p.module, prc):
if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember:
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
header = "__declspec(noreturn) " & header
if sfPure in prc.flags:
if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember:
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
header = "__declspec(naked) " & header
generatedProc.add ropecg(p.module, "$1 {$n$2$3$4}$N$N",
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
@@ -1291,7 +1291,7 @@ proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
proc genProcPrototype(m: BModule, sym: PSym) =
useHeader(m, sym)
if lfNoDecl in sym.loc.flags or sfCppMember * sym.flags != {}: return
if lfNoDecl in sym.loc.flags or {sfVirtual, sfConstructor} * sym.flags != {}: return
if lfDynamicLib in sym.loc.flags:
if sym.itemId.module != m.module.position and
not containsOrIncl(m.declaredThings, sym.id):
@@ -1470,21 +1470,17 @@ proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
proc getSomeNameForModule(conf: ConfigRef, filename: AbsoluteFile): Rope =
## Returns a mangled module name.
result = ""
result.add mangleModuleName(conf, filename).mangle
proc getSomeNameForModule(m: BModule): Rope =
## Returns a mangled module name.
assert m.module.kind == skModule
assert m.module.owner.kind == skPackage
result = ""
result.add mangleModuleName(m.g.config, m.filename).mangle
proc getSomeInitName(m: BModule, suffix: string): Rope =
if not m.hcrOn:
result = getSomeNameForModule(m)
else:
result = ""
result.add suffix
proc getInitName(m: BModule): Rope =
@@ -1503,10 +1499,10 @@ proc genMainProc(m: BModule) =
## this function is called in cgenWriteModules after all modules are closed,
## it means raising dependency on the symbols is too late as it will not propagate
## into other modules, only simple rope manipulations are allowed
var preMainCode: Rope = ""
var preMainCode: Rope
if m.hcrOn:
proc loadLib(handle: string, name: string): Rope =
result = ""
let prc = magicsys.getCompilerProc(m.g.graph, name)
assert prc != nil
let n = newStrNode(nkStrLit, prc.annex.path.strVal)
@@ -1530,7 +1526,7 @@ proc genMainProc(m: BModule) =
else:
preMainCode.add("\t$1PreMain();\L" % [rope m.config.nimMainPrefix])
var posixCmdLine: Rope = ""
var posixCmdLine: Rope
if optNoMain notin m.config.globalOptions:
posixCmdLine.add "N_LIB_PRIVATE int cmdCount;\L"
posixCmdLine.add "N_LIB_PRIVATE char** cmdLine;\L"
@@ -1814,7 +1810,7 @@ proc genDatInitCode(m: BModule) =
# we don't want to break into such init code - could happen if a line
# directive from a function written by the user spills after itself
genCLineDir(prc, "generated_not_to_break_here", 999999, m.config)
genCLineDir(prc, InvalidFileIdx, 999999, m.config)
for i in cfsTypeInit1..cfsDynLibInit:
if m.s[i].len != 0:
@@ -1855,7 +1851,7 @@ proc genInitCode(m: BModule) =
[rope(if m.hcrOn: "N_LIB_EXPORT" else: "N_LIB_PRIVATE"), initname]
# we don't want to break into such init code - could happen if a line
# directive from a function written by the user spills after itself
genCLineDir(prc, "generated_not_to_break_here", 999999, m.config)
genCLineDir(prc, InvalidFileIdx, 999999, m.config)
if m.typeNodes > 0:
if m.hcrOn:
appcg(m, m.s[cfsTypeInit1], "\t#TNimNode* $1;$N", [m.typeNodesName])
@@ -1970,6 +1966,40 @@ proc genInitCode(m: BModule) =
registerModuleToMain(m.g, m)
proc postprocessCode(conf: ConfigRef, r: var Rope) =
# find the first directive
var f = r.find(postprocessDirStart)
if f == -1:
return
var
nimlnDirLastF = ""
var res: Rope = r.substr(0, f - 1)
while f != -1:
var
e = r.find(postprocessDirEnd, f + 1)
dir = r.substr(f + 1, e - 1).split(postprocessDirSep)
case dir[0]
of "nimln":
if dir[2] == nimlnDirLastF:
res.add("nimln_(" & dir[1] & ");")
else:
res.add("nimlf_(" & dir[1] & ", " & quotedFilename(conf, dir[2].parseInt.FileIndex) & ");")
nimlnDirLastF = dir[2]
else:
raiseAssert "unexpected postprocess directive"
# find the next directive
f = r.find(postprocessDirStart, e + 1)
# copy the code until the next directive
if f != -1:
res.add(r.substr(e + 1, f - 1))
else:
res.add(r.substr(e + 1))
r = res
proc genModule(m: BModule, cfile: Cfile): Rope =
var moduleIsEmpty = true
@@ -1998,9 +2028,17 @@ proc genModule(m: BModule, cfile: Cfile): Rope =
if m.config.cppCustomNamespace.len > 0:
closeNamespaceNim(result)
if optLineDir in m.config.options:
var srcFileDefs = ""
for fi in 0..m.config.m.fileInfos.high:
srcFileDefs.add("#define FX_" & $fi & " " & makeSingleLineCString(toFullPath(m.config, fi.FileIndex)) & "\n")
result = srcFileDefs & result
if moduleIsEmpty:
result = ""
postprocessCode(m.config, result)
proc initProcOptions(m: BModule): TOptions =
let opts = m.config.options
if sfSystemModule in m.module.flags: opts-{optStackTrace} else: opts
@@ -2025,7 +2063,7 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
result.preInitProc = newProc(nil, result)
result.preInitProc.flags.incl nimErrorFlagDisabled
result.preInitProc.labels = 100_000 # little hack so that unique temporaries are generated
result.dataCache = initNodeTable()
initNodeTable(result.dataCache)
result.typeStack = @[]
result.typeNodesName = getTempName(result)
result.nimTypesName = getTempName(result)
@@ -2200,7 +2238,7 @@ proc updateCachedModule(m: BModule) =
cf.flags = {CfileFlag.Cached}
addFileToCompile(m.config, cf)
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode =
## Also called from IC.
if sfMainModule in m.module.flags:
# phase ordering problem here: We need to announce this
@@ -2249,11 +2287,7 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
if m.g.forwardedProcs.len == 0:
incl m.flags, objHasKidsValid
if optMultiMethods in m.g.config.globalOptions or
m.g.config.selectedGC notin {gcArc, gcOrc, gcAtomicArc} or
vtables notin m.g.config.features:
generateIfMethodDispatchers(graph, m.idgen)
result = generateMethodDispatchers(graph, m.idgen)
let mm = m
m.g.modulesClosed.add mm

View File

@@ -10,10 +10,8 @@
## This module contains the data structures for the C code generation phase.
import
ast, ropes, options,
ndi, lineinfos, pathutils, modulegraphs
import std/[intsets, tables, sets]
ast, ropes, options, intsets,
tables, ndi, lineinfos, pathutils, modulegraphs, sets
type
TLabel* = Rope # for the C generator a label is just a rope
@@ -137,6 +135,7 @@ type
# unconditionally...
# nimtvDeps is VERY hard to cache because it's
# not a list of IDs nor can it be made to be one.
mangledPrcs*: HashSet[string]
TCGen = object of PPassContext # represents a C source file
s*: TCFileSections # sections of the C file
@@ -150,7 +149,7 @@ type
typeABICache*: HashSet[SigHash] # cache for ABI checks; reusing typeCache
# would be ideal but for some reason enums
# don't seem to get cached so it'd generate
# 1 ABI check per occurence in code
# 1 ABI check per occurrence in code
forwTypeCache*: TypeCache # cache for forward declarations of types
declaredThings*: IntSet # things we have declared in this .c file
declaredProtos*: IntSet # prototypes we have declared in this .c file

View File

@@ -10,15 +10,12 @@
## This module implements code generation for methods.
import
options, ast, msgs, idents, renderer, types, magicsys,
sempass2, modulegraphs, lineinfos, astalgo
import std/intsets
intsets, options, ast, msgs, idents, renderer, types, magicsys,
sempass2, modulegraphs, lineinfos
when defined(nimPreviewSlimSystem):
import std/assertions
import std/[tables]
proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode =
var dest = skipTypes(d, abstractPtrs)
@@ -47,8 +44,6 @@ proc getDispatcher*(s: PSym): PSym =
if dispatcherPos < s.ast.len:
result = s.ast[dispatcherPos].sym
doAssert sfDispatcher in result.flags
else:
result = nil
proc methodCall*(n: PNode; conf: ConfigRef): PNode =
result = n
@@ -67,7 +62,6 @@ type
MethodResult = enum No, Invalid, Yes
proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
result = No
if a.name.id != b.name.id: return
if a.typ.len != b.typ.len:
return
@@ -124,7 +118,7 @@ proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
incl(disp.flags, sfDispatcher)
excl(disp.flags, sfExported)
let old = disp.typ
disp.typ = copyType(disp.typ, idgen, disp.typ.owner)
disp.typ = copyType(disp.typ, nextTypeId(idgen), disp.typ.owner)
copyTypeProps(g, idgen.module, disp.typ, old)
# we can't inline the dispatcher itself (for now):
@@ -156,10 +150,7 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
disp.ast[resultPos] = copyTree(meth.ast[resultPos])
proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
var witness: PSym = nil
if s.typ[1].owner.getModule != s.getModule and vtables in g.config.features and not g.config.isDefined("nimInternalNonVtablesTesting"):
localError(g.config, s.info, errGenerated, "method `" & s.name.s &
"` can be defined only in the same module with its type (" & s.typ[1].typeToString() & ")")
var witness: PSym
for i in 0..<g.methods.len:
let disp = g.methods[i].dispatcher
case sameMethodBucket(disp, s, multimethods = optMultiMethods in g.config.globalOptions)
@@ -178,11 +169,6 @@ proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
of Invalid:
if witness.isNil: witness = g.methods[i].methods[0]
# create a new dispatcher:
# stores the id and the position
if s.typ[1].skipTypes(skipPtrs).itemId notin g.bucketTable:
g.bucketTable[s.typ[1].skipTypes(skipPtrs).itemId] = 1
else:
g.bucketTable.inc(s.typ[1].skipTypes(skipPtrs).itemId)
g.methods.add((methods: @[s], dispatcher: createDispatcher(s, g, idgen)))
#echo "adding ", s.info
if witness != nil:
@@ -191,9 +177,8 @@ proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
elif sfBase notin s.flags:
message(g.config, s.info, warnUseBase)
proc relevantCol*(methods: seq[PSym], col: int): bool =
proc relevantCol(methods: seq[PSym], col: int): bool =
# returns true iff the position is relevant
result = false
var t = methods[0].typ[col].skipTypes(skipPtrs)
if t.kind == tyObject:
for i in 1..high(methods):
@@ -202,7 +187,6 @@ proc relevantCol*(methods: seq[PSym], col: int): bool =
return true
proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
result = 0
for col in 1..<a.typ.len:
if contains(relevantCols, col):
var aa = skipTypes(a.typ[col], skipPtrs)
@@ -211,7 +195,7 @@ proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
if (d != high(int)) and d != 0:
return d
proc sortBucket*(a: var seq[PSym], relevantCols: IntSet) =
proc sortBucket(a: var seq[PSym], relevantCols: IntSet) =
# we use shellsort here; fast and simple
var n = a.len
var h = 1
@@ -230,7 +214,7 @@ proc sortBucket*(a: var seq[PSym], relevantCols: IntSet) =
a[j] = v
if h == 1: break
proc genIfDispatcher*(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idgen: IdGenerator): PSym =
proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idgen: IdGenerator): PSym =
var base = methods[0].ast[dispatcherPos].sym
result = base
var paramLen = base.typ.len
@@ -289,7 +273,8 @@ proc genIfDispatcher*(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet;
nilchecks.flags.incl nfTransf # should not be further transformed
result.ast[bodyPos] = nilchecks
proc generateIfMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator) =
proc generateMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator): PNode =
result = newNode(nkStmtList)
for bucket in 0..<g.methods.len:
var relevantCols = initIntSet()
for col in 1..<g.methods[bucket].methods[0].typ.len:
@@ -298,4 +283,4 @@ proc generateIfMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator) =
# if multi-methods are not enabled, we are interested only in the first field
break
sortBucket(g.methods[bucket].methods, relevantCols)
g.addDispatchers genIfDispatcher(g, g.methods[bucket].methods, relevantCols, idgen)
result.add newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols, idgen))

View File

@@ -134,9 +134,7 @@
import
ast, msgs, idents,
renderer, magicsys, lowerings, lambdalifting, modulegraphs, lineinfos,
options
import std/tables
tables, options
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -165,7 +163,7 @@ type
const
nkSkip = {nkEmpty..nkNilLit, nkTemplateDef, nkTypeSection, nkStaticStmt,
nkCommentStmt, nkMixinStmt, nkBindStmt} + procDefs
nkCommentStmt, nkMixinStmt, nkBindStmt, nkTypeOfExpr} + procDefs
proc newStateAccess(ctx: var Ctx): PNode =
if ctx.stateVarSym.isNil:
@@ -260,9 +258,8 @@ proc hasYields(n: PNode): bool =
of nkYieldStmt:
result = true
of nkSkip:
result = false
discard
else:
result = false
for c in n:
if c.hasYields:
result = true
@@ -328,7 +325,7 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
var ifBranch: PNode
if c.len > 1:
var cond: PNode = nil
var cond: PNode
for i in 0..<c.len - 1:
assert(c[i].kind == nkType)
let nextCond = newTree(nkCall,
@@ -391,22 +388,19 @@ proc getFinallyNode(ctx: var Ctx, n: PNode): PNode =
proc hasYieldsInExpressions(n: PNode): bool =
case n.kind
of nkSkip:
result = false
discard
of nkStmtListExpr:
if isEmptyType(n.typ):
result = false
for c in n:
if c.hasYieldsInExpressions:
return true
else:
result = n.hasYields
of nkCast:
result = false
for i in 1..<n.len:
if n[i].hasYieldsInExpressions:
return true
else:
result = false
for c in n:
if c.hasYieldsInExpressions:
return true
@@ -501,7 +495,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
if ns:
needsSplit = true
var tmp: PSym = nil
var tmp: PSym
let isExpr = not isEmptyType(n.typ)
if isExpr:
tmp = ctx.newTempVar(n.typ)
@@ -1160,9 +1154,9 @@ proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode=
n[i] = ctx.skipThroughEmptyStates(n[i])
proc newArrayType(g: ModuleGraph; n: int, t: PType; idgen: IdGenerator; owner: PSym): PType =
result = newType(tyArray, idgen, owner)
result = newType(tyArray, nextTypeId(idgen), owner)
let rng = newType(tyRange, idgen, owner)
let rng = newType(tyRange, nextTypeId(idgen), owner)
rng.n = newTree(nkRange, g.newIntLit(owner.info, 0), g.newIntLit(owner.info, n - 1))
rng.rawAddSon(t)
@@ -1367,7 +1361,6 @@ proc freshVars(n: PNode; c: var FreshVarsContext): PNode =
else:
result.add it
of nkRaiseStmt:
result = nil
localError(c.config, c.info, "unsupported control flow: 'finally: ... raise' duplicated because of 'break'")
else:
result = n

View File

@@ -11,9 +11,7 @@
import
options, idents, nimconf, extccomp, commands, msgs,
lineinfos, modulegraphs, condsyms, pathutils
import std/[os, parseopt]
lineinfos, modulegraphs, condsyms, os, pathutils, parseopt
proc prependCurDir*(f: AbsoluteFile): AbsoluteFile =
when defined(unix):
@@ -57,6 +55,11 @@ proc loadConfigsAndProcessCmdLine*(self: NimProg, cache: IdentCache; conf: Confi
if conf.cmd == cmdNimscript:
incl(conf.globalOptions, optWasNimscript)
loadConfigs(DefaultConfig, cache, conf, graph.idgen) # load all config files
# restores `conf.notes` after loading config files
# because it has overwrites the notes when compiling the system module which
# is a foreign module compared to the project
if conf.cmd in cmdBackends:
conf.notes = conf.mainPackageNotes
if not self.suggestMode:
let scriptFile = conf.projectFull.changeFileExt("nims")

View File

@@ -27,9 +27,7 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none")
import std/[setutils, os, strutils, parseutils, parseopt, sequtils, strtabs]
import
msgs, options, nversion, condsyms, extccomp, platform,
wordrecg, nimblecmd, lineinfos, pathutils
import std/pathnorm
wordrecg, nimblecmd, lineinfos, pathutils, pathnorm
from ast import setUseIc, eqTypeFlags, tfGcSafe, tfNoSideEffect
@@ -186,7 +184,7 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
info: TLineInfo; orig: string; conf: ConfigRef) =
var id = "" # arg = key or [key] or key:val or [key]:val; with val=on|off
var i = 0
var notes: set[TMsgKind] = {}
var notes: set[TMsgKind]
var isBracket = false
if i < arg.len and arg[i] == '[':
isBracket = true
@@ -269,17 +267,13 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
of "none": result = conf.selectedGC == gcNone
of "stack", "regions": result = conf.selectedGC == gcRegions
of "atomicarc": result = conf.selectedGC == gcAtomicArc
else:
result = false
localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
of "opt":
case arg.normalize
of "speed": result = contains(conf.options, optOptimizeSpeed)
of "size": result = contains(conf.options, optOptimizeSize)
of "none": result = conf.options * {optOptimizeSpeed, optOptimizeSize} == {}
else:
result = false
localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
of "verbosity": result = $conf.verbosity == arg
of "app":
case arg.normalize
@@ -289,9 +283,7 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
not contains(conf.globalOptions, optGenGuiApp)
of "staticlib": result = contains(conf.globalOptions, optGenStaticLib) and
not contains(conf.globalOptions, optGenGuiApp)
else:
result = false
localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
of "dynliboverride":
result = isDynlibOverride(conf, arg)
of "exceptions":
@@ -300,12 +292,8 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
of "setjmp": result = conf.exc == excSetjmp
of "quirky": result = conf.exc == excQuirky
of "goto": result = conf.exc == excGoto
else:
result = false
localError(conf, info, errInvalidExceptionSystem % arg)
else:
result = false
invalidCmdLineOption(conf, passCmd1, switch, info)
else: localError(conf, info, errInvalidExceptionSystem % arg)
else: invalidCmdLineOption(conf, passCmd1, switch, info)
proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool =
case switch.normalize
@@ -351,14 +339,10 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
if switch.normalize == "patterns": deprecatedAlias(switch, "trmacros")
result = contains(conf.options, optTrMacros)
of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace)
of "nilseqs", "nilchecks", "taintmode":
warningOptionNoop(switch)
result = false
of "nilseqs", "nilchecks", "taintmode": warningOptionNoop(switch)
of "panics": result = contains(conf.globalOptions, optPanics)
of "jsbigint64": result = contains(conf.globalOptions, optJsBigInt64)
else:
result = false
invalidCmdLineOption(conf, passCmd1, switch, info)
else: invalidCmdLineOption(conf, passCmd1, switch, info)
proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
notRelativeToProj = false): AbsoluteDir =
@@ -400,8 +384,7 @@ proc makeAbsolute(s: string): AbsoluteFile =
proc setTrackingInfo(conf: ConfigRef; dirty, file, line, column: string,
info: TLineInfo) =
## set tracking info, common code for track, trackDirty, & ideTrack
var ln: int = 0
var col: int = 0
var ln, col: int
if parseUtils.parseInt(line, ln) <= 0:
localError(conf, info, errInvalidNumber % line)
if parseUtils.parseInt(column, col) <= 0:
@@ -462,12 +445,10 @@ proc handleCmdInput*(conf: ConfigRef) =
proc parseCommand*(command: string): Command =
case command.normalize
of "c", "cc", "compile", "compiletoc": cmdCompileToC
of "nir": cmdCompileToNir
of "cpp", "compiletocpp": cmdCompileToCpp
of "objc", "compiletooc": cmdCompileToOC
of "js", "compiletojs": cmdCompileToJS
of "r": cmdCrun
of "m": cmdM
of "run": cmdTcc
of "check": cmdCheck
of "e": cmdNimscript
@@ -500,7 +481,6 @@ proc setCmd*(conf: ConfigRef, cmd: Command) =
of cmdCompileToCpp: conf.backend = backendCpp
of cmdCompileToOC: conf.backend = backendObjc
of cmdCompileToJS: conf.backend = backendJs
of cmdCompileToNir: conf.backend = backendNir
else: discard
proc setCommandEarly*(conf: ConfigRef, command: string) =
@@ -613,17 +593,10 @@ proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass,
defineSymbol(conf.symbols, "gcregions")
else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
proc pathRelativeToConfig(arg: string, pass: TCmdLinePass, conf: ConfigRef): string =
if pass == passPP and not isAbsolute(arg):
assert isAbsolute(conf.currentConfigDir), "something is wrong with currentConfigDir"
result = conf.currentConfigDir / arg
else:
result = arg
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
conf: ConfigRef) =
var key = ""
var val = ""
var
key, val: string
case switch.normalize
of "eval":
expectArg(conf, switch, arg, pass, info)
@@ -638,7 +611,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
for path in nimbleSubs(conf, arg):
addPath(conf, if pass == passPP: processCfgPath(conf, path, info)
else: processPath(conf, path, info), info)
of "nimblepath":
of "nimblepath", "babelpath":
if switch.normalize == "babelpath": deprecatedAlias(switch, "nimblepath")
if pass in {passCmd2, passPP} and optNoNimblePath notin conf.globalOptions:
expectArg(conf, switch, arg, pass, info)
var path = processPath(conf, arg, info, notRelativeToProj=true)
@@ -648,7 +622,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
nimblePath(conf, path, info)
path = nimbleDir / RelativeDir"pkgs"
nimblePath(conf, path, info)
of "nonimblepath":
of "nonimblepath", "nobabelpath":
if switch.normalize == "nobabelpath": deprecatedAlias(switch, "nonimblepath")
expectNoArg(conf, switch, arg, pass, info)
disableNimblePath(conf)
of "clearnimblepath":
@@ -665,7 +640,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
# refs bug #18674, otherwise `--os:windows` messes up with `--nimcache` set
# in config nims files, e.g. via: `import os; switch("nimcache", "/tmp/somedir")`
if conf.target.targetOS == osWindows and DirSep == '/': arg = arg.replace('\\', '/')
conf.nimcacheDir = processPath(conf, pathRelativeToConfig(arg, pass, conf), info, notRelativeToProj=true)
conf.nimcacheDir = processPath(conf, arg, info, notRelativeToProj=true)
of "out", "o":
expectArg(conf, switch, arg, pass, info)
let f = splitFile(processPath(conf, arg, info, notRelativeToProj=true).string)
@@ -799,10 +774,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
if conf.backend == backendJs or conf.cmd == cmdNimscript: discard
else: processOnOffSwitchG(conf, {optThreads}, arg, pass, info)
#if optThreads in conf.globalOptions: conf.setNote(warnGcUnsafe)
of "tlsemulation":
processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info)
if optTlsEmulation in conf.globalOptions:
conf.legacyFeatures.incl emitGenerics
of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info)
of "implicitstatic":
processOnOffSwitch(conf, {optImplicitStatic}, arg, pass, info)
of "patterns", "trmacros":
@@ -910,19 +882,15 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
defineSymbol(conf.symbols, "nodejs")
of "maxloopiterationsvm":
expectArg(conf, switch, arg, pass, info)
var value: int = 10_000_000
discard parseSaturatedNatural(arg, value)
if not value > 0: localError(conf, info, "maxLoopIterationsVM must be a positive integer greater than zero")
conf.maxLoopIterationsVM = value
conf.maxLoopIterationsVM = parseInt(arg)
of "errormax":
expectArg(conf, switch, arg, pass, info)
# Note: `nim check` (etc) can overwrite this.
# `0` is meaningless, give it a useful meaning as in clang's -ferror-limit
# If user doesn't set this flag and the code doesn't either, it'd
# have the same effect as errorMax = 1
var value: int = 0
discard parseSaturatedNatural(arg, value)
conf.errorMax = if value == 0: high(int) else: value
let ret = parseInt(arg)
conf.errorMax = if ret == 0: high(int) else: ret
of "verbosity":
expectArg(conf, switch, arg, pass, info)
let verbosity = parseInt(arg)
@@ -936,9 +904,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
conf.mainPackageNotes = conf.notes
of "parallelbuild":
expectArg(conf, switch, arg, pass, info)
var value: int = 0
discard parseSaturatedNatural(arg, value)
conf.numberOfProcessors = value
conf.numberOfProcessors = parseInt(arg)
of "version", "v":
expectNoArg(conf, switch, arg, pass, info)
writeVersionInfo(conf, pass)
@@ -1147,8 +1113,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
else: invalidCmdLineOption(conf, pass, switch, info)
proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) =
var cmd = ""
var arg = ""
var cmd, arg: string
splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo)
processSwitch(cmd, arg, pass, gCmdLineInfo, config)
@@ -1175,10 +1140,7 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
config.projectName = unixToNativePath(p.key)
config.arguments = cmdLineRest(p)
result = true
elif pass != passCmd2:
setCommandEarly(config, p.key)
result = false
else: result = false
elif pass != passCmd2: setCommandEarly(config, p.key)
else:
if pass == passCmd1: config.commandArgs.add p.key
if argsCount == 1:
@@ -1189,6 +1151,4 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
config.projectName = unixToNativePath(p.key)
config.arguments = cmdLineRest(p)
result = true
else:
result = false
inc argsCount

View File

@@ -11,9 +11,9 @@
## 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, astalgo, semdata, lookups, lineinfos, idents, msgs, renderer, types, intsets
import std/intsets
from magicsys import addSonSkipIntLit
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -28,11 +28,23 @@ proc declareSelf(c: PContext; info: TLineInfo) =
## Adds the magical 'Self' symbols to the current scope.
let ow = getCurrOwner(c)
let s = newSym(skType, getIdent(c.cache, "Self"), c.idgen, ow, info)
s.typ = newType(tyTypeDesc, c.idgen, ow)
s.typ = newType(tyTypeDesc, nextTypeId(c.idgen), ow)
s.typ.flags.incl {tfUnresolved, tfPacked}
s.typ.add newType(tyEmpty, c.idgen, ow)
s.typ.add newType(tyEmpty, nextTypeId(c.idgen), ow)
addDecl(c, s, info)
proc isSelf*(t: PType): bool {.inline.} =
## Is this the magical 'Self' type?
t.kind == tyTypeDesc and tfPacked in t.flags
proc makeTypeDesc*(c: PContext, typ: PType): PType =
if typ.kind == tyTypeDesc and not isSelf(typ):
result = typ
else:
result = newTypeS(tyTypeDesc, c)
incl result.flags, tfCheckedForDestructor
result.addSonSkipIntLit(typ, c.idgen)
proc semConceptDecl(c: PContext; n: PNode): PNode =
## Recursive helper for semantic checking for the concept declaration.
## Currently we only support (possibly empty) lists of statements
@@ -109,11 +121,8 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
for i in 0..<a.len:
if not matchType(c, f[i], a[i], m): return false
return true
else:
result = false
of tyGenericInvocation:
result = false
if a.kind == tyGenericInst and a[0].kind == tyGenericBody:
if sameType(f[0], a[0]) and f.len == a.len-1:
for i in 1 ..< f.len:
@@ -147,17 +156,15 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
result = matchType(c, old, ak, m)
if m.magic == mArrPut and ak.kind == tyGenericParam:
result = true
else:
result = false
#echo "B for ", result, " to ", typeToString(a), " to ", typeToString(m.potentialImplementation)
of tyVar, tySink, tyLent, tyOwned:
# modifiers in the concept must be there in the actual implementation
# too but not vice versa.
if a.kind == f.kind:
result = matchType(c, f[0], a[0], m)
result = matchType(c, f.sons[0], a.sons[0], m)
elif m.magic == mArrPut:
result = matchType(c, f[0], a, m)
result = matchType(c, f.sons[0], a, m)
else:
result = false
of tyEnum, tyObject, tyDistinct:
@@ -178,7 +185,6 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
m.inferred.setLen oldLen
of tyArray, tyTuple, tyVarargs, tyOpenArray, tyRange, tySequence, tyRef, tyPtr,
tyGenericInst:
result = false
let ak = a.skipTypes(ignorableForArgType - {f.kind})
if ak.kind == f.kind and f.len == ak.len:
for i in 0..<ak.len:
@@ -203,7 +209,6 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
if not result:
m.inferred.setLen oldLen
else:
result = false
for i in 0..<f.len:
result = matchType(c, f[i], a, m)
if result: break # and remember the binding!
@@ -252,7 +257,7 @@ proc matchSym(c: PContext; candidate: PSym, n: PNode; m: var MatchCon): bool =
m.inferred.setLen oldLen
return false
if not matchReturnType(c, n[0].sym.typ[0], candidate.typ[0], m):
if not matchReturnType(c, n[0].sym.typ.sons[0], candidate.typ.sons[0], m):
m.inferred.setLen oldLen
return false
@@ -309,7 +314,7 @@ proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool =
proc conceptMatch*(c: PContext; concpt, arg: PType; bindings: var TIdTable; invocation: PType): bool =
## Entry point from sigmatch. 'concpt' is the concept we try to match (here still a PType but
## we extract its AST via 'concpt.n.lastSon'). 'arg' is the type that might fullfill the
## we extract its AST via 'concpt.n.lastSon'). 'arg' is the type that might fulfill the
## concept's requirements. If so, we return true and fill the 'bindings' with pairs of
## (typeVar, instance) pairs. ('typeVar' is usually simply written as a generic 'T'.)
## 'invocation' can be nil for atomic concepts. For non-atomic concepts, it contains the

View File

@@ -10,7 +10,7 @@
# This module handles the conditional symbols.
import
std/strtabs
strtabs
from options import Feature
from lineinfos import hintMin, hintMax, warnMin, warnMax
@@ -157,12 +157,9 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimAllowNonVarDestructor")
defineSymbol("nimHasQuirky")
defineSymbol("nimHasEnsureMove")
defineSymbol("nimUseStrictDefs")
defineSymbol("nimHasNolineTooLong")
defineSymbol("nimHasNoReturnError")
defineSymbol("nimHasCastExtendedVm")
defineSymbol("nimHasWarnStdPrefix")
defineSymbol("nimHasVtables")
defineSymbol("nimHasSeqsV3")
defineSymbol("nimHasGenericsOpenSym2")
defineSymbol("nimHasNolineTooLong")
defineSymbol("nimHasGenericsOpenSym3")

View File

@@ -14,7 +14,7 @@ import options, ast, ropes, pathutils, msgs, lineinfos
import modulegraphs
import std/[os, parseutils]
import std/strutils except addf
import strutils except addf
import std/private/globs
when defined(nimPreviewSlimSystem):
@@ -42,7 +42,7 @@ proc toNimblePath(s: string, isStdlib: bool): string =
let sub = "lib/"
var start = s.find(sub)
if start < 0:
raiseAssert "unreachable"
doAssert false
else:
start += sub.len
let base = s[start..^1]
@@ -105,6 +105,11 @@ proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) =
changeFileExt(project, "dot"))
proc setupDependPass*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
result = PGen(module: module, config: graph.config, graph: graph)
var g: PGen
new(g)
g.module = module
g.config = graph.config
g.graph = graph
if graph.backend == nil:
graph.backend = Backend(dotGraph: "")
result = g

View File

@@ -22,9 +22,8 @@
## "A GraphFree Approach to DataFlow Analysis" by Markus Mohnen.
## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf
import ast, lineinfos, renderer, aliasanalysis
import ast, intsets, lineinfos, renderer, aliasanalysis
import std/private/asciitables
import std/intsets
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -61,7 +60,6 @@ type
proc codeListing(c: ControlFlowGraph, start = 0; last = -1): string =
# for debugging purposes
# first iteration: compute all necessary labels:
result = ""
var jumpTargets = initIntSet()
let last = if last < 0: c.len-1 else: min(last, c.len-1)
for i in start..last:
@@ -113,7 +111,7 @@ proc patch(c: var Con, p: TPosition) =
proc gen(c: var Con; n: PNode)
proc popBlock(c: var Con; oldLen: int) =
var exits: seq[TPosition] = @[]
var exits: seq[TPosition]
exits.add c.gotoI()
for f in c.blocks[oldLen].breakFixups:
c.patch(f[0])
@@ -130,6 +128,10 @@ template withBlock(labl: PSym; body: untyped) =
body
popBlock(c, oldLen)
proc isTrue(n: PNode): bool =
n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
n.kind == nkIntLit and n.intVal != 0
template forkT(body) =
let lab1 = c.forkI()
body
@@ -261,7 +263,7 @@ proc genBreakOrRaiseAux(c: var Con, i: int, n: PNode) =
if c.blocks[i].isTryBlock:
c.blocks[i].raiseFixups.add lab1
else:
var trailingFinales: seq[PNode] = @[]
var trailingFinales: seq[PNode]
if c.inTryStmt > 0:
# Ok, we are in a try, lets see which (if any) try's we break out from:
for b in countdown(c.blocks.high, i):
@@ -467,7 +469,7 @@ proc gen(c: var Con; n: PNode) =
of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, PathKinds1:
gen(c, n[1])
of nkVarSection, nkLetSection: genVarSection(c, n)
of nkDefer: raiseAssert "dfa construction pass requires the elimination of 'defer'"
of nkDefer: doAssert false, "dfa construction pass requires the elimination of 'defer'"
else: discard
when false:

View File

@@ -15,16 +15,15 @@
## For corresponding users' documentation see [Nim DocGen Tools Guide].
import
ast, options, msgs, idents,
ast, strutils, strtabs, algorithm, sequtils, options, msgs, os, idents,
wordrecg, syntaxes, renderer, lexer,
packages/docutils/[rst, rstidx, rstgen, dochelpers],
trees, types,
typesrenderer, astalgo, lineinfos,
pathutils, nimpaths, renderverbatim, packages
json, xmltree, trees, types,
typesrenderer, astalgo, lineinfos, intsets,
pathutils, tables, nimpaths, renderverbatim, osproc, packages
import packages/docutils/rstast except FileIndex, TLineInfo
import std/[os, strutils, strtabs, algorithm, json, osproc, tables, intsets, xmltree, sequtils]
from std/uri import encodeUrl
from uri import encodeUrl
from nodejs import findNodeJs
when defined(nimPreviewSlimSystem):
@@ -171,7 +170,6 @@ proc cmpDecimalsIgnoreCase(a, b: string): int =
proc prettyString(a: object): string =
# xxx pending std/prettyprint refs https://github.com/nim-lang/RFCs/issues/203#issuecomment-602534906
result = ""
for k, v in fieldPairs(a):
result.add k & ": " & $v & "\n"
@@ -217,16 +215,12 @@ proc whichType(d: PDoc; n: PNode): PSym =
if n.kind == nkSym:
if d.types.strTableContains(n.sym):
result = n.sym
else:
result = nil
else:
result = nil
for i in 0..<n.safeLen:
let x = whichType(d, n[i])
if x != nil: return x
proc attachToType(d: PDoc; p: PSym): PSym =
result = nil
let params = p.ast[paramsPos]
template check(i) =
result = whichType(d, params[i])
@@ -349,7 +343,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
if conf.configVars.hasKey("doc.googleAnalytics") and
conf.configVars.hasKey("doc.plausibleAnalytics"):
raiseAssert "Either use googleAnalytics or plausibleAnalytics"
doAssert false, "Either use googleAnalytics or plausibleAnalytics"
if conf.configVars.hasKey("doc.googleAnalytics"):
result.analytics = """
@@ -374,7 +368,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
result.seenSymbols = newStringTable(modeCaseInsensitive)
result.id = 100
result.jEntriesFinal = newJArray()
result.types = initStrTable()
initStrTable result.types
result.onTestSnippet =
proc (gen: var RstGenerator; filename, cmd: string; status: int; content: string) {.gcsafe.} =
if conf.docCmd == docCmdSkip: return
@@ -441,8 +435,6 @@ proc genComment(d: PDoc, n: PNode): PRstNode =
d.conf, d.sharedState)
except ERecoverableError:
result = newRstNode(rnLiteralBlock, @[newRstLeaf(n.comment)])
else:
result = nil
proc genRecCommentAux(d: PDoc, n: PNode): PRstNode =
if n == nil: return nil
@@ -477,7 +469,6 @@ proc getPlainDocstring(n: PNode): string =
elif startsWith(n.comment, "##"):
result = n.comment
else:
result = ""
for i in 0..<n.safeLen:
result = getPlainDocstring(n[i])
if result.len > 0: return
@@ -493,8 +484,9 @@ proc externalDep(d: PDoc; module: PSym): string =
proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var string;
renderFlags: TRenderFlags = {};
procLink: string) =
var r: TSrcGen = initTokRender(n, renderFlags)
var r: TSrcGen
var literal = ""
initTokRender(r, n, renderFlags)
var kind = tkEof
var tokenPos = 0
var procTokenPos = 0
@@ -608,9 +600,7 @@ proc runAllExamples(d: PDoc) =
rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string])
# removeFile(outp.changeFileExt(ExeExt)) # it's in nimcache, no need to remove
proc quoted(a: string): string =
result = ""
result.addQuoted(a)
proc quoted(a: string): string = result.addQuoted(a)
proc toInstantiationInfo(conf: ConfigRef, info: TLineInfo): (string, int, int) =
# xxx expose in compiler/lineinfos.nim
@@ -736,7 +726,7 @@ proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var ItemPre,
let (rdoccmd, code) = prepareExample(d, n, topLevel)
var msg = "Example:"
if rdoccmd.len > 0: msg.add " cmd: " & rdoccmd
var s: string = ""
var s: string
dispA(d.conf, s, "\n<p><strong class=\"examples_text\">$1</strong></p>\n",
"\n\n\\textbf{$1}\n", [msg])
dest.add s
@@ -831,7 +821,7 @@ proc getName(n: PNode): string =
result = "`"
for i in 0..<n.len: result.add(getName(n[i]))
result = "`"
of nkOpenSymChoice, nkClosedSymChoice:
of nkOpenSymChoice, nkClosedSymChoice, nkOpenSym:
result = getName(n[0])
else:
result = ""
@@ -849,7 +839,7 @@ proc getNameIdent(cache: IdentCache; n: PNode): PIdent =
var r = ""
for i in 0..<n.len: r.add(getNameIdent(cache, n[i]).s)
result = getIdent(cache, r)
of nkOpenSymChoice, nkClosedSymChoice:
of nkOpenSymChoice, nkClosedSymChoice, nkOpenSym:
result = getNameIdent(cache, n[0])
else:
result = nil
@@ -863,7 +853,7 @@ proc getRstName(n: PNode): PRstNode =
of nkAccQuoted:
result = getRstName(n[0])
for i in 1..<n.len: result.text.add(getRstName(n[i]).text)
of nkOpenSymChoice, nkClosedSymChoice:
of nkOpenSymChoice, nkClosedSymChoice, nkOpenSym:
result = getRstName(n[0])
else:
result = nil
@@ -952,17 +942,14 @@ proc genDeprecationMsg(d: PDoc, n: PNode): string =
if n[1].kind in {nkStrLit..nkTripleStrLit}:
result = getConfigVar(d.conf, "doc.deprecationmsg") % [
"label", "Deprecated:", "message", xmltree.escape(n[1].strVal)]
else:
result = ""
else:
raiseAssert "unreachable"
doAssert false
type DocFlags = enum
kDefault
kForceExport
proc genSeeSrc(d: PDoc, path: string, line: int): string =
result = ""
let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc")
if docItemSeeSrc.len > 0:
let path = relativeTo(AbsoluteFile path, AbsoluteDir getCurrentDir(), '/')
@@ -1004,7 +991,7 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
result.symKind = k.toHumanStr
if k in routineKinds:
var
paramTypes: seq[string] = @[]
paramTypes: seq[string]
renderParamTypes(paramTypes, n[paramsPos], toNormalize=true)
let paramNames = renderParamNames(n[paramsPos], toNormalize=true)
# In some rare cases (system.typeof) parameter type is not set for default:
@@ -1029,7 +1016,8 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
genNode = n[miscPos][1] # FIXME: what is index 1?
if genNode != nil:
var literal = ""
var r: TSrcGen = initTokRender(genNode, {renderNoBody, renderNoComments,
var r: TSrcGen
initTokRender(r, genNode, {renderNoBody, renderNoComments,
renderNoPragmas, renderNoProcDefs, renderExpandUsing})
var kind = tkEof
while true:
@@ -1050,14 +1038,15 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
var result = ""
var literal, plainName = ""
var kind = tkEof
var comm: ItemPre = default(ItemPre)
var comm: ItemPre
if n.kind in routineDefs:
getAllRunnableExamples(d, n, comm)
else:
comm.add genRecComment(d, n)
var r: TSrcGen
# Obtain the plain rendered string for hyperlink titles.
var r: TSrcGen = initTokRender(n, {renderNoBody, renderNoComments, renderDocComments,
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments,
renderNoPragmas, renderNoProcDefs, renderExpandUsing})
while true:
getNextTok(r, kind, literal)
@@ -1165,7 +1154,7 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false):
renderFlags = {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing}
if nonExports:
renderFlags.incl renderNonExportedFields
r = initTokRender(n, renderFlags)
initTokRender(r, n, renderFlags)
result.json = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
"col": %n.info.col}
if comm != nil:
@@ -1197,9 +1186,9 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false):
result.json["signature"]["genericParams"] = newJArray()
for genericParam in n[genericParamsPos]:
var param = %{"name": %($genericParam)}
if genericParam.sym.typ.len > 0:
if genericParam.sym.typ.sons.len > 0:
param["types"] = newJArray()
for kind in genericParam.sym.typ:
for kind in genericParam.sym.typ.sons:
param["types"].add %($kind)
result.json["signature"]["genericParams"].add param
if optGenIndex in d.conf.globalOptions:
@@ -1294,8 +1283,6 @@ proc documentNewEffect(cache: IdentCache; n: PNode): PNode =
let s = n[namePos].sym
if tfReturnsNew in s.typ.flags:
result = newIdentNode(getIdent(cache, "new"), n.info)
else:
result = nil
proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, idx: int): PNode =
let spec = effectSpec(x, effectType)
@@ -1318,8 +1305,6 @@ proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, id
result = newTreeI(nkExprColonExpr, n.info,
newIdentNode(getIdent(cache, $effectType), n.info), effects)
else:
result = nil
proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName: string): PNode =
let s = n[namePos].sym
@@ -1333,8 +1318,6 @@ proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName
if effects.len > 0:
result = newTreeI(nkExprColonExpr, n.info,
newIdentNode(getIdent(cache, pragmaName), n.info), effects)
else:
result = nil
proc documentRaises*(cache: IdentCache; n: PNode) =
if n[namePos].kind != nkSym: return
@@ -1408,7 +1391,7 @@ proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags
of nkExportExceptStmt: discard "transformed into nkExportStmt by semExportExcept"
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n[0])
of nkCallKinds:
var comm: ItemPre = default(ItemPre)
var comm: ItemPre
getAllRunnableExamples(d, n, comm)
if comm.len != 0: d.modDescPre.add(comm)
else: discard
@@ -1517,7 +1500,7 @@ proc finishGenerateDoc*(d: var PDoc) =
overloadChoices.sort(cmp)
var nameContent = ""
for item in overloadChoices:
var itemDesc: string = ""
var itemDesc: string
renderItemPre(d, item.descRst, itemDesc)
nameContent.add(
getConfigVar(d.conf, "doc.item") % (
@@ -1543,7 +1526,7 @@ proc finishGenerateDoc*(d: var PDoc) =
for i, entry in d.jEntriesPre:
if entry.rst != nil:
let resolved = resolveSubs(d.sharedState, entry.rst)
var str: string = ""
var str: string
renderRstToOut(d[], resolved, str)
entry.json[entry.rstField] = %str
d.jEntriesPre[i].rst = nil
@@ -1658,7 +1641,7 @@ proc genSection(d: PDoc, kind: TSymKind, groupedToc = false) =
for plainName in overloadableNames.sorted(cmpDecimalsIgnoreCase):
var overloadChoices = d.tocTable[kind][plainName]
overloadChoices.sort(cmp)
var content: string = ""
var content: string
for item in overloadChoices:
content.add item.content
d.toc2[kind].add getConfigVar(d.conf, "doc.section.toc2") % [
@@ -1689,7 +1672,7 @@ proc relLink(outDir: AbsoluteDir, destFile: AbsoluteFile, linkto: RelativeFile):
proc genOutFile(d: PDoc, groupedToc = false): string =
var
code, content: string = ""
code, content: string
title = ""
var j = 0
var toc = ""
@@ -1798,7 +1781,7 @@ proc writeOutput*(d: PDoc, useWarning = false, groupedToc = false) =
proc writeOutputJson*(d: PDoc, useWarning = false) =
runAllExamples(d)
var modDesc: string = ""
var modDesc: string
for desc in d.modDescFinal:
modDesc &= desc
let content = %*{"orig": d.filename,
@@ -1806,11 +1789,11 @@ proc writeOutputJson*(d: PDoc, useWarning = false) =
"moduleDescription": modDesc,
"entries": d.jEntriesFinal}
if optStdout in d.conf.globalOptions:
writeLine(stdout, $content)
write(stdout, $content)
else:
let dir = d.destFile.splitFile.dir
createDir(dir)
var f: File = default(File)
var f: File
if open(f, d.destFile, fmWrite):
write(f, $content)
close(f)

View File

@@ -39,12 +39,10 @@ template closeImpl(body: untyped) {.dirty.} =
discard
proc closeDoc*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
result = nil
closeImpl:
writeOutput(g.doc, useWarning, groupedToc)
proc closeJson*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
result = nil
closeImpl:
writeOutputJson(g.doc, useWarning)

View File

@@ -14,7 +14,7 @@ proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGener
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
res.typ = getSysType(g, info, tyString)
result.typ = newType(tyProc, idgen, t.owner)
result.typ = newType(tyProc, nextTypeId idgen, t.owner)
result.typ.n = newNodeI(nkFormalParams, info)
rawAddSon(result.typ, res.typ)
result.typ.n.add newNodeI(nkEffectList, info)
@@ -56,7 +56,6 @@ proc searchObjCaseImpl(obj: PNode; field: PSym): PNode =
if obj.kind == nkRecCase and obj[0].kind == nkSym and obj[0].sym == field:
result = obj
else:
result = nil
for x in obj:
result = searchObjCaseImpl(x, field)
if result != nil: break
@@ -76,7 +75,7 @@ proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGra
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
res.typ = getSysType(g, info, tyUInt8)
result.typ = newType(tyProc, idgen, t.owner)
result.typ = newType(tyProc, nextTypeId idgen, t.owner)
result.typ.n = newNodeI(nkFormalParams, info)
rawAddSon(result.typ, res.typ)
result.typ.n.add newNodeI(nkEffectList, info)

View File

@@ -10,8 +10,7 @@
## This module contains support code for new-styled error
## handling via an `nkError` node kind.
import ast, renderer, options, types
import std/strutils
import ast, renderer, options, strutils, types
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -41,8 +40,7 @@ proc newError*(wrongNode: PNode; k: ErrorKind; args: varargs[PNode]): PNode =
let innerError = errorSubNode(wrongNode)
if innerError != nil:
return innerError
var idgen = idGeneratorForPackage(-1'i32)
result = newNodeIT(nkError, wrongNode.info, newType(tyError, idgen, nil))
result = newNodeIT(nkError, wrongNode.info, newType(tyError, ItemId(module: -1, item: -1), nil))
result.add wrongNode
result.add newIntNode(nkIntLit, ord(k))
for a in args: result.add a
@@ -52,8 +50,7 @@ proc newError*(wrongNode: PNode; msg: string): PNode =
let innerError = errorSubNode(wrongNode)
if innerError != nil:
return innerError
var idgen = idGeneratorForPackage(-1'i32)
result = newNodeIT(nkError, wrongNode.info, newType(tyError, idgen, nil))
result = newNodeIT(nkError, wrongNode.info, newType(tyError, ItemId(module: -1, item: -1), nil))
result.add wrongNode
result.add newIntNode(nkIntLit, ord(CustomError))
result.add newStrNode(msg, wrongNode.info)

View File

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

View File

@@ -9,8 +9,8 @@
## Template evaluation engine. Now hygienic.
import options, ast, astalgo, msgs, renderer, lineinfos, idents, trees
import std/strutils
import
strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents, trees
type
TemplCtx = object
@@ -56,6 +56,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
# internalAssert c.config, false
idTablePut(c.mapping, s, x)
if sfGenSym in s.flags:
# TODO: getIdent(c.ic, "`" & x.name.s & "`gensym" & $c.instID)
result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $c.instID),
if c.instLines: actual.info else: templ.info)
else:
@@ -187,7 +188,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
ctx.genSymOwner = genSymOwner
ctx.config = conf
ctx.ic = ic
ctx.mapping = initIdTable()
initIdTable(ctx.mapping)
ctx.instID = instID[]
ctx.idgen = idgen

View File

@@ -1,131 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
import lineinfos, ast, types
proc caseObjDefaultBranch*(obj: PNode; branch: Int128): int =
result = 0
for i in 1 ..< obj.len:
for j in 0 .. obj[i].len - 2:
if obj[i][j].kind == nkRange:
let x = getOrdValue(obj[i][j][0])
let y = getOrdValue(obj[i][j][1])
if branch >= x and branch <= y:
return i
elif getOrdValue(obj[i][j]) == branch:
return i
if obj[i].len == 1:
# else branch
return i
return 1
template newZero(t: PType; info: TLineInfo; k = nkIntLit): PNode = newNodeIT(k, info, t)
proc expandDefault*(t: PType; info: TLineInfo): PNode
proc expandField(s: PSym; info: TLineInfo): PNode =
result = newNodeIT(nkExprColonExpr, info, s.typ)
result.add newSymNode(s)
result.add expandDefault(s.typ, info)
proc expandDefaultN(n: PNode; info: TLineInfo; res: PNode) =
case n.kind
of nkRecList:
for i in 0..<n.len:
expandDefaultN(n[i], info, res)
of nkRecCase:
res.add expandField(n[0].sym, info)
var branch = Zero
let constOrNil = n[0].sym.astdef
if constOrNil != nil:
branch = getOrdValue(constOrNil)
let selectedBranch = caseObjDefaultBranch(n, branch)
let b = lastSon(n[selectedBranch])
expandDefaultN b, info, res
of nkSym:
res.add expandField(n.sym, info)
else:
discard
proc expandDefaultObj(t: PType; info: TLineInfo; res: PNode) =
if t[0] != nil:
expandDefaultObj(t[0], info, res)
expandDefaultN(t.n, info, res)
proc expandDefault(t: PType; info: TLineInfo): PNode =
case t.kind
of tyInt: result = newZero(t, info, nkIntLit)
of tyInt8: result = newZero(t, info, nkInt8Lit)
of tyInt16: result = newZero(t, info, nkInt16Lit)
of tyInt32: result = newZero(t, info, nkInt32Lit)
of tyInt64: result = newZero(t, info, nkInt64Lit)
of tyUInt: result = newZero(t, info, nkUIntLit)
of tyUInt8: result = newZero(t, info, nkUInt8Lit)
of tyUInt16: result = newZero(t, info, nkUInt16Lit)
of tyUInt32: result = newZero(t, info, nkUInt32Lit)
of tyUInt64: result = newZero(t, info, nkUInt64Lit)
of tyFloat: result = newZero(t, info, nkFloatLit)
of tyFloat32: result = newZero(t, info, nkFloat32Lit)
of tyFloat64: result = newZero(t, info, nkFloat64Lit)
of tyFloat128: result = newZero(t, info, nkFloat64Lit)
of tyChar: result = newZero(t, info, nkCharLit)
of tyBool: result = newZero(t, info, nkIntLit)
of tyEnum:
# Could use low(T) here to finally fix old language quirks
result = newZero(t, info, nkIntLit)
of tyRange:
# Could use low(T) here to finally fix old language quirks
result = expandDefault(t[0], info)
of tyVoid: result = newZero(t, info, nkEmpty)
of tySink, tyGenericInst, tyDistinct, tyAlias, tyOwned:
result = expandDefault(t.lastSon, info)
of tyOrdinal, tyGenericBody, tyGenericParam, tyInferred, tyStatic:
if t.len > 0:
result = expandDefault(t.lastSon, info)
else:
result = newZero(t, info, nkEmpty)
of tyFromExpr:
if t.n != nil and t.n.typ != nil:
result = expandDefault(t.n.typ, info)
else:
result = newZero(t, info, nkEmpty)
of tyArray:
result = newZero(t, info, nkBracket)
let n = toInt64(lengthOrd(nil, t))
for i in 0..<n:
result.add expandDefault(t[1], info)
of tyPtr, tyRef, tyProc, tyPointer, tyCstring:
result = newZero(t, info, nkNilLit)
of tyVar, tyLent:
let e = t.lastSon
if e.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
# skip the modifier, `var openArray` is a (ptr, len) pair too:
result = expandDefault(e, info)
else:
result = newZero(t.lastSon, info, nkNilLit)
of tySet:
result = newZero(t, info, nkCurly)
of tyObject:
result = newNodeIT(nkObjConstr, info, t)
result.add newNodeIT(nkType, info, t)
expandDefaultObj(t, info, result)
of tyTuple:
result = newZero(t, info, nkTupleConstr)
for it in t:
result.add expandDefault(it, info)
of tyVarargs, tyOpenArray, tySequence, tyUncheckedArray:
result = newZero(t, info, nkBracket)
of tyString:
result = newZero(t, info, nkStrLit)
of tyNone, tyEmpty, tyUntyped, tyTyped, tyTypeDesc,
tyNil, tyGenericInvocation, tyProxy, tyBuiltInTypeClass,
tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass,
tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward:
result = newZero(t, info, nkEmpty) # bug indicator

View File

@@ -19,7 +19,7 @@ import std/[os, osproc, streams, sequtils, times, strtabs, json, jsonutils, suga
import std / strutils except addf
when defined(nimPreviewSlimSystem):
import std/syncio
import std/[syncio, assertions]
import ../dist/checksums/src/checksums/sha1
@@ -319,7 +319,7 @@ proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
var fullSuffix = suffix
case conf.backend
of backendCpp, backendJs, backendObjc: fullSuffix = "." & $conf.backend & suffix
of backendC, backendNir: discard
of backendC: discard
of backendInvalid:
# during parsing of cfg files; we don't know the backend yet, no point in
# guessing wrong thing
@@ -452,6 +452,11 @@ proc noAbsolutePaths(conf: ConfigRef): bool {.inline.} =
proc cFileSpecificOptions(conf: ConfigRef; nimname, fullNimFile: string): string =
result = conf.compileOptions
if (conf.cCompiler == ccGcc or conf.cCompiler == ccCLang) and
conf.selectedGC == gcRefc:
# bug #10625
addOpt(result, "-fno-omit-frame-pointer")
for option in conf.compileOptionsCmd:
if strutils.find(result, option, 0) < 0:
addOpt(result, option)
@@ -487,10 +492,6 @@ proc vccplatform(conf: ConfigRef): string =
of cpuArm: " --platform:arm"
of cpuAmd64: " --platform:amd64"
else: ""
else:
result = ""
else:
result = ""
proc getLinkOptions(conf: ConfigRef): string =
result = conf.linkOptions & " " & conf.linkOptionsCmd & " "
@@ -539,7 +540,7 @@ proc ccHasSaneOverflow*(conf: ConfigRef): bool =
# NOTE: should we need the full version, use -dumpfullversion
let (s, exitCode) = try: execCmdEx(exe & " -dumpversion") except IOError, OSError, ValueError: ("", 1)
if exitCode == 0:
var major: int = 0
var major: int
discard parseInt(s, major)
result = major >= 5
else:
@@ -649,7 +650,7 @@ proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
let hashFile = toGeneratedFile(conf, conf.mangleModuleName(cfile.cname).AbsoluteFile, "sha1")
let currentHash = footprint(conf, cfile)
var f: File = default(File)
var f: File
if open(f, hashFile.string, fmRead):
let oldHash = parseSecureHash(f.readLine())
close(f)
@@ -784,7 +785,6 @@ template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body
raise
proc getExtraCmds(conf: ConfigRef; output: AbsoluteFile): seq[string] =
result = @[]
when defined(macosx):
if optCDebug in conf.globalOptions and optGenStaticLib notin conf.globalOptions:
# if needed, add an option to skip or override location
@@ -867,7 +867,6 @@ proc hcrLinkTargetName(conf: ConfigRef, objFile: string, isMain = false): Absolu
result = conf.getNimcacheDir / RelativeFile(targetName)
proc displayProgressCC(conf: ConfigRef, path, compileCmd: string): string =
result = ""
if conf.hasHint(hintCC):
if optListCmd in conf.globalOptions or conf.verbosity > 1:
result = MsgKindToStr[hintCC] % (demangleModuleName(path.splitFile.name) & ": " & compileCmd)
@@ -890,15 +889,15 @@ proc preventLinkCmdMaxCmdLen(conf: ConfigRef, linkCmd: string) =
proc callCCompiler*(conf: ConfigRef) =
var
linkCmd: string = ""
linkCmd: string
extraCmds: seq[string]
if conf.globalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
return # speed up that call if only compiling and no script shall be
# generated
#var c = cCompiler
var script: Rope = ""
var cmds: TStringSeq = default(TStringSeq)
var prettyCmds: TStringSeq = default(TStringSeq)
var cmds: TStringSeq
var prettyCmds: TStringSeq
let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx])
for idx, it in conf.toCompile:
@@ -999,7 +998,7 @@ type BuildCache = object
depfiles: seq[(string, string)]
nimexe: string
proc writeJsonBuildInstructions*(conf: ConfigRef) =
proc writeJsonBuildInstructions*(conf: ConfigRef; deps: StringTableRef) =
var linkFiles = collect(for it in conf.externalToLink:
var it = it
if conf.noAbsolutePaths: it = it.extractFilename
@@ -1020,18 +1019,21 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) =
currentDir: getCurrentDir())
if optRun in conf.globalOptions or isDefined(conf, "nimBetterRun"):
bcache.cmdline = conf.commandLine
bcache.depfiles = collect(for it in conf.m.fileInfos:
for it in conf.m.fileInfos:
let path = it.fullPath.string
if isAbsolute(path): # TODO: else?
(path, $secureHashFile(path)))
if path in deps:
bcache.depfiles.add (path, deps[path])
else: # backup for configs etc.
bcache.depfiles.add (path, $secureHashFile(path))
bcache.nimexe = hashNimExe()
conf.jsonBuildFile = conf.jsonBuildInstructionsFile
conf.jsonBuildFile.string.writeFile(bcache.toJson.pretty)
proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile): bool =
result = false
if not fileExists(jsonFile) or not fileExists(conf.absOutFile): return true
var bcache: BuildCache = default(BuildCache)
var bcache: BuildCache
try: bcache.fromJson(jsonFile.string.parseFile)
except IOError, OSError, ValueError:
stderr.write "Warning: JSON processing failed for: $#\n" % jsonFile.string
@@ -1047,7 +1049,7 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: Absolute
if $secureHashFile(file) != hash: return true
proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
var bcache: BuildCache = default(BuildCache)
var bcache: BuildCache
try: bcache.fromJson(jsonFile.string.parseFile)
except ValueError, KeyError, JsonKindError:
let e = getCurrentException()
@@ -1060,8 +1062,7 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
globalError(conf, gCmdLineInfo,
"jsonscript command outputFile '$1' must match '$2' which was specified during --compileOnly, see \"outputFile\" entry in '$3' " %
[outputCurrent, output, jsonFile.string])
var cmds: TStringSeq = default(TStringSeq)
var prettyCmds: TStringSeq= default(TStringSeq)
var cmds, prettyCmds: TStringSeq
let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx])
for (name, cmd) in bcache.compile:
cmds.add cmd
@@ -1071,7 +1072,6 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
for cmd in bcache.extraCmds: execExternalProgram(conf, cmd, hintExecuting)
proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope =
result = ""
for it in list:
result.addf("--file:r\"$1\"$N", [rope(it.cname.string)])

View File

@@ -10,11 +10,9 @@
# This module implements Nim's standard template filter.
import
llstream, ast, msgs, options,
llstream, strutils, ast, msgs, options,
filters, lineinfos, pathutils
import std/strutils
type
TParseState = enum
psDirective, psTempl
@@ -203,15 +201,17 @@ proc parseLine(p: var TTmplParser) =
proc filterTmpl*(conf: ConfigRef, stdin: PLLStream, filename: AbsoluteFile,
call: PNode): PLLStream =
var p = TTmplParser(config: conf, info: newLineInfo(conf, filename, 0, 0),
outp: llStreamOpen(""), inp: stdin,
subsChar: charArg(conf, call, "subschar", 1, '$'),
nimDirective: charArg(conf, call, "metachar", 2, '#'),
emit: strArg(conf, call, "emit", 3, "result.add"),
conc: strArg(conf, call, "conc", 4, " & "),
toStr: strArg(conf, call, "tostring", 5, "$"),
x: newStringOfCap(120)
)
var p: TTmplParser
p.config = conf
p.info = newLineInfo(conf, filename, 0, 0)
p.outp = llStreamOpen("")
p.inp = stdin
p.subsChar = charArg(conf, call, "subschar", 1, '$')
p.nimDirective = charArg(conf, call, "metachar", 2, '#')
p.emit = strArg(conf, call, "emit", 3, "result.add")
p.conc = strArg(conf, call, "conc", 4, " & ")
p.toStr = strArg(conf, call, "tostring", 5, "$")
p.x = newStringOfCap(120)
# do not process the first line which contains the directive:
if llStreamReadLine(p.inp, p.x):
inc p.info.line

View File

@@ -10,11 +10,9 @@
# This module implements Nim's simple filters and helpers for filters.
import
llstream, idents, ast, msgs, options,
llstream, idents, strutils, ast, msgs, options,
renderer, pathutils
import std/strutils
proc invalidPragma(conf: ConfigRef; n: PNode) =
localError(conf, n.info,
"'$1' not allowed here" % renderTree(n, {renderNoComments}))
@@ -31,30 +29,23 @@ proc getArg(conf: ConfigRef; n: PNode, name: string, pos: int): PNode =
return n[i]
proc charArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: char): char =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind == nkCharLit: result = chr(int(x.intVal))
else:
result = default(char)
invalidPragma(conf, n)
else: invalidPragma(conf, n)
proc strArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: string): string =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind in {nkStrLit..nkTripleStrLit}: result = x.strVal
else:
result = ""
invalidPragma(conf, n)
else: invalidPragma(conf, n)
proc boolArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: bool): bool =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "true") == 0: result = true
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "false") == 0: result = false
else:
result = false
invalidPragma(conf, n)
else: invalidPragma(conf, n)
proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: AbsoluteFile, call: PNode): PLLStream =
var pattern = strArg(conf, call, "startswith", 1, "")

View File

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

View File

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

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

View File

@@ -1,8 +1,7 @@
## A BiTable is a table that can be seen as an optimized pair
## of `(Table[LitId, Val], Table[Val, LitId])`.
import std/hashes
import rodfiles
import hashes, rodfiles
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -14,8 +13,6 @@ type
vals: seq[T] # indexed by LitId
keys: seq[LitId] # indexed by hash(val)
proc initBiTable*[T](): BiTable[T] = BiTable[T](vals: @[], keys: @[])
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = (h + 1) and maxHash
@@ -36,7 +33,9 @@ proc mustRehash(length, counter: int): bool {.inline.} =
result = (length * 2 < counter * 3) or (length - counter < 4)
const
idStart = 1
idStart = 256 ##
## Ids do not start with 0 but with this value. The IR needs it.
## TODO: explain why
template idToIdx(x: LitId): int = x.int - idStart
@@ -119,12 +118,6 @@ proc load*[T](f: var RodFile; t: var BiTable[T]) =
loadSeq(f, t.vals)
loadSeq(f, t.keys)
proc sizeOnDisc*(t: BiTable[string]): int =
result = 4
for x in t.vals:
result += x.len + 4
result += t.keys.len * sizeof(LitId)
when isMainModule:
var t: BiTable[string]

View File

@@ -18,7 +18,7 @@
## also doing cross-module dependency tracking and DCE that we don't need
## anymore. DCE is now done as prepass over the entire packed module graph.
import std/[packedsets, algorithm, tables]
import std/packedsets, algorithm, tables
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -50,9 +50,10 @@ proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var Alive
let n = unpackTree(g, m.module.position, m.fromDisk.topLevel, p)
cgen.genTopLevelStmt(bmod, n)
finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
for disp in getDispatchers(g):
genProcAux(bmod, disp)
let disps = finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
if disps != nil:
for disp in disps:
genProcAux(bmod, disp.sym)
m.fromDisk.backendFlags = cgen.whichInitProcs(bmod)
proc replayTypeInfo(g: ModuleGraph; m: var LoadedModule; origin: FileIndex) =
@@ -100,7 +101,7 @@ proc aliveSymsChanged(config: ConfigRef; position: int; alive: AliveSyms): bool
var f2 = rodfiles.open(asymFile.string)
f2.loadHeader()
f2.loadSection aliveSymsSection
var oldData: seq[int32] = @[]
var oldData: seq[int32]
f2.loadSeq(oldData)
f2.close
if f2.err == ok and oldData == s:
@@ -146,12 +147,12 @@ proc generateCode*(g: ModuleGraph) =
var alive = computeAliveSyms(g.packed, g.config)
when false:
for i in 0..<len(g.packed):
for i in 0..high(g.packed):
echo i, " is of status ", g.packed[i].status, " ", toFullPath(g.config, FileIndex(i))
# First pass: Setup all the backend modules for all the modules that have
# changed:
for i in 0..<len(g.packed):
for i in 0..high(g.packed):
# case statement here to enforce exhaustive checks.
case g.packed[i].status
of undefined:
@@ -173,7 +174,7 @@ proc generateCode*(g: ModuleGraph) =
let mainModuleIdx = g.config.projectMainIdx2.int
# We need to generate the main module last, because only then
# all init procs have been registered:
for i in 0..<len(g.packed):
for i in 0..high(g.packed):
if i != mainModuleIdx:
genPackedModule(g, i, alive)
if mainModuleIdx >= 0:

View File

@@ -40,14 +40,10 @@ proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): boo
if ({sfExportc, sfCompilerProc} * flags != {}) or
(symPtr.kind == skMethod):
result = true
else:
result = false
# XXX: This used to be a condition to:
# (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
if sfCompilerProc in flags:
c.compilerProcs[g[c.thisModule].fromDisk.strings[symPtr.name]] = (c.thisModule, symId)
else:
result = false
template isNotGeneric(n: NodePos): bool = ithSon(tree, n, genericParamsPos).kind == nkEmpty
@@ -109,13 +105,13 @@ proc aliveCode(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: N
discard "ignore non-sym atoms"
of nkSym:
# This symbol is alive and everything its body references.
followLater(c, g, c.thisModule, tree[n].soperand)
followLater(c, g, c.thisModule, n.operand)
of nkModuleRef:
let (n1, n2) = sons2(tree, n)
assert n1.kind == nkNone
assert n2.kind == nkNone
assert n1.kind == nkInt32Lit
assert n2.kind == nkInt32Lit
let m = n1.litId
let item = tree[n2].soperand
let item = n2.operand
let otherModule = toFileIndexCached(c.decoder, g, c.thisModule, m).int
followLater(c, g, otherModule, item)
of nkMacroDef, nkTemplateDef, nkTypeSection, nkTypeOfExpr,
@@ -131,7 +127,7 @@ proc aliveCode(c: var AliveContext; g: PackedModuleGraph; tree: PackedTree; n: N
rangeCheckAnalysis(c, g, tree, n)
of nkProcDef, nkConverterDef, nkMethodDef, nkFuncDef, nkIteratorDef:
if n.firstSon.kind == nkSym and isNotGeneric(n):
let item = tree[n.firstSon].soperand
let item = n.firstSon.operand
if isExportedToC(c, g, item):
# This symbol is alive and everything its body references.
followLater(c, g, c.thisModule, item)
@@ -153,7 +149,7 @@ proc computeAliveSyms*(g: PackedModuleGraph; conf: ConfigRef): AliveSyms =
var c = AliveContext(stack: @[], decoder: PackedDecoder(config: conf),
thisModule: -1, alive: newSeq[IntSet](g.len),
options: conf.options)
for i in countdown(len(g)-1, 0):
for i in countdown(high(g), 0):
if g[i].status != undefined:
c.thisModule = i
for p in allNodes(g[i].fromDisk.topLevel):

View File

@@ -7,17 +7,15 @@
# distribution, for details about the copyright.
#
import std/[hashes, tables, intsets, monotimes]
import hashes, tables, intsets
import packed_ast, bitabs, rodfiles
import ".." / [ast, idents, lineinfos, msgs, ropes, options,
pathutils, condsyms, packages, modulepaths]
#import ".." / [renderer, astalgo]
from std/os import removeFile, isAbsolute
from os import removeFile, isAbsolute
import ../../dist/checksums/src/checksums/sha1
import ".." / nir / nirlineinfos
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions, formatfloat]
@@ -43,18 +41,16 @@ type
bodies*: PackedTree # other trees. Referenced from typ.n and sym.ast by their position.
#producedGenerics*: Table[GenericKey, SymId]
exports*: seq[(LitId, int32)]
hidden: seq[(LitId, int32)]
reexports: seq[(LitId, PackedItemId)]
hidden*: seq[(LitId, int32)]
reexports*: seq[(LitId, PackedItemId)]
compilerProcs*: seq[(LitId, int32)]
converters*, methods*, trmacros*, pureEnums*: seq[int32]
typeInstCache*: seq[(PackedItemId, PackedItemId)]
procInstCache*: seq[PackedInstantiation]
attachedOps*: seq[(PackedItemId, TTypeAttachedOp, PackedItemId)]
methodsPerGenericType*: seq[(PackedItemId, int, PackedItemId)]
methodsPerType*: seq[(PackedItemId, int, PackedItemId)]
enumToStringProcs*: seq[(PackedItemId, PackedItemId)]
methodsPerType*: seq[(PackedItemId, PackedItemId)]
dispatchers*: seq[PackedItemId]
emittedTypeInfo*: seq[string]
backendFlags*: set[ModuleBackendFlag]
@@ -64,7 +60,6 @@ type
strings*: BiTable[string] # we could share these between modules.
numbers*: BiTable[BiggestInt] # we also store floats in here so
# that we can assure that every bit is kept
man*: LineInfoManager
cfg: PackedConfig
@@ -80,36 +75,37 @@ type
symMarker*: IntSet #Table[ItemId, SymId] # ItemId.item -> SymId
config*: ConfigRef
proc toString*(tree: PackedTree; pos: NodePos; m: PackedModule; nesting: int;
proc toString*(tree: PackedTree; n: NodePos; m: PackedModule; nesting: int;
result: var string) =
let pos = n.int
if result.len > 0 and result[^1] notin {' ', '\n'}:
result.add ' '
result.add $tree[pos].kind
case tree[pos].kind
of nkEmpty, nkNilLit, nkType: discard
case tree.nodes[pos].kind
of nkNone, nkEmpty, nkNilLit, nkType: discard
of nkIdent, nkStrLit..nkTripleStrLit:
result.add " "
result.add m.strings[LitId tree[pos].uoperand]
result.add m.strings[LitId tree.nodes[pos].operand]
of nkSym:
result.add " "
result.add m.strings[m.syms[tree[pos].soperand].name]
result.add m.strings[m.syms[tree.nodes[pos].operand].name]
of directIntLit:
result.add " "
result.addInt tree[pos].soperand
result.addInt tree.nodes[pos].operand
of externSIntLit:
result.add " "
result.addInt m.numbers[LitId tree[pos].uoperand]
result.addInt m.numbers[LitId tree.nodes[pos].operand]
of externUIntLit:
result.add " "
result.addInt cast[uint64](m.numbers[LitId tree[pos].uoperand])
result.addInt cast[uint64](m.numbers[LitId tree.nodes[pos].operand])
of nkFloatLit..nkFloat128Lit:
result.add " "
result.addFloat cast[BiggestFloat](m.numbers[LitId tree[pos].uoperand])
result.addFloat cast[BiggestFloat](m.numbers[LitId tree.nodes[pos].operand])
else:
result.add "(\n"
for i in 1..(nesting+1)*2: result.add ' '
for child in sonsReadonly(tree, pos):
for child in sonsReadonly(tree, n):
toString(tree, child, m, nesting + 1, result)
result.add "\n"
for i in 1..nesting*2: result.add ' '
@@ -235,14 +231,10 @@ proc addImportFileDep*(c: var PackedEncoder; m: var PackedModule; f: FileIndex)
m.imports.add toLitId(f, c, m)
proc addHidden*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
assert s.kind != skUnknown
let nameId = getOrIncl(m.strings, s.name.s)
m.hidden.add((nameId, s.itemId.item))
assert s.itemId.module == c.thisModule
proc addExported*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
assert s.kind != skUnknown
assert s.itemId.module == c.thisModule
let nameId = getOrIncl(m.strings, s.name.s)
m.exports.add((nameId, s.itemId.item))
@@ -261,8 +253,6 @@ proc addMethod*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
m.methods.add s.itemId.item
proc addReexport*(c: var PackedEncoder; m: var PackedModule; s: PSym) =
assert s.kind != skUnknown
if s.kind == skModule: return
let nameId = getOrIncl(m.strings, s.name.s)
m.reexports.add((nameId, PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m),
item: s.itemId.item)))
@@ -294,8 +284,7 @@ proc toLitId(x: BiggestInt; m: var PackedModule): LitId =
result = getOrIncl(m.numbers, x)
proc toPackedInfo(x: TLineInfo; c: var PackedEncoder; m: var PackedModule): PackedLineInfo =
pack(m.man, toLitId(x.fileIndex, c, m), x.line.int32, x.col.int32)
#PackedLineInfo(line: x.line, col: x.col, file: toLitId(x.fileIndex, c, m))
PackedLineInfo(line: x.line, col: x.col, file: toLitId(x.fileIndex, c, m))
proc safeItemId(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId {.inline.} =
## given a symbol, produce an ItemId with the correct properties
@@ -347,7 +336,7 @@ proc storeTypeLater(t: PType; c: var PackedEncoder; m: var PackedModule): Packed
proc storeSymLater(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId =
if s.isNil: return nilItemId
assert s.itemId.module >= 0
assert s.itemId.item >= 0
assert s.itemId.module >= 0
result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item)
if s.itemId.module == c.thisModule:
# the sym belongs to this module, so serialize it here, eventually.
@@ -370,7 +359,7 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI
paddingAtEnd: t.paddingAtEnd)
storeNode(p, t, n)
p.typeInst = t.typeInst.storeType(c, m)
for kid in items t:
for kid in items t.sons:
p.types.add kid.storeType(c, m)
c.addMissing t.sym
p.sym = t.sym.safeItemId(c, m)
@@ -424,7 +413,6 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
p.annex = toPackedLib(s.annex, c, m)
when hasFFI:
p.cname = toLitId(s.cname, m)
p.instantiatedFrom = s.instantiatedFrom.safeItemId(c, m)
# fill the reserved slot, nothing else:
m.syms[s.itemId.item] = p
@@ -432,59 +420,53 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
proc addModuleRef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) =
## add a remote symbol reference to the tree
let info = n.info.toPackedInfo(c, m)
if n.typ != n.sym.typ:
ir.addNode(kind = nkModuleRef, operand = 3.int32, # spans 3 nodes in total
info = info,
typeId = storeTypeLater(n.typ, c, m))
else:
ir.addNode(kind = nkModuleRef, operand = 3.int32, # spans 3 nodes in total
info = info)
ir.addNode(kind = nkNone, info = info,
operand = toLitId(n.sym.itemId.module.FileIndex, c, m).int32)
ir.addNode(kind = nkNone, info = info,
operand = n.sym.itemId.item)
ir.nodes.add PackedNode(kind: nkModuleRef, operand: 3.int32, # spans 3 nodes in total
typeId: storeTypeLater(n.typ, c, m), info: info, flags: n.flags)
ir.nodes.add PackedNode(kind: nkInt32Lit, info: info,
operand: toLitId(n.sym.itemId.module.FileIndex, c, m).int32)
ir.nodes.add PackedNode(kind: nkInt32Lit, info: info,
operand: n.sym.itemId.item)
proc toPackedNode*(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var PackedModule) =
## serialize a node into the tree
if n == nil:
ir.addNode(kind = nkNilRodNode, operand = 1, info = NoLineInfo)
ir.nodes.add PackedNode(kind: nkNilRodNode, flags: {}, operand: 1)
return
let info = toPackedInfo(n.info, c, m)
case n.kind
of nkNone, nkEmpty, nkNilLit, nkType:
ir.addNode(kind = n.kind, flags = n.flags, operand = 0,
typeId = storeTypeLater(n.typ, c, m), info = info)
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags, operand: 0,
typeId: storeTypeLater(n.typ, c, m), info: info)
of nkIdent:
ir.addNode(kind = n.kind, flags = n.flags,
operand = int32 getOrIncl(m.strings, n.ident.s),
typeId = storeTypeLater(n.typ, c, m), info = info)
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
operand: int32 getOrIncl(m.strings, n.ident.s),
typeId: storeTypeLater(n.typ, c, m), info: info)
of nkSym:
if n.sym.itemId.module == c.thisModule:
# it is a symbol that belongs to the module we're currently
# packing:
let id = n.sym.storeSymLater(c, m).item
if n.typ != n.sym.typ:
ir.addNode(kind = nkSym, flags = n.flags, operand = id,
info = info,
typeId = storeTypeLater(n.typ, c, m))
else:
ir.addNode(kind = nkSym, flags = n.flags, operand = id,
info = info)
ir.nodes.add PackedNode(kind: nkSym, flags: n.flags, operand: id,
typeId: storeTypeLater(n.typ, c, m), info: info)
else:
# store it as an external module reference:
addModuleRef(n, ir, c, m)
of directIntLit:
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
operand: int32(n.intVal),
typeId: storeTypeLater(n.typ, c, m), info: info)
of externIntLit:
ir.addNode(kind = n.kind, flags = n.flags,
operand = int32 getOrIncl(m.numbers, n.intVal),
typeId = storeTypeLater(n.typ, c, m), info = info)
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
operand: int32 getOrIncl(m.numbers, n.intVal),
typeId: storeTypeLater(n.typ, c, m), info: info)
of nkStrLit..nkTripleStrLit:
ir.addNode(kind = n.kind, flags = n.flags,
operand = int32 getOrIncl(m.strings, n.strVal),
typeId = storeTypeLater(n.typ, c, m), info = info)
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
operand: int32 getOrIncl(m.strings, n.strVal),
typeId: storeTypeLater(n.typ, c, m), info: info)
of nkFloatLit..nkFloat128Lit:
ir.addNode(kind = n.kind, flags = n.flags,
operand = int32 getOrIncl(m.numbers, cast[BiggestInt](n.floatVal)),
typeId = storeTypeLater(n.typ, c, m), info = info)
ir.nodes.add PackedNode(kind: n.kind, flags: n.flags,
operand: int32 getOrIncl(m.numbers, cast[BiggestInt](n.floatVal)),
typeId: storeTypeLater(n.typ, c, m), info: info)
else:
let patchPos = ir.prepare(n.kind, n.flags,
storeTypeLater(n.typ, c, m), info)
@@ -509,8 +491,8 @@ proc toPackedProcDef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var
# do not serialize the body of the proc, it's unnecessary since
# n[0].sym.ast has the sem'checked variant of it which is what
# everybody should use instead.
ir.addNode(kind = nkEmpty, flags = {}, operand = 0,
typeId = nilItemId, info = info)
ir.nodes.add PackedNode(kind: nkEmpty, flags: {}, operand: 0,
typeId: nilItemId, info: info)
ir.patch patchPos
proc toPackedNodeIgnoreProcDefs(n: PNode, encoder: var PackedEncoder; m: var PackedModule) =
@@ -583,20 +565,6 @@ proc toRodFile*(conf: ConfigRef; f: AbsoluteFile; ext = RodExt): AbsoluteFile =
result = changeFileExt(completeGeneratedFilePath(conf,
mangleModuleName(conf, f).AbsoluteFile), ext)
const
BenchIC* = false
when BenchIC:
var gloadBodies: MonoTime
template bench(x, body) =
let start = getMonoTime()
body
x = x + (getMonoTime() - start)
else:
template bench(x, body) = body
proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef;
ignoreConfig = false): RodFileError =
var f = rodfiles.open(filename.string)
@@ -621,48 +589,40 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef
loadTabSection stringsSection, m.strings
loadSeqSection checkSumsSection, m.includes
if config.cmd != cmdM and not includesIdentical(m, config):
if not includesIdentical(m, config):
f.err = includeFileChanged
loadSeqSection depsSection, m.imports
bench gloadBodies:
loadTabSection numbersSection, m.numbers
loadTabSection numbersSection, m.numbers
loadSeqSection exportsSection, m.exports
loadSeqSection hiddenSection, m.hidden
loadSeqSection reexportsSection, m.reexports
loadSeqSection exportsSection, m.exports
loadSeqSection hiddenSection, m.hidden
loadSeqSection reexportsSection, m.reexports
loadSeqSection compilerProcsSection, m.compilerProcs
loadSeqSection compilerProcsSection, m.compilerProcs
loadSeqSection trmacrosSection, m.trmacros
loadSeqSection trmacrosSection, m.trmacros
loadSeqSection convertersSection, m.converters
loadSeqSection methodsSection, m.methods
loadSeqSection pureEnumsSection, m.pureEnums
loadSeqSection convertersSection, m.converters
loadSeqSection methodsSection, m.methods
loadSeqSection pureEnumsSection, m.pureEnums
loadSeqSection toReplaySection, m.toReplay.nodes
loadSeqSection topLevelSection, m.topLevel.nodes
loadSeqSection bodiesSection, m.bodies.nodes
loadSeqSection symsSection, m.syms
loadSeqSection typesSection, m.types
loadTabSection toReplaySection, m.toReplay
loadTabSection topLevelSection, m.topLevel
loadSeqSection typeInstCacheSection, m.typeInstCache
loadSeqSection procInstCacheSection, m.procInstCache
loadSeqSection attachedOpsSection, m.attachedOps
loadSeqSection methodsPerTypeSection, m.methodsPerType
loadSeqSection enumToStringProcsSection, m.enumToStringProcs
loadSeqSection typeInfoSection, m.emittedTypeInfo
loadTabSection bodiesSection, m.bodies
loadSeqSection symsSection, m.syms
loadSeqSection typesSection, m.types
loadSeqSection typeInstCacheSection, m.typeInstCache
loadSeqSection procInstCacheSection, m.procInstCache
loadSeqSection attachedOpsSection, m.attachedOps
loadSeqSection methodsPerGenericTypeSection, m.methodsPerGenericType
loadSeqSection enumToStringProcsSection, m.enumToStringProcs
loadSeqSection methodsPerTypeSection, m.methodsPerType
loadSeqSection dispatchersSection, m.dispatchers
loadSeqSection typeInfoSection, m.emittedTypeInfo
f.loadSection backendFlagsSection
f.loadPrim m.backendFlags
f.loadSection sideChannelSection
f.load m.man
f.loadSection backendFlagsSection
f.loadPrim m.backendFlags
close(f)
result = f.err
@@ -711,10 +671,10 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac
storeSeqSection methodsSection, m.methods
storeSeqSection pureEnumsSection, m.pureEnums
storeTabSection toReplaySection, m.toReplay
storeTabSection topLevelSection, m.topLevel
storeSeqSection toReplaySection, m.toReplay.nodes
storeSeqSection topLevelSection, m.topLevel.nodes
storeTabSection bodiesSection, m.bodies
storeSeqSection bodiesSection, m.bodies.nodes
storeSeqSection symsSection, m.syms
storeSeqSection typesSection, m.types
@@ -722,18 +682,13 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac
storeSeqSection typeInstCacheSection, m.typeInstCache
storeSeqSection procInstCacheSection, m.procInstCache
storeSeqSection attachedOpsSection, m.attachedOps
storeSeqSection methodsPerGenericTypeSection, m.methodsPerGenericType
storeSeqSection enumToStringProcsSection, m.enumToStringProcs
storeSeqSection methodsPerTypeSection, m.methodsPerType
storeSeqSection dispatchersSection, m.dispatchers
storeSeqSection enumToStringProcsSection, m.enumToStringProcs
storeSeqSection typeInfoSection, m.emittedTypeInfo
f.storeSection backendFlagsSection
f.storePrim m.backendFlags
f.storeSection sideChannelSection
f.store m.man
close(f)
encoder.disable()
if f.err != ok:
@@ -775,29 +730,13 @@ type
# PackedItemId so that it works with reexported symbols too
# ifaceHidden includes private symbols
type
PackedModuleGraph* = object
pm*: seq[LoadedModule] # indexed by FileIndex
when BenchIC:
depAnalysis: MonoTime
loadBody: MonoTime
loadSym, loadType, loadBodies: MonoTime
when BenchIC:
proc echoTimes*(m: PackedModuleGraph) =
echo "analysis: ", m.depAnalysis, " loadBody: ", m.loadBody, " loadSym: ",
m.loadSym, " loadType: ", m.loadType, " all bodies: ", gloadBodies
template `[]`*(m: PackedModuleGraph; i: int): LoadedModule = m.pm[i]
template len*(m: PackedModuleGraph): int = m.pm.len
PackedModuleGraph* = seq[LoadedModule] # indexed by FileIndex
proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t: PackedItemId): PType
proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym
proc toFileIndexCached*(c: var PackedDecoder; g: PackedModuleGraph; thisModule: int; f: LitId): FileIndex =
if f == LitId(0):
result = InvalidFileIdx
elif c.lastLit == f and c.lastModule == thisModule:
if c.lastLit == f and c.lastModule == thisModule:
result = c.lastFile
else:
result = toFileIndex(f, g[thisModule].fromDisk, c.config)
@@ -808,9 +747,8 @@ proc toFileIndexCached*(c: var PackedDecoder; g: PackedModuleGraph; thisModule:
proc translateLineInfo(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
x: PackedLineInfo): TLineInfo =
assert g[thisModule].status in {loaded, storing, stored}
let (fileId, line, col) = unpack(g[thisModule].fromDisk.man, x)
result = TLineInfo(line: line.uint16, col: col.int16,
fileIndex: toFileIndexCached(c, g, thisModule, fileId))
result = TLineInfo(line: x.line, col: x.col,
fileIndex: toFileIndexCached(c, g, thisModule, x.file))
proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
tree: PackedTree; n: NodePos): PNode =
@@ -824,13 +762,16 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
result.flags = n.flags
case k
of nkNone, nkEmpty, nkNilLit, nkType:
of nkEmpty, nkNilLit, nkType:
discard
of nkIdent:
result.ident = getIdent(c.cache, g[thisModule].fromDisk.strings[n.litId])
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.sym = loadSym(c, g, thisModule, PackedItemId(module: LitId(0), item: tree.nodes[n.int].operand))
if result.typ == nil:
result.typ = result.sym.typ
of directIntLit:
result.intVal = tree.nodes[n.int].operand
of externIntLit:
result.intVal = g[thisModule].fromDisk.numbers[n.litId]
of nkStrLit..nkTripleStrLit:
@@ -839,11 +780,12 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
result.floatVal = cast[BiggestFloat](g[thisModule].fromDisk.numbers[n.litId])
of nkModuleRef:
let (n1, n2) = sons2(tree, n)
assert n1.kind == nkNone
assert n2.kind == nkNone
assert n1.kind == nkInt32Lit
assert n2.kind == nkInt32Lit
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.sym = loadSym(c, g, thisModule, PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand))
if result.typ == nil:
result.typ = result.sym.typ
else:
for n0 in sonsReadonly(tree, n):
result.addAllowNil loadNodes(c, g, thisModule, tree, n0)
@@ -875,7 +817,6 @@ proc loadProcHeader(c: var PackedDecoder; g: var PackedModuleGraph; thisModule:
proc loadProcBody(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
tree: PackedTree; n: NodePos): PNode =
result = nil
var i = 0
for n0 in sonsReadonly(tree, n):
if i == bodyPos:
@@ -938,27 +879,12 @@ proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
if externalName != "":
result.loc.r = rope externalName
result.loc.flags = s.locFlags
result.instantiatedFrom = loadSym(c, g, si, s.instantiatedFrom)
proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
fileIdx: FileIndex; cachedModules: var seq[FileIndex]): bool
proc loadToReplayNodes(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
fileIdx: FileIndex; m: var LoadedModule)
proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym =
if s == nilItemId:
result = nil
else:
let si = moduleIndex(c, g, thisModule, s)
if si >= g.len:
g.pm.setLen(si+1)
if g[si].status == undefined and c.config.cmd == cmdM:
var cachedModules: seq[FileIndex] = @[]
discard needsRecompile(g, c.config, c.cache, FileIndex(si), cachedModules)
for m in cachedModules:
loadToReplayNodes(g, c.config, c.cache, m, g[int m])
assert g[si].status in {loaded, storing, stored}
if not g[si].symsInit:
g[si].symsInit = true
@@ -973,7 +899,6 @@ proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s:
else:
result = g[si].module
assert result != nil
g[si].syms[s.item] = result
else:
result = g[si].syms[s.item]
@@ -994,10 +919,8 @@ proc typeBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
for op, item in pairs t.attachedOps:
result.attachedOps[op] = loadSym(c, g, si, item)
result.typeInst = loadType(c, g, si, t.typeInst)
var sons = newSeq[PType]()
for son in items t.types:
sons.add loadType(c, g, si, son)
result.setSons(sons)
result.sons.add loadType(c, g, si, son)
loadAstBody(t, n)
when false:
for gen, id in items t.methods:
@@ -1020,11 +943,9 @@ proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t
# store it here early on, so that recursions work properly:
g[si].types[t.item] = result
typeBodyFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item, result)
#assert result.itemId.item == t.item, $(result.itemId.item, t.item)
assert result.itemId.item > 0, $(result.itemId.item, t.item)
else:
result = g[si].types[t.item]
assert result.itemId.item > 0, "2"
assert result.itemId.item > 0
proc setupLookupTables(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
fileIdx: FileIndex; m: var LoadedModule) =
@@ -1074,37 +995,30 @@ proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache
# Does the file belong to the fileIdx need to be recompiled?
let m = int(fileIdx)
if m >= g.len:
g.pm.setLen(m+1)
g.setLen(m+1)
case g[m].status
of undefined:
g[m].status = loading
let fullpath = msgs.toFullPath(conf, fileIdx)
let rod = toRodFile(conf, AbsoluteFile fullpath)
let err = loadRodFile(rod, g[m].fromDisk, conf, ignoreConfig = conf.cmd == cmdM)
let err = loadRodFile(rod, g[m].fromDisk, conf)
if err == ok:
if conf.cmd == cmdM:
result = optForceFullMake in conf.globalOptions
# check its dependencies:
for dep in g[m].fromDisk.imports:
let fid = toFileIndex(dep, g[m].fromDisk, conf)
# Warning: we need to traverse the full graph, so
# do **not use break here**!
if needsRecompile(g, conf, cache, fid, cachedModules):
result = true
if not result:
setupLookupTables(g, conf, cache, fileIdx, g[m])
cachedModules.add fileIdx
g[m].status = loaded
result = false
else:
result = optForceFullMake in conf.globalOptions
# check its dependencies:
let imp = g[m].fromDisk.imports
for dep in imp:
let fid = toFileIndex(dep, g[m].fromDisk, conf)
# Warning: we need to traverse the full graph, so
# do **not use break here**!
if needsRecompile(g, conf, cache, fid, cachedModules):
result = true
if not result:
setupLookupTables(g, conf, cache, fileIdx, g[m])
cachedModules.add fileIdx
g[m].status = loaded
else:
g.pm[m] = LoadedModule(status: outdated, module: g[m].module)
g[m] = LoadedModule(status: outdated, module: g[m].module)
else:
loadError(err, rod, conf)
g[m].status = outdated
@@ -1119,13 +1033,12 @@ proc needsRecompile(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache
proc moduleFromRodFile*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
fileIdx: FileIndex; cachedModules: var seq[FileIndex]): PSym =
## Returns 'nil' if the module needs to be recompiled.
bench g.depAnalysis:
if needsRecompile(g, conf, cache, fileIdx, cachedModules):
result = nil
else:
result = g[int fileIdx].module
assert result != nil
assert result.position == int(fileIdx)
if needsRecompile(g, conf, cache, fileIdx, cachedModules):
result = nil
else:
result = g[int fileIdx].module
assert result != nil
assert result.position == int(fileIdx)
for m in cachedModules:
loadToReplayNodes(g, conf, cache, m, g[int m])
@@ -1139,49 +1052,46 @@ template setupDecoder() {.dirty.} =
proc loadProcBody*(config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; s: PSym): PNode =
bench g.loadBody:
let mId = s.itemId.module
let mId = s.itemId.module
var decoder = PackedDecoder(
lastModule: int32(-1),
lastLit: LitId(0),
lastFile: FileIndex(-1),
config: config,
cache: cache)
let pos = g[mId].fromDisk.syms[s.itemId.item].ast
assert pos != emptyNodeId
result = loadProcBody(decoder, g, mId, g[mId].fromDisk.bodies, NodePos pos)
proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; module: int; id: PackedItemId): PType =
if id.item < g[module].types.len:
result = g[module].types[id.item]
else:
result = nil
if result == nil:
var decoder = PackedDecoder(
lastModule: int32(-1),
lastLit: LitId(0),
lastFile: FileIndex(-1),
config: config,
cache: cache)
let pos = g[mId].fromDisk.syms[s.itemId.item].ast
assert pos != emptyNodeId
result = loadProcBody(decoder, g, mId, g[mId].fromDisk.bodies, NodePos pos)
proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; module: int; id: PackedItemId): PType =
bench g.loadType:
if id.item < g[module].types.len:
result = g[module].types[id.item]
else:
result = nil
if result == nil:
var decoder = PackedDecoder(
lastModule: int32(-1),
lastLit: LitId(0),
lastFile: FileIndex(-1),
config: config,
cache: cache)
result = loadType(decoder, g, module, id)
result = loadType(decoder, g, module, id)
proc loadSymFromId*(config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; module: int; id: PackedItemId): PSym =
bench g.loadSym:
if id.item < g[module].syms.len:
result = g[module].syms[id.item]
else:
result = nil
if result == nil:
var decoder = PackedDecoder(
lastModule: int32(-1),
lastLit: LitId(0),
lastFile: FileIndex(-1),
config: config,
cache: cache)
result = loadSym(decoder, g, module, id)
if id.item < g[module].syms.len:
result = g[module].syms[id.item]
else:
result = nil
if result == nil:
var decoder = PackedDecoder(
lastModule: int32(-1),
lastLit: LitId(0),
lastFile: FileIndex(-1),
config: config,
cache: cache)
result = loadSym(decoder, g, module, id)
proc translateId*(id: PackedItemId; g: PackedModuleGraph; thisModule: int; config: ConfigRef): ItemId =
if id.module == LitId(0):
@@ -1241,11 +1151,9 @@ proc initRodIter*(it: var RodIter; config: ConfigRef, cache: IdentCache;
if it.i < it.values.len:
result = loadSym(it.decoder, g, int(module), it.values[it.i])
inc it.i
else:
result = nil
proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; module: FileIndex; importHidden: bool): PSym =
g: var PackedModuleGraph; module: FileIndex, importHidden: bool): PSym =
it.decoder = PackedDecoder(
lastModule: int32(-1),
lastLit: LitId(0),
@@ -1260,15 +1168,11 @@ proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache;
if it.i < it.values.len:
result = loadSym(it.decoder, g, int(module), it.values[it.i])
inc it.i
else:
result = nil
proc nextRodIter*(it: var RodIter; g: var PackedModuleGraph): PSym =
if it.i < it.values.len:
result = loadSym(it.decoder, g, it.module, it.values[it.i])
inc it.i
else:
result = nil
iterator interfaceSymbols*(config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; module: FileIndex;
@@ -1301,12 +1205,12 @@ proc searchForCompilerproc*(m: LoadedModule; name: string): int32 =
# ------------------------- .rod file viewer ---------------------------------
proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) =
var m: PackedModule = PackedModule()
var m: PackedModule
let err = loadRodFile(rodfile, m, config, ignoreConfig=true)
if err != ok:
config.quitOrRaise "Error: could not load: " & $rodfile.string & " reason: " & $err
when false:
when true:
echo "exports:"
for ex in m.exports:
echo " ", m.strings[ex[0]], " local ID: ", ex[1]
@@ -1322,32 +1226,13 @@ proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) =
for ex in m.hidden:
echo " ", m.strings[ex[0]], " local ID: ", ex[1]
when false:
echo "all symbols"
for i in 0..high(m.syms):
if m.syms[i].name != LitId(0):
echo " ", m.strings[m.syms[i].name], " local ID: ", i, " kind ", m.syms[i].kind
else:
echo " <anon symbol?> local ID: ", i, " kind ", m.syms[i].kind
echo "all symbols"
for i in 0..high(m.syms):
if m.syms[i].name != LitId(0):
echo " ", m.strings[m.syms[i].name], " local ID: ", i, " kind ", m.syms[i].kind
else:
echo " <anon symbol?> local ID: ", i, " kind ", m.syms[i].kind
echo "symbols: ", m.syms.len, " types: ", m.types.len,
" top level nodes: ", m.topLevel.len, " other nodes: ", m.bodies.len,
" top level nodes: ", m.topLevel.nodes.len, " other nodes: ", m.bodies.nodes.len,
" strings: ", m.strings.len, " numbers: ", m.numbers.len
echo "SIZES:"
echo "symbols: ", m.syms.len * sizeof(PackedSym), " types: ", m.types.len * sizeof(PackedType),
" top level nodes: ", m.topLevel.len * sizeof(PackedNode),
" other nodes: ", m.bodies.len * sizeof(PackedNode),
" strings: ", sizeOnDisc(m.strings)
when false:
var tt = 0
var fc = 0
for x in m.topLevel:
if x.kind == nkSym or x.typeId == nilItemId: inc tt
if x.flags == {}: inc fc
for x in m.bodies:
if x.kind == nkSym or x.typeId == nilItemId: inc tt
if x.flags == {}: inc fc
let total = float(m.topLevel.len + m.bodies.len)
echo "nodes with nil type: ", tt, " in % ", tt.float / total
echo "nodes with empty flags: ", fc.float / total

View File

@@ -10,7 +10,7 @@
## Integrity checking for a set of .rod files.
## The set must cover a complete Nim project.
import std/sets
import sets
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -72,16 +72,15 @@ proc checkForeignSym(c: var CheckedContext; symId: PackedItemId) =
c.thisModule = oldThisModule
proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) =
let t = findType(tree, n)
if t != nilItemId:
checkType(c, t)
if tree[n.int].typeId != nilItemId:
checkType(c, tree[n.int].typeId)
case n.kind
of nkEmpty, nkNilLit, nkType, nkNilRodNode:
discard
of nkIdent:
assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
of nkSym:
checkLocalSym(c, tree[n].soperand)
checkLocalSym(c, tree.nodes[n.int].operand)
of directIntLit:
discard
of externIntLit, nkFloatLit..nkFloat128Lit:
@@ -90,9 +89,9 @@ proc checkNode(c: var CheckedContext; tree: PackedTree; n: NodePos) =
assert c.g.packed[c.thisModule].fromDisk.strings.hasLitId n.litId
of nkModuleRef:
let (n1, n2) = sons2(tree, n)
assert n1.kind == nkNone
assert n2.kind == nkNone
checkForeignSym(c, PackedItemId(module: n1.litId, item: tree[n2].soperand))
assert n1.kind == nkInt32Lit
assert n2.kind == nkInt32Lit
checkForeignSym(c, PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand))
else:
for n0 in sonsReadonly(tree, n):
checkNode(c, tree, n0)
@@ -135,15 +134,13 @@ proc checkModule(c: var CheckedContext; m: PackedModule) =
typeInstCache*: seq[(PackedItemId, PackedItemId)]
procInstCache*: seq[PackedInstantiation]
attachedOps*: seq[(TTypeAttachedOp, PackedItemId, PackedItemId)]
methodsPerGenericType*: seq[(PackedItemId, int, PackedItemId)]
methodsPerType*: seq[(PackedItemId, int, PackedItemId)]
enumToStringProcs*: seq[(PackedItemId, PackedItemId)]
methodsPerType*: seq[(PackedItemId, PackedItemId)]
dispatchers*: seq[PackedItemId]
]#
proc checkIntegrity*(g: ModuleGraph) =
var c = CheckedContext(g: g)
for i in 0..<len(g.packed):
for i in 0..high(g.packed):
# case statement here to enforce exhaustive checks.
case g.packed[i].status
of undefined:
@@ -153,3 +150,4 @@ proc checkIntegrity*(g: ModuleGraph) =
of stored, storing, outdated, loaded:
c.thisModule = int32 i
checkModule(c, g.packed[i].fromDisk)

View File

@@ -11,70 +11,59 @@
## IDE-like features. It uses the set of .rod files to accomplish
## its task. The set must cover a complete Nim project.
import std/sets
import sets
from std/os import nil
from os import nil
from std/private/miscdollars import toLocation
when defined(nimPreviewSlimSystem):
import std/assertions
import ".." / [ast, modulegraphs, msgs, options]
import ".." / nir / nirlineinfos
import packed_ast, bitabs, ic
type
UnpackedLineInfo = object
file: LitId
line, col: int
NavContext = object
g: ModuleGraph
thisModule: int32
trackPos: UnpackedLineInfo
trackPos: PackedLineInfo
alreadyEmitted: HashSet[string]
outputSep: char # for easier testing, use short filenames and spaces instead of tabs.
proc isTracked(man: LineInfoManager; current: PackedLineInfo, trackPos: UnpackedLineInfo, tokenLen: int): bool =
let (currentFile, currentLine, currentCol) = man.unpack(current)
if currentFile == trackPos.file and currentLine == trackPos.line:
proc isTracked(current, trackPos: PackedLineInfo, tokenLen: int): bool =
if current.file == trackPos.file and current.line == trackPos.line:
let col = trackPos.col
if col >= currentCol and col < currentCol+tokenLen:
result = true
else:
result = false
else:
result = false
if col >= current.col and col < current.col+tokenLen:
return true
proc searchLocalSym(c: var NavContext; s: PackedSym; info: PackedLineInfo): bool =
result = s.name != LitId(0) and
isTracked(c.g.packed[c.thisModule].fromDisk.man, info, c.trackPos, c.g.packed[c.thisModule].fromDisk.strings[s.name].len)
isTracked(info, c.trackPos, c.g.packed[c.thisModule].fromDisk.strings[s.name].len)
proc searchForeignSym(c: var NavContext; s: ItemId; info: PackedLineInfo): bool =
let name = c.g.packed[s.module].fromDisk.syms[s.item].name
result = name != LitId(0) and
isTracked(c.g.packed[c.thisModule].fromDisk.man, info, c.trackPos, c.g.packed[s.module].fromDisk.strings[name].len)
isTracked(info, c.trackPos, c.g.packed[s.module].fromDisk.strings[name].len)
const
EmptyItemId = ItemId(module: -1'i32, item: -1'i32)
proc search(c: var NavContext; tree: PackedTree): ItemId =
# We use the linear representation here directly:
for i in 0..<len(tree):
let i = NodePos(i)
case tree[i].kind
for i in 0..high(tree.nodes):
case tree.nodes[i].kind
of nkSym:
let item = tree[i].soperand
if searchLocalSym(c, c.g.packed[c.thisModule].fromDisk.syms[item], tree[i].info):
let item = tree.nodes[i].operand
if searchLocalSym(c, c.g.packed[c.thisModule].fromDisk.syms[item], tree.nodes[i].info):
return ItemId(module: c.thisModule, item: item)
of nkModuleRef:
let (currentFile, currentLine, currentCol) = c.g.packed[c.thisModule].fromDisk.man.unpack(tree[i].info)
if currentLine == c.trackPos.line and currentFile == c.trackPos.file:
let (n1, n2) = sons2(tree, i)
if tree.nodes[i].info.line == c.trackPos.line and tree.nodes[i].info.file == c.trackPos.file:
let (n1, n2) = sons2(tree, NodePos i)
assert n1.kind == nkInt32Lit
assert n2.kind == nkInt32Lit
let pId = PackedItemId(module: n1.litId, item: tree[n2].soperand)
let pId = PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand)
let itemId = translateId(pId, c.g.packed, c.thisModule, c.g.config)
if searchForeignSym(c, itemId, tree[i].info):
if searchForeignSym(c, itemId, tree.nodes[i].info):
return itemId
else: discard
return EmptyItemId
@@ -84,38 +73,36 @@ proc isDecl(tree: PackedTree; n: NodePos): bool =
const declarativeNodes = procDefs + {nkMacroDef, nkTemplateDef,
nkLetSection, nkVarSection, nkUsingStmt, nkConstSection, nkTypeSection,
nkIdentDefs, nkEnumTy, nkVarTuple}
result = n.int >= 0 and tree[n].kind in declarativeNodes
result = n.int >= 0 and tree[n.int].kind in declarativeNodes
proc usage(c: var NavContext; info: PackedLineInfo; isDecl: bool) =
let (fileId, line, col) = unpack(c.g.packed[c.thisModule].fromDisk.man, info)
var m = ""
var file = c.g.packed[c.thisModule].fromDisk.strings[fileId]
var file = c.g.packed[c.thisModule].fromDisk.strings[info.file]
if c.outputSep == ' ':
file = os.extractFilename file
toLocation(m, file, line, col + ColOffset)
toLocation(m, file, info.line.int, info.col.int + ColOffset)
if not c.alreadyEmitted.containsOrIncl(m):
msgWriteln c.g.config, (if isDecl: "def" else: "usage") & c.outputSep & m
proc list(c: var NavContext; tree: PackedTree; sym: ItemId) =
for i in 0..<len(tree):
let i = NodePos(i)
case tree[i].kind
for i in 0..high(tree.nodes):
case tree.nodes[i].kind
of nkSym:
let item = tree[i].soperand
let item = tree.nodes[i].operand
if sym.item == item and sym.module == c.thisModule:
usage(c, tree[i].info, isDecl(tree, parent(i)))
usage(c, tree.nodes[i].info, isDecl(tree, parent(NodePos i)))
of nkModuleRef:
let (n1, n2) = sons2(tree, i)
assert n1.kind == nkNone
assert n2.kind == nkNone
let pId = PackedItemId(module: n1.litId, item: tree[n2].soperand)
let (n1, n2) = sons2(tree, NodePos i)
assert n1.kind == nkInt32Lit
assert n2.kind == nkInt32Lit
let pId = PackedItemId(module: n1.litId, item: tree.nodes[n2.int].operand)
let itemId = translateId(pId, c.g.packed, c.thisModule, c.g.config)
if itemId.item == sym.item and sym.module == itemId.module:
usage(c, tree[i].info, isDecl(tree, parent(i)))
usage(c, tree.nodes[i].info, isDecl(tree, parent(NodePos i)))
else: discard
proc searchForIncludeFile(g: ModuleGraph; fullPath: string): int =
for i in 0..<len(g.packed):
for i in 0..high(g.packed):
for k in 1..high(g.packed[i].fromDisk.includes):
# we start from 1 because the first "include" file is
# the module's filename.
@@ -147,7 +134,7 @@ proc nav(g: ModuleGraph) =
var c = NavContext(
g: g,
thisModule: int32 mid,
trackPos: UnpackedLineInfo(line: unpacked.line.int, col: unpacked.col.int, file: fileId),
trackPos: PackedLineInfo(line: unpacked.line, col: unpacked.col, file: fileId),
outputSep: if isDefined(g.config, "nimIcNavigatorTests"): ' ' else: '\t'
)
var symId = search(c, g.packed[mid].fromDisk.topLevel)
@@ -158,7 +145,7 @@ proc nav(g: ModuleGraph) =
localError(g.config, unpacked, "no symbol at this position")
return
for i in 0..<len(g.packed):
for i in 0..high(g.packed):
# case statement here to enforce exhaustive checks.
case g.packed[i].status
of undefined:
@@ -175,7 +162,7 @@ proc navUsages*(g: ModuleGraph) = nav(g)
proc navDefusages*(g: ModuleGraph) = nav(g)
proc writeRodFiles*(g: ModuleGraph) =
for i in 0..<len(g.packed):
for i in 0..high(g.packed):
case g.packed[i].status
of undefined, loading, stored, loaded:
discard "nothing to do"

View File

@@ -12,12 +12,10 @@
## use this representation directly in all the transformations,
## it is superior.
import std/[hashes, tables, strtabs]
import bitabs, rodfiles
import hashes, tables, strtabs
import bitabs
import ".." / [ast, options]
import ".." / nir / nirlineinfos
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -33,12 +31,17 @@ type
item*: int32 # same as the in-memory representation
const
nilItemId* = PackedItemId(module: LitId(0), item: 0.int32)
nilItemId* = PackedItemId(module: LitId(0), item: -1.int32)
const
emptyNodeId* = NodeId(-1)
type
PackedLineInfo* = object
line*: uint16
col*: int16
file*: LitId
PackedLib* = object
kind*: TLibKind
generated*: bool
@@ -68,7 +71,6 @@ type
when hasFFI:
cname*: LitId
constraint*: NodeId
instantiatedFrom*: PackedItemId
PackedType* = object
kind*: TTypeKind
@@ -87,35 +89,23 @@ type
typeInst*: PackedItemId
nonUniqueId*: int32
PackedNode* = object # 8 bytes
x: uint32
PackedNode* = object # 28 bytes
kind*: TNodeKind
flags*: TNodeFlags
operand*: int32 # for kind in {nkSym, nkSymDef}: SymId
# for kind in {nkStrLit, nkIdent, nkNumberLit}: LitId
# for kind in nkInt32Lit: direct value
# for non-atom kinds: the number of nodes (for easy skipping)
typeId*: PackedItemId
info*: PackedLineInfo
PackedTree* = object ## usually represents a full Nim module
nodes: seq[PackedNode]
withFlags: seq[(int32, TNodeFlags)]
withTypes: seq[(int32, PackedItemId)]
nodes*: seq[PackedNode]
PackedInstantiation* = object
key*, sym*: PackedItemId
concreteTypes*: seq[PackedItemId]
const
NodeKindBits = 8'u32
NodeKindMask = (1'u32 shl NodeKindBits) - 1'u32
template kind*(n: PackedNode): TNodeKind = TNodeKind(n.x and NodeKindMask)
template uoperand*(n: PackedNode): uint32 = (n.x shr NodeKindBits)
template soperand*(n: PackedNode): int32 = int32(uoperand(n))
template toX(k: TNodeKind; operand: uint32): uint32 =
uint32(k) or (operand shl NodeKindBits)
template toX(k: TNodeKind; operand: LitId): uint32 =
uint32(k) or (operand.uint32 shl NodeKindBits)
template typeId*(n: PackedNode): PackedItemId = n.typ
proc `==`*(a, b: SymId): bool {.borrow.}
proc hash*(a: SymId): Hash {.borrow.}
@@ -127,32 +117,68 @@ proc newTreeFrom*(old: PackedTree): PackedTree =
result.nodes = @[]
when false: result.sh = old.sh
when false:
proc declareSym*(tree: var PackedTree; kind: TSymKind;
name: LitId; info: PackedLineInfo): SymId =
result = SymId(tree.sh.syms.len)
tree.sh.syms.add PackedSym(kind: kind, name: name, flags: {}, magic: mNone, info: info)
proc litIdFromName*(tree: PackedTree; name: string): LitId =
result = tree.sh.strings.getOrIncl(name)
proc add*(tree: var PackedTree; kind: TNodeKind; token: string; info: PackedLineInfo) =
tree.nodes.add PackedNode(kind: kind, info: info,
operand: int32 getOrIncl(tree.sh.strings, token))
proc add*(tree: var PackedTree; kind: TNodeKind; info: PackedLineInfo) =
tree.nodes.add PackedNode(kind: kind, operand: 0, info: info)
proc throwAwayLastNode*(tree: var PackedTree) =
tree.nodes.setLen(tree.nodes.len-1)
proc addIdent*(tree: var PackedTree; s: LitId; info: PackedLineInfo) =
tree.nodes.add PackedNode(x: toX(nkIdent, uint32(s)), info: info)
tree.nodes.add PackedNode(kind: nkIdent, operand: int32(s), info: info)
proc addSym*(tree: var PackedTree; s: int32; info: PackedLineInfo) =
tree.nodes.add PackedNode(x: toX(nkSym, cast[uint32](s)), info: info)
tree.nodes.add PackedNode(kind: nkSym, operand: s, info: info)
proc addModuleId*(tree: var PackedTree; s: ModuleId; info: PackedLineInfo) =
tree.nodes.add PackedNode(kind: nkInt32Lit, operand: int32(s), info: info)
proc addSymDef*(tree: var PackedTree; s: SymId; info: PackedLineInfo) =
tree.nodes.add PackedNode(x: toX(nkSym, cast[uint32](s)), info: info)
tree.nodes.add PackedNode(kind: nkSym, operand: int32(s), info: info)
proc isAtom*(tree: PackedTree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= nkNilLit
proc copyTree*(dest: var PackedTree; tree: PackedTree; n: NodePos) =
# and this is why the IR is superior. We can copy subtrees
# via a linear scan.
let pos = n.int
let L = if isAtom(tree, pos): 1 else: tree.nodes[pos].operand
let d = dest.nodes.len
dest.nodes.setLen(d + L)
for i in 0..<L:
dest.nodes[d+i] = tree.nodes[pos+i]
when false:
proc copySym*(dest: var PackedTree; tree: PackedTree; s: SymId): SymId =
result = SymId(dest.sh.syms.len)
assert int(s) < tree.sh.syms.len
let oldSym = tree.sh.syms[s.int]
dest.sh.syms.add oldSym
type
PatchPos = distinct int
proc addNode*(t: var PackedTree; kind: TNodeKind; operand: int32;
typeId: PackedItemId = nilItemId; info: PackedLineInfo;
flags: TNodeFlags = {}) =
t.nodes.add PackedNode(x: toX(kind, cast[uint32](operand)), info: info)
if flags != {}:
t.withFlags.add (t.nodes.len.int32 - 1, flags)
if typeId != nilItemId:
t.withTypes.add (t.nodes.len.int32 - 1, typeId)
when false:
proc prepare*(tree: var PackedTree; kind: TNodeKind; info: PackedLineInfo): PatchPos =
result = PatchPos tree.nodes.len
tree.nodes.add PackedNode(kind: kind, operand: 0, info: info)
proc prepare*(tree: var PackedTree; kind: TNodeKind; flags: TNodeFlags; typeId: PackedItemId; info: PackedLineInfo): PatchPos =
result = PatchPos tree.nodes.len
tree.addNode(kind = kind, flags = flags, operand = 0, info = info, typeId = typeId)
tree.nodes.add PackedNode(kind: kind, flags: flags, operand: 0, info: info,
typeId: typeId)
proc prepare*(dest: var PackedTree; source: PackedTree; sourcePos: NodePos): PatchPos =
result = PatchPos dest.nodes.len
@@ -160,30 +186,26 @@ proc prepare*(dest: var PackedTree; source: PackedTree; sourcePos: NodePos): Pat
proc patch*(tree: var PackedTree; pos: PatchPos) =
let pos = pos.int
let k = tree.nodes[pos].kind
assert k > nkNilLit
assert tree.nodes[pos].kind > nkNilLit
let distance = int32(tree.nodes.len - pos)
assert distance > 0
tree.nodes[pos].x = toX(k, cast[uint32](distance))
tree.nodes[pos].operand = distance
proc len*(tree: PackedTree): int {.inline.} = tree.nodes.len
proc `[]`*(tree: PackedTree; i: NodePos): lent PackedNode {.inline.} =
tree.nodes[i.int]
template rawSpan(n: PackedNode): int = int(uoperand(n))
proc `[]`*(tree: PackedTree; i: int): lent PackedNode {.inline.} =
tree.nodes[i]
proc nextChild(tree: PackedTree; pos: var int) {.inline.} =
if tree.nodes[pos].kind > nkNilLit:
assert tree.nodes[pos].uoperand > 0
inc pos, tree.nodes[pos].rawSpan
assert tree.nodes[pos].operand > 0
inc pos, tree.nodes[pos].operand
else:
inc pos
iterator sonsReadonly*(tree: PackedTree; n: NodePos): NodePos =
var pos = n.int
assert tree.nodes[pos].kind > nkNilLit
let last = pos + tree.nodes[pos].rawSpan
let last = pos + tree.nodes[pos].operand
inc pos
while pos < last:
yield NodePos pos
@@ -204,7 +226,7 @@ iterator isons*(dest: var PackedTree; tree: PackedTree;
iterator sonsFrom1*(tree: PackedTree; n: NodePos): NodePos =
var pos = n.int
assert tree.nodes[pos].kind > nkNilLit
let last = pos + tree.nodes[pos].rawSpan
let last = pos + tree.nodes[pos].operand
inc pos
if pos < last:
nextChild tree, pos
@@ -218,7 +240,7 @@ iterator sonsWithoutLast2*(tree: PackedTree; n: NodePos): NodePos =
inc count
var pos = n.int
assert tree.nodes[pos].kind > nkNilLit
let last = pos + tree.nodes[pos].rawSpan
let last = pos + tree.nodes[pos].operand
inc pos
while pos < last and count > 2:
yield NodePos pos
@@ -228,7 +250,7 @@ iterator sonsWithoutLast2*(tree: PackedTree; n: NodePos): NodePos =
proc parentImpl(tree: PackedTree; n: NodePos): NodePos =
# finding the parent of a node is rather easy:
var pos = n.int - 1
while pos >= 0 and (isAtom(tree, pos) or (pos + tree.nodes[pos].rawSpan - 1 < n.int)):
while pos >= 0 and (isAtom(tree, pos) or (pos + tree.nodes[pos].operand - 1 < n.int)):
dec pos
#assert pos >= 0, "node has no parent"
result = NodePos(pos)
@@ -254,32 +276,20 @@ proc firstSon*(tree: PackedTree; n: NodePos): NodePos {.inline.} =
proc kind*(tree: PackedTree; n: NodePos): TNodeKind {.inline.} =
tree.nodes[n.int].kind
proc litId*(tree: PackedTree; n: NodePos): LitId {.inline.} =
LitId tree.nodes[n.int].uoperand
LitId tree.nodes[n.int].operand
proc info*(tree: PackedTree; n: NodePos): PackedLineInfo {.inline.} =
tree.nodes[n.int].info
proc findType*(tree: PackedTree; n: NodePos): PackedItemId =
for x in tree.withTypes:
if x[0] == int32(n): return x[1]
if x[0] > int32(n): return nilItemId
return nilItemId
proc findFlags*(tree: PackedTree; n: NodePos): TNodeFlags =
for x in tree.withFlags:
if x[0] == int32(n): return x[1]
if x[0] > int32(n): return {}
return {}
template typ*(n: NodePos): PackedItemId =
tree.findType(n)
tree.nodes[n.int].typeId
template flags*(n: NodePos): TNodeFlags =
tree.findFlags(n)
tree.nodes[n.int].flags
template uoperand*(n: NodePos): uint32 =
tree.nodes[n.int].uoperand
template operand*(n: NodePos): int32 =
tree.nodes[n.int].operand
proc span*(tree: PackedTree; pos: int): int {.inline.} =
if isAtom(tree, pos): 1 else: tree.nodes[pos].rawSpan
if isAtom(tree, pos): 1 else: tree.nodes[pos].operand
proc sons2*(tree: PackedTree; n: NodePos): (NodePos, NodePos) =
assert(not isAtom(tree, n.int))
@@ -295,7 +305,6 @@ proc sons3*(tree: PackedTree; n: NodePos): (NodePos, NodePos, NodePos) =
result = (NodePos a, NodePos b, NodePos c)
proc ithSon*(tree: PackedTree; n: NodePos; i: int): NodePos =
result = default(NodePos)
if tree.nodes[n.int].kind > nkNilLit:
var count = 0
for child in sonsReadonly(tree, n):
@@ -309,28 +318,64 @@ when false:
template kind*(n: NodePos): TNodeKind = tree.nodes[n.int].kind
template info*(n: NodePos): PackedLineInfo = tree.nodes[n.int].info
template litId*(n: NodePos): LitId = LitId tree.nodes[n.int].uoperand
template litId*(n: NodePos): LitId = LitId tree.nodes[n.int].operand
template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].soperand
template symId*(n: NodePos): SymId = SymId tree.nodes[n.int].operand
proc firstSon*(n: NodePos): NodePos {.inline.} = NodePos(n.int+1)
when false:
# xxx `nkStrLit` or `nkStrLit..nkTripleStrLit:` below?
proc strLit*(tree: PackedTree; n: NodePos): lent string =
assert n.kind == nkStrLit
result = tree.sh.strings[LitId tree.nodes[n.int].operand]
proc strVal*(tree: PackedTree; n: NodePos): string =
assert n.kind == nkStrLit
result = tree.sh.strings[LitId tree.nodes[n.int].operand]
#result = cookedStrLit(raw)
proc filenameVal*(tree: PackedTree; n: NodePos): string =
case n.kind
of nkStrLit:
result = strVal(tree, n)
of nkIdent:
result = tree.sh.strings[n.litId]
of nkSym:
result = tree.sh.strings[tree.sh.syms[int n.symId].name]
else:
result = ""
proc identAsStr*(tree: PackedTree; n: NodePos): lent string =
assert n.kind == nkIdent
result = tree.sh.strings[LitId tree.nodes[n.int].operand]
const
externIntLit* = {nkCharLit,
nkIntLit,
nkInt8Lit,
nkInt16Lit,
nkInt32Lit,
nkInt64Lit,
nkUIntLit,
nkUInt8Lit,
nkUInt16Lit,
nkUInt32Lit,
nkUInt64Lit}
nkUInt64Lit} # nkInt32Lit is missing by design!
externSIntLit* = {nkIntLit, nkInt8Lit, nkInt16Lit, nkInt32Lit, nkInt64Lit}
externSIntLit* = {nkIntLit, nkInt8Lit, nkInt16Lit, nkInt64Lit}
externUIntLit* = {nkUIntLit, nkUInt8Lit, nkUInt16Lit, nkUInt32Lit, nkUInt64Lit}
directIntLit* = nkNone
directIntLit* = nkInt32Lit
when false:
proc identIdImpl(tree: PackedTree; n: NodePos): LitId =
if n.kind == nkIdent:
result = n.litId
elif n.kind == nkSym:
result = tree.sh.syms[int n.symId].name
else:
result = LitId(0)
template identId*(n: NodePos): LitId = identIdImpl(tree, n)
template copyInto*(dest, n, body) =
let patchPos = prepare(dest, tree, n)
@@ -342,8 +387,28 @@ template copyIntoKind*(dest, kind, info, body) =
body
patch dest, patchPos
when false:
proc hasPragma*(tree: PackedTree; n: NodePos; pragma: string): bool =
let litId = tree.sh.strings.getKeyId(pragma)
if litId == LitId(0):
return false
assert n.kind == nkPragma
for ch0 in sonsReadonly(tree, n):
if ch0.kind == nkExprColonExpr:
if ch0.firstSon.identId == litId:
return true
elif ch0.identId == litId:
return true
proc getNodeId*(tree: PackedTree): NodeId {.inline.} = NodeId tree.nodes.len
when false:
proc produceError*(dest: var PackedTree; tree: PackedTree; n: NodePos; msg: string) =
let patchPos = prepare(dest, nkError, n.info)
dest.add nkStrLit, msg, n.info
copyTree(dest, tree, n)
patch dest, patchPos
iterator allNodes*(tree: PackedTree): NodePos =
var p = 0
while p < tree.len:
@@ -353,13 +418,3 @@ iterator allNodes*(tree: PackedTree): NodePos =
proc toPackedItemId*(item: int32): PackedItemId {.inline.} =
PackedItemId(module: LitId(0), item: item)
proc load*(f: var RodFile; t: var PackedTree) =
loadSeq f, t.nodes
loadSeq f, t.withFlags
loadSeq f, t.withTypes
proc store*(f: var RodFile; t: PackedTree) =
storeSeq f, t.nodes
storeSeq f, t.withFlags
storeSeq f, t.withTypes

View File

@@ -14,7 +14,7 @@
import ".." / [ast, modulegraphs, trees, extccomp, btrees,
msgs, lineinfos, pathutils, options, cgmeth]
import std/tables
import tables
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -103,17 +103,6 @@ proc replayBackendProcs*(g: ModuleGraph; module: int) =
let symId = FullId(module: tmp.module, packed: it[1])
g.enumToStringProcs[key] = LazySym(id: symId, sym: nil)
for it in mitems(g.packed[module].fromDisk.methodsPerType):
let key = translateId(it[0], g.packed, module, g.config)
let tmp = translateId(it[1], g.packed, module, g.config)
let symId = FullId(module: tmp.module, packed: it[1])
g.methodsPerType.mgetOrPut(key, @[]).add LazySym(id: symId, sym: nil)
for it in mitems(g.packed[module].fromDisk.dispatchers):
let tmp = translateId(it, g.packed, module, g.config)
let symId = FullId(module: tmp.module, packed: it)
g.dispatchers.add LazySym(id: symId, sym: nil)
proc replayGenericCacheInformation*(g: ModuleGraph; module: int) =
## We remember the generic instantiations a module performed
## in order to to avoid the code bloat that generic code tends
@@ -138,12 +127,12 @@ proc replayGenericCacheInformation*(g: ModuleGraph; module: int) =
module: module, sym: FullId(module: sym.module, packed: it.sym),
concreteTypes: concreteTypes, inst: nil)
for it in mitems(g.packed[module].fromDisk.methodsPerGenericType):
for it in mitems(g.packed[module].fromDisk.methodsPerType):
let key = translateId(it[0], g.packed, module, g.config)
let col = it[1]
let tmp = translateId(it[2], g.packed, module, g.config)
let symId = FullId(module: tmp.module, packed: it[2])
g.methodsPerGenericType.mgetOrPut(key, @[]).add (col, LazySym(id: symId, sym: nil))
g.methodsPerType.mgetOrPut(key, @[]).add (col, LazySym(id: symId, sym: nil))
replayBackendProcs(g, module)

View File

@@ -14,7 +14,7 @@
## compiler works and less a storage format, you're probably looking for
## the `ic` or `packed_ast` modules to understand the logical format.
from std/typetraits import supportsCopyMem
from typetraits import supportsCopyMem
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
@@ -92,16 +92,11 @@ type
typeInstCacheSection
procInstCacheSection
attachedOpsSection
methodsPerGenericTypeSection
enumToStringProcsSection
methodsPerTypeSection
dispatchersSection
enumToStringProcsSection
typeInfoSection # required by the backend
backendFlagsSection
aliveSymsSection # beware, this is stored in a `.alivesyms` file.
sideChannelSection
namespaceSection
symnamesSection
RodFileError* = enum
ok, tooBig, cannotOpen, ioFailure, wrongHeader, wrongSection, configMismatch,
@@ -114,8 +109,8 @@ type
# better than exceptions.
const
RodVersion = 2
defaultCookie = [byte(0), byte('R'), byte('O'), byte('D'),
RodVersion = 1
cookie = [byte(0), byte('R'), byte('O'), byte('D'),
byte(sizeof(int)*8), byte(system.cpuEndian), byte(0), byte(RodVersion)]
proc setError(f: var RodFile; err: RodFileError) {.inline.} =
@@ -211,16 +206,16 @@ proc loadSeq*[T](f: var RodFile; s: var seq[T]) =
for i in 0..<lenPrefix:
loadPrim(f, s[i])
proc storeHeader*(f: var RodFile; cookie = defaultCookie) =
proc storeHeader*(f: var RodFile) =
## stores the header which is described by `cookie`.
if f.err != ok: return
if f.f.writeBytes(cookie, 0, cookie.len) != cookie.len:
setError f, ioFailure
proc loadHeader*(f: var RodFile; cookie = defaultCookie) =
proc loadHeader*(f: var RodFile) =
## Loads the header which is described by `cookie`.
if f.err != ok: return
var thisCookie: array[cookie.len, byte] = default(array[cookie.len, byte])
var thisCookie: array[cookie.len, byte]
if f.f.readBytes(thisCookie, 0, thisCookie.len) != thisCookie.len:
setError f, ioFailure
elif thisCookie != cookie:
@@ -236,14 +231,13 @@ proc storeSection*(f: var RodFile; s: RodSection) =
proc loadSection*(f: var RodFile; expected: RodSection) =
## read the bytes value of s, sets and error if the section is incorrect.
if f.err != ok: return
var s: RodSection = default(RodSection)
var s: RodSection
loadPrim(f, s)
if expected != s and f.err == ok:
setError f, wrongSection
proc create*(filename: string): RodFile =
## create the file and open it for writing
result = default(RodFile)
if not open(result.f, filename, fmWrite):
setError result, cannotOpen
@@ -251,6 +245,5 @@ proc close*(f: var RodFile) = close(f.f)
proc open*(filename: string): RodFile =
## open the file for reading
result = default(RodFile)
if not open(result.f, filename, fmRead):
setError result, cannotOpen

View File

@@ -11,8 +11,8 @@
# An identifier is a shared immutable string that can be compared by its
# id. This module is essential for the compiler's performance.
import wordrecg
import std/hashes
import
hashes, wordrecg
when defined(nimPreviewSlimSystem):
import std/assertions

View File

@@ -10,12 +10,10 @@
## This module implements the symbol importing mechanism.
import
ast, astalgo, msgs, options, idents, lookups,
semdata, modulepaths, sigmatch, lineinfos,
modulegraphs, wordrecg
from std/strutils import `%`, startsWith
from std/sequtils import addUnique
import std/[sets, tables, intsets]
intsets, ast, astalgo, msgs, options, idents, lookups,
semdata, modulepaths, sigmatch, lineinfos, sets,
modulegraphs, wordrecg, tables
from strutils import `%`
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -115,7 +113,6 @@ proc rawImportSymbol(c: PContext, s, origin: PSym; importSet: var IntSet) =
proc splitPragmas(c: PContext, n: PNode): (PNode, seq[TSpecialWord]) =
template bail = globalError(c.config, n.info, "invalid pragma")
result = (nil, @[])
if n.kind == nkPragmaExpr:
if n.len == 2 and n[1].kind == nkPragma:
result[0] = n[0]
@@ -144,7 +141,7 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym; importSet: var IntSet) =
# for an enumeration we have to add all identifiers
if multiImport:
# for a overloadable syms add all overloaded routines
var it: ModuleIter
var it: ModuleIter = default(ModuleIter)
var e = initModuleIter(it, c.graph, fromMod, s.name)
while e != nil:
if e.name.id != s.name.id: internalError(c.config, n.info, "importSymbol: 3")
@@ -231,6 +228,11 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym; im
for i in 0..n.safeLen-1:
importForwarded(c, n[i], exceptSet, fromMod, importSet)
proc addUnique[T](x: var seq[T], y: sink T) {.noSideEffect.} =
for i in 0..high(x):
if x[i] == y: return
x.add y
proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool): PSym =
result = realModule
template createModuleAliasImpl(ident): untyped =
@@ -302,18 +304,19 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym =
var prefix = ""
if realModule.constraint != nil: prefix = realModule.constraint.strVal & "; "
message(c.config, n.info, warnDeprecated, prefix & realModule.name.s & " is deprecated")
let moduleName = getModuleName(c.config, n)
if belongsToStdlib(c.graph, result) and not startsWith(moduleName, stdPrefix) and
not startsWith(moduleName, "system/") and not startsWith(moduleName, "packages/"):
message(c.config, n.info, warnStdPrefix, realModule.name.s)
suggestSym(c.graph, n.info, result, c.graph.usageSym, false)
proc suggestMod(n: PNode; s: PSym) =
if n.kind == nkImportAs:
suggestMod(n[0], realModule)
elif n.kind == nkInfix:
suggestMod(n[2], s)
else:
suggestSym(c.graph, n.info, s, c.graph.usageSym, false)
suggestMod(n, result)
importStmtResult.add newSymNode(result, n.info)
#newStrNode(toFullPath(c.config, f), n.info)
else:
result = nil
proc afterImport(c: PContext, m: PSym) =
if isCachedModule(c.graph, m): return
# fixes bug #17510, for re-exported symbols
let realModuleId = c.importModuleMap[m.id]
for s in allSyms(c.graph, m):
@@ -349,9 +352,11 @@ proc evalImport*(c: PContext, n: PNode): PNode =
imp[lastPos] = x[1]
impAs[1] = imp
impAs[2] = x[2]
impAs.info = x[2].info
impMod(c, impAs, result)
else:
imp[lastPos] = x
imp.info = x.info
impMod(c, imp, result)
else:
impMod(c, it, result)

View File

@@ -14,13 +14,11 @@
## See doc/destructors.rst for a spec of the implemented rewrite rules
import
ast, astalgo, msgs, renderer, magicsys, types, idents,
options, lowerings, modulegraphs,
intsets, strtabs, ast, astalgo, msgs, renderer, magicsys, types, idents,
strutils, options, lowerings, tables, modulegraphs,
lineinfos, parampatterns, sighashes, liftdestructors, optimizer,
varpartitions, aliasanalysis, dfa, wordrecg
import std/[strtabs, tables, strutils, intsets]
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -163,7 +161,8 @@ proc isLastReadImpl(n: PNode; c: var Con; scope: var Scope): bool =
result = false
proc isLastRead(n: PNode; c: var Con; s: var Scope): bool =
if not hasDestructor(c, n.typ): return true
# bug #23354; an object type could have a non-trival assignements when it is passed to a sink parameter
if not hasDestructor(c, n.typ) and (n.typ.kind != tyObject or isTrival(getAttachedOp(c.graph, n.typ, attachedAsgn))): return true
let m = skipConvDfa(n)
result = (m.kind == nkSym and sfSingleUsedTemp in m.sym.flags) or
@@ -211,12 +210,10 @@ proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string; inferredFr
m.add " a 'sink' parameter"
m.add "; routine: "
m.add c.owner.name.s
#m.add "\n\n"
#m.add renderTree(c.body, {renderIds})
localError(c.graph.config, ri.info, errGenerated, m)
proc makePtrType(c: var Con, baseType: PType): PType =
result = newType(tyPtr, c.idgen, c.owner)
result = newType(tyPtr, nextTypeId c.idgen, c.owner)
addSonSkipIntLit(result, baseType, c.idgen)
proc genOp(c: var Con; op: PSym; dest: PNode): PNode =
@@ -299,7 +296,7 @@ proc genSink(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFla
proc isCriticalLink(dest: PNode): bool {.inline.} =
#[
Lins's idea that only "critical" links can introduce a cycle. This is
critical for the performance gurantees that we strive for: If you
critical for the performance guarantees that we strive for: If you
traverse a data structure, no tracing will be performed at all.
ORC is about this promise: The GC only touches the memory that the
mutator touches too.
@@ -316,9 +313,10 @@ proc isCriticalLink(dest: PNode): bool {.inline.} =
]#
result = dest.kind != nkSym
proc finishCopy(c: var Con; result, dest: PNode; isFromSink: bool) =
if c.graph.config.selectedGC == gcOrc:
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
proc finishCopy(c: var Con; result, dest: PNode; flags: set[MoveOrCopyFlag]; isFromSink: bool) =
if c.graph.config.selectedGC == gcOrc and IsExplicitSink notin flags:
# add cyclic flag, but not to sink calls, which IsExplicitSink generates
let t = dest.typ.skipTypes(tyUserTypeClasses + {tyGenericInst, tyAlias, tySink, tyDistinct})
if cyclicType(c.graph, t):
result.add boolLit(c.graph, result.info, isFromSink or isCriticalLink(dest))
@@ -411,7 +409,10 @@ proc genDefaultCall(t: PType; c: Con; info: TLineInfo): PNode =
proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
# generate: (let tmp = v; reset(v); tmp)
if (not hasDestructor(c, n.typ)) and c.inEnsureMove == 0:
assert n.kind != nkSym or not hasDestructor(c, n.sym.typ)
assert n.kind != nkSym or not hasDestructor(c, n.sym.typ) or
(n.typ.kind == tyPtr and n.sym.typ.kind == tyRef)
# bug #23505; transformed by `transf`: addr (deref ref) -> ptr
# we know it's really a pointer; so here we assign it directly
result = copyTree(n)
else:
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
@@ -438,28 +439,28 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
proc isCapturedVar(n: PNode): bool =
let root = getRoot(n)
if root != nil: result = root.name.s[0] == ':'
else: result = false
proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let tmp = c.getTemp(s, n.typ, n.info)
if hasDestructor(c, n.typ):
let typ = n.typ.skipTypes({tyGenericInst, tyAlias, tySink})
let nTyp = n.typ.skipTypes(tyUserTypeClasses)
let tmp = c.getTemp(s, nTyp, n.info)
if hasDestructor(c, nTyp):
let typ = nTyp.skipTypes({tyGenericInst, tyAlias, tySink})
let op = getAttachedOp(c.graph, typ, attachedDup)
if op != nil and tfHasOwned notin typ.flags:
if sfError in op.flags:
c.checkForErrorPragma(n.typ, n, "=dup")
c.checkForErrorPragma(nTyp, n, "=dup")
else:
let copyOp = getAttachedOp(c.graph, typ, attachedAsgn)
if copyOp != nil and sfError in copyOp.flags and
sfOverridden notin op.flags:
c.checkForErrorPragma(n.typ, n, "=dup", inferredFromCopy = true)
c.checkForErrorPragma(nTyp, n, "=dup", inferredFromCopy = true)
let src = p(n, c, s, normal)
var newCall = newTreeIT(nkCall, src.info, src.typ,
newSymNode(op),
src)
c.finishCopy(newCall, n, isFromSink = true)
c.finishCopy(newCall, n, {}, isFromSink = true)
result.add newTreeI(nkFastAsgn,
src.info, tmp,
newCall
@@ -468,9 +469,9 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
result.add c.genWasMoved(tmp)
var m = c.genCopy(tmp, n, {})
m.add p(n, c, s, normal)
c.finishCopy(m, n, isFromSink = true)
c.finishCopy(m, n, {}, isFromSink = true)
result.add m
if isLValue(n) and not isCapturedVar(n) and n.typ.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0:
if isLValue(n) and not isCapturedVar(n) and nTyp.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0:
message(c.graph.config, n.info, hintPerformance,
("passing '$1' to a sink parameter introduces an implicit copy; " &
"if possible, rearrange your program's control flow to prevent it") % $n)
@@ -479,8 +480,8 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
("cannot move '$1', passing '$1' to a sink parameter introduces an implicit copy") % $n)
else:
if c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
assert(not containsManagedMemory(n.typ))
if n.typ.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
assert(not containsManagedMemory(nTyp))
if nTyp.skipTypes(abstractInst).kind in {tyOpenArray, tyVarargs}:
localError(c.graph.config, n.info, "cannot create an implicit openArray copy to be passed to a sink parameter")
result.add newTree(nkAsgn, tmp, p(n, c, s, normal))
# Since we know somebody will take over the produced copy, there is
@@ -496,7 +497,7 @@ proc containsConstSeq(n: PNode): bool =
return true
result = false
case n.kind
of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv, nkCast:
result = containsConstSeq(n[1])
of nkObjConstr, nkClosure:
for i in 1..<n.len:
@@ -594,7 +595,9 @@ template processScopeExpr(c: var Con; s: var Scope; ret: PNode, processCall: unt
# tricky because you would have to intercept moveOrCopy at a certain point
let tmp = c.getTemp(s.parent[], ret.typ, ret.info)
tmp.sym.flags = tmpFlags
let cpy = if hasDestructor(c, ret.typ):
let cpy = if hasDestructor(c, ret.typ) and
ret.typ.kind notin {tyOpenArray, tyVarargs}:
# bug #23247 we don't own the data, so it's harmful to destroy it
s.parent[].final.add c.genDestroy(tmp)
moveOrCopy(tmp, ret, c, s, {IsDecl})
else:
@@ -740,9 +743,7 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false,
result[^1] = maybeVoid(n[^1], s)
dec c.inUncheckedAssignSection, inUncheckedAssignSection
else:
result = nil
assert(false)
else: assert(false)
proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
if optOwnedRefs in c.graph.config.globalOptions and n[0].kind != nkEmpty:
@@ -754,7 +755,7 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
let tmp = c.getTemp(s, n[0].typ, n.info)
var m = c.genCopyNoCheck(tmp, n[0], attachedAsgn)
m.add p(n[0], c, s, normal)
c.finishCopy(m, n[0], isFromSink = false)
c.finishCopy(m, n[0], {}, isFromSink = false)
result = newTree(nkStmtList, c.genWasMoved(tmp), m)
var toDisarm = n[0]
if toDisarm.kind == nkStmtListExpr: toDisarm = toDisarm.lastSon
@@ -769,6 +770,18 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
result.add copyNode(n[0])
s.needsTry = true
template isCustomDestructor(c: Con, t: PType): bool =
hasDestructor(c, t) and
getAttachedOp(c.graph, t, attachedDestructor) != nil and
sfOverridden in getAttachedOp(c.graph, t, attachedDestructor).flags
proc hasCustomDestructor(c: Con, t: PType): bool =
result = isCustomDestructor(c, t)
var obj = t
while obj.len > 0 and obj[0] != nil:
obj = skipTypes(obj[0], abstractPtrs)
result = result or isCustomDestructor(c, obj)
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode =
if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt,
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt, nkPragmaBlock}:
@@ -782,15 +795,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
@@ -810,6 +815,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
elif n.kind in {nkObjDownConv, nkObjUpConv}:
result = copyTree(n)
result[0] = p(n[0], c, s, sinkArg)
elif n.kind == nkCast and n.typ.skipTypes(abstractInst).kind in {tyString, tySequence}:
result = copyTree(n)
result[1] = p(n[1], c, s, sinkArg)
elif n.typ == nil:
# 'raise X' can be part of a 'case' expression. Deal with it here:
result = p(n, c, s, normal)
@@ -859,17 +867,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
result[i][1] = p(n[i][1], c, s, m)
else:
result[i] = p(n[i], c, s, m)
if mode == normal and (isRefConstr or (hasDestructor(c, t) and
getAttachedOp(c.graph, t, attachedDestructor) != nil and
sfOverridden in getAttachedOp(c.graph, t, attachedDestructor).flags)):
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
@@ -886,13 +886,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:
@@ -907,7 +913,10 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
result[0] = p(n[0], c, s, normal)
if canRaise(n[0]): s.needsTry = true
if mode == normal:
result = ensureDestruction(result, n, c, s)
if result.typ != nil and result.typ.kind notin {tyOpenArray, tyVarargs}:
# Returns of openarray types shouldn't be destroyed
# bug #19435; # bug #23247
result = ensureDestruction(result, n, c, s)
of nkDiscardStmt: # Small optimization
result = shallowCopy(n)
if n[0].kind != nkEmpty:
@@ -1055,7 +1064,6 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
of nkGotoState, nkState, nkAsmStmt:
result = n
else:
result = nil
internalError(c.graph.config, n.info, "cannot inject destructors to node kind: " & $n.kind)
proc sameLocation*(a, b: PNode): bool =
@@ -1148,7 +1156,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
c.finishCopy(result, dest, flags, isFromSink = false)
of nkBracket:
# array constructor
if ri.len > 0 and isDangerousSeq(ri.typ):
@@ -1156,7 +1164,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
c.finishCopy(result, dest, flags, isFromSink = false)
else:
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit:
@@ -1167,8 +1175,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
let snk = c.genSink(s, dest, ri, flags)
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri) and
not ({sfGlobal, sfPure} <= ri.sym.flags):
isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri):
# Rule 3: `=sink`(x, z); wasMoved(z)
let snk = c.genSink(s, dest, ri, flags)
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
@@ -1177,7 +1184,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
c.finishCopy(result, dest, flags, isFromSink = false)
of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv, nkCast:
result = c.genSink(s, dest, p(ri, c, s, sinkArg), flags)
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt:
@@ -1197,7 +1204,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
c.finishCopy(result, dest, flags, isFromSink = false)
when false:
proc computeUninit(c: var Con) =

View File

@@ -10,7 +10,7 @@ Platforms: """
macosx: i386;amd64;powerpc64;arm64
solaris: i386;amd64;sparc;sparc64
freebsd: i386;amd64;powerpc64;arm;arm64;riscv64;sparc64;mips;mipsel;mips64;mips64el;powerpc;powerpc64el
netbsd: i386;amd64
netbsd: i386;amd64;arm64
openbsd: i386;amd64;arm;arm64
dragonfly: i386;amd64
crossos: amd64
@@ -71,7 +71,6 @@ Files: "testament"
Files: "nimsuggest"
Files: "nimsuggest/tests/*.nim"
Files: "changelogs/*.md"
Files: "ci/funs.sh"
[Lib]
Files: "lib"

View File

@@ -3,7 +3,7 @@
## hold all from `low(BiggestInt)` to `high(BiggestUInt)`, This
## type is for that purpose.
from std/math import trunc
from math import trunc
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -171,7 +171,6 @@ proc addToHex*(result: var string; arg: Int128) =
i -= 1
proc toHex*(arg: Int128): string =
result = ""
result.addToHex(arg)
proc inc*(a: var Int128, y: uint32 = 1) =
@@ -331,8 +330,8 @@ proc `*`*(a: Int128, b: int32): Int128 =
if b < 0:
result = -result
proc `*=`(a: var Int128, b: int32) =
a = a * b
proc `*=`*(a: var Int128, b: int32): Int128 =
result = result * b
proc makeInt128(high, low: uint64): Int128 =
result.udata[0] = cast[uint32](low)
@@ -358,10 +357,9 @@ proc `*`*(lhs, rhs: Int128): Int128 =
proc `*=`*(a: var Int128, b: Int128) =
a = a * b
import std/bitops
import bitops
proc fastLog2*(a: Int128): int =
result = 0
if a.udata[3] != 0:
return 96 + fastLog2(a.udata[3])
if a.udata[2] != 0:
@@ -573,4 +571,4 @@ proc maskBytes*(arg: Int128, numbytes: int): Int128 {.noinit.} =
of 8:
return maskUInt64(arg)
else:
raiseAssert "masking only implemented for 1, 2, 4 and 8 bytes"
assert(false, "masking only implemented for 1, 2, 4 and 8 bytes")

View File

@@ -11,9 +11,7 @@
## https://github.com/nim-lang/RFCs/issues/244 for more details.
import
ast, types, renderer
import std/intsets
ast, types, renderer, intsets
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -23,7 +21,6 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool
proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool =
case n.kind
of nkRecList:
result = false
for i in 0..<n.len:
result = canAliasN(arg, n[i], marker)
if result: return
@@ -39,7 +36,7 @@ proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool =
else: discard
of nkSym:
result = canAlias(arg, n.sym.typ, marker)
else: result = false
else: discard
proc canAlias(arg, ret: PType; marker: var IntSet): bool =
if containsOrIncl(marker, ret.id):
@@ -59,7 +56,6 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool =
else:
result = true
of tyTuple:
result = false
for i in 0..<ret.len:
result = canAlias(arg, ret[i], marker)
if result: break
@@ -188,12 +184,10 @@ proc checkIsolate*(n: PNode): bool =
return false
result = true
of nkIfStmt, nkIfExpr:
result = false
for it in n:
result = checkIsolate(it.lastSon)
if not result: break
of nkCaseStmt:
result = false
for i in 1..<n.len:
result = checkIsolate(n[i].lastSon)
if not result: break
@@ -203,7 +197,6 @@ proc checkIsolate*(n: PNode): bool =
result = checkIsolate(n[i].lastSon)
if not result: break
of nkBracket, nkTupleConstr, nkPar:
result = false
for it in n:
result = checkIsolate(it)
if not result: break

View File

@@ -32,18 +32,17 @@ import
ast, trees, magicsys, options,
nversion, msgs, idents, types,
ropes, ccgutils, wordrecg, renderer,
cgmeth, lowerings, sighashes, modulegraphs, lineinfos,
cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
transf, injectdestructors, sourcemap, astmsgs, backendpragmas
import pipelineutils
import std/[json, sets, math, tables, intsets]
import std/strutils except addf
import json, sets, math, tables, intsets
import strutils except addf
when defined(nimPreviewSlimSystem):
import std/[assertions, syncio]
import std/formatfloat
type
TJSGen = object of PPassContext
@@ -138,15 +137,17 @@ template nested(p, body) =
dec p.extraIndent
proc newGlobals(): PGlobals =
result = PGlobals(forwarded: @[],
generatedSyms: initIntSet(),
typeInfoGenerated: initIntSet()
)
new(result)
result.forwarded = @[]
result.generatedSyms = initIntSet()
result.typeInfoGenerated = initIntSet()
proc initCompRes(): TCompRes =
result = TCompRes(address: "", res: "",
tmpLoc: "", typ: etyNone, kind: resNone
)
proc initCompRes(r: var TCompRes) =
r.address = ""
r.res = ""
r.tmpLoc = ""
r.typ = etyNone
r.kind = resNone
proc rdLoc(a: TCompRes): Rope {.inline.} =
if a.typ != etyBaseIndex:
@@ -218,8 +219,7 @@ proc mapType(typ: PType): TJSTypeKind =
else: result = etyNone
of tyProc: result = etyProc
of tyCstring: result = etyString
of tyConcept, tyIterable:
raiseAssert "unreachable"
of tyConcept, tyIterable: doAssert false
proc mapType(p: PProc; typ: PType): TJSTypeKind =
result = mapType(typ)
@@ -348,7 +348,8 @@ proc isSimpleExpr(p: PProc; n: PNode): bool =
if n[i].kind notin {nkCommentStmt, nkEmpty}: return false
result = isSimpleExpr(p, n.lastSon)
else:
result = n.isAtom
if n.isAtom:
result = true
proc getTemp(p: PProc, defineInLocals: bool = true): Rope =
inc(p.unique)
@@ -358,7 +359,7 @@ proc getTemp(p: PProc, defineInLocals: bool = true): Rope =
proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
assert r.kind == resNone
var x, y: TCompRes = default(TCompRes)
var x, y: TCompRes
if p.isSimpleExpr(a) and p.isSimpleExpr(b):
gen(p, a, x)
gen(p, b, y)
@@ -385,7 +386,7 @@ proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
assert r.kind == resNone
var x, y: TCompRes = default(TCompRes)
var x, y: TCompRes
if p.isSimpleExpr(a) and p.isSimpleExpr(b):
gen(p, a, x)
gen(p, b, y)
@@ -473,7 +474,6 @@ const # magic checked op; magic unchecked op;
proc needsTemp(p: PProc; n: PNode): bool =
# check if n contains a call to determine
# if a temp should be made to prevent multiple evals
result = false
if n.kind in nkCallKinds + {nkTupleConstr, nkObjConstr, nkBracket, nkCurly}:
return true
for c in n:
@@ -509,8 +509,8 @@ proc maybeMakeTempAssignable(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rop
elif x.tmpLoc != "" and n.kind == nkBracketExpr:
# genArrayAddr
var
address, index: TCompRes = default(TCompRes)
first: Int128 = Zero
address, index: TCompRes
first: Int128
gen(p, n[0], address)
gen(p, n[1], index)
let (m1, tmp1) = maybeMakeTemp(p, n[0], address)
@@ -542,7 +542,7 @@ template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string,
# $1 and $2 in the `frmt` string bind to lhs and rhs of the expr,
# if $3 or $4 are present they will be substituted with temps for
# lhs and rhs respectively
var x, y: TCompRes = default(TCompRes)
var x, y: TCompRes
useMagic(p, magic)
gen(p, n[1], x)
gen(p, n[2], y)
@@ -572,7 +572,7 @@ proc signedTrimmer(size: BiggestInt): string =
proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
reassign: static[bool] = false) =
var x, y: TCompRes = default(TCompRes)
var x, y: TCompRes
gen(p, n[1], x)
gen(p, n[2], y)
let size = n[1].typ.skipTypes(abstractRange).size
@@ -611,8 +611,8 @@ template unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
var
x, y: TCompRes = default(TCompRes)
xLoc, yLoc: Rope = ""
x, y: TCompRes
xLoc, yLoc: Rope
let i = ord(optOverflowCheck notin p.options)
useMagic(p, jsMagics[op][i])
if n.len > 2:
@@ -676,38 +676,8 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
applyFormat("modInt64($1, $2)", "$1 % $2")
else:
applyFormat("modInt($1, $2)", "Math.trunc($1 % $2)")
of mSucc:
let typ = n[1].typ.skipTypes(abstractVarRange)
case typ.kind
of tyUInt..tyUInt32:
binaryUintExpr(p, n, r, "+")
of tyUInt64:
if optJsBigInt64 in p.config.globalOptions:
applyFormat("BigInt.asUintN(64, $1 + BigInt($2))")
else: binaryUintExpr(p, n, r, "+")
elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
if optOverflowCheck notin p.options:
applyFormat("BigInt.asIntN(64, $1 + BigInt($2))")
else: binaryExpr(p, n, r, "addInt64", "addInt64($1, BigInt($2))")
else:
if optOverflowCheck notin p.options: applyFormat("$1 + $2")
else: binaryExpr(p, n, r, "addInt", "addInt($1, $2)")
of mPred:
let typ = n[1].typ.skipTypes(abstractVarRange)
case typ.kind
of tyUInt..tyUInt32:
binaryUintExpr(p, n, r, "-")
of tyUInt64:
if optJsBigInt64 in p.config.globalOptions:
applyFormat("BigInt.asUintN(64, $1 - BigInt($2))")
else: binaryUintExpr(p, n, r, "-")
elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
if optOverflowCheck notin p.options:
applyFormat("BigInt.asIntN(64, $1 - BigInt($2))")
else: binaryExpr(p, n, r, "subInt64", "subInt64($1, BigInt($2))")
else:
if optOverflowCheck notin p.options: applyFormat("$1 - $2")
else: binaryExpr(p, n, r, "subInt", "subInt($1, $2)")
of mSucc: applyFormat("addInt($1, $2)", "($1 + $2)")
of mPred: applyFormat("subInt($1, $2)", "($1 - $2)")
of mAddF64: applyFormat("($1 + $2)", "($1 + $2)")
of mSubF64: applyFormat("($1 - $2)", "($1 - $2)")
of mMulF64: applyFormat("($1 * $2)", "($1 * $2)")
@@ -833,7 +803,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
if mapType(n[1].typ) != etyBaseIndex:
arithAux(p, n, r, op)
else:
var x, y: TCompRes = default(TCompRes)
var x, y: TCompRes
gen(p, n[1], x)
gen(p, n[2], y)
r.res = "($# == $# && $# == $#)" % [x.address, y.address, x.res, y.res]
@@ -866,7 +836,7 @@ proc genLineDir(p: PProc, n: PNode) =
p.previousFileName = currentFileName
proc genWhileStmt(p: PProc, n: PNode) =
var cond: TCompRes = default(TCompRes)
var cond: TCompRes
internalAssert p.config, isEmptyType(n.typ)
genLineDir(p, n)
inc(p.unique)
@@ -926,7 +896,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
p.body.add("++excHandler;\L")
var tmpFramePtr = rope"F"
lineF(p, "try {$n", [])
var a: TCompRes
var a: TCompRes = default(TCompRes)
gen(p, n[0], a)
moveInto(p, a, r)
var generalCatchBranchExists = false
@@ -961,7 +931,6 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
elif it.kind == nkType:
throwObj = it
else:
throwObj = nil
internalError(p.config, n.info, "genTryStmt")
if orExpr != "": orExpr.add("||")
@@ -1002,7 +971,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
proc genRaiseStmt(p: PProc, n: PNode) =
if n[0].kind != nkEmpty:
var a: TCompRes = default(TCompRes)
var a: TCompRes
gen(p, n[0], a)
let typ = skipTypes(n[0].typ, abstractPtrs)
genLineDir(p, n)
@@ -1016,7 +985,7 @@ proc genRaiseStmt(p: PProc, n: PNode) =
proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
var
a, b, cond, stmt: TCompRes = default(TCompRes)
a, b, cond, stmt: TCompRes
genLineDir(p, n)
gen(p, n[0], cond)
let typeKind = skipTypes(n[0].typ, abstractVar).kind
@@ -1150,7 +1119,7 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) =
if false:
discard
else:
var r = default(TCompRes)
var r: TCompRes
gen(p, it, r)
if it.typ.kind == tyPointer:
@@ -1166,13 +1135,13 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) =
p.body.add(r.rdLoc)
else:
var r: TCompRes = default(TCompRes)
var r: TCompRes
gen(p, it, r)
p.body.add(r.rdLoc)
p.body.add "\L"
proc genIf(p: PProc, n: PNode, r: var TCompRes) =
var cond, stmt: TCompRes = default(TCompRes)
var cond, stmt: TCompRes
var toClose = 0
if not isEmptyType(n.typ):
r.kind = resVal
@@ -1209,7 +1178,6 @@ proc generateHeader(p: PProc, typ: PType): Rope =
result.add("_Idx")
proc countJsParams(typ: PType): int =
result = 0
for i in 1..<typ.n.len:
assert(typ.n[i].kind == nkSym)
var param = typ.n[i].sym
@@ -1230,10 +1198,10 @@ proc needsNoCopy(p: PProc; y: PNode): bool =
return y.kind in nodeKindsNeedNoCopy or
((mapType(y.typ) != etyBaseIndex or (y.kind == nkSym and y.sym.kind == skParam)) and
(skipTypes(y.typ, abstractInst).kind in
{tyRef, tyPtr, tyLent, tyVar, tyCstring, tyProc, tyOwned} + IntegralTypes))
{tyRef, tyPtr, tyLent, tyVar, tyCstring, tyProc, tyOwned, tyOpenArray} + IntegralTypes))
proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
var a, b: TCompRes = default(TCompRes)
var a, b: TCompRes
var xtyp = mapType(p, x.typ)
# disable `[]=` for cstring
@@ -1312,7 +1280,7 @@ proc genFastAsgn(p: PProc, n: PNode) =
genAsgnAux(p, n[0], n[1], noCopyNeeded=noCopy)
proc genSwap(p: PProc, n: PNode) =
var a, b: TCompRes = default(TCompRes)
var a, b: TCompRes
gen(p, n[1], a)
gen(p, n[2], b)
var tmp = p.getTemp(false)
@@ -1330,12 +1298,10 @@ proc getFieldPosition(p: PProc; f: PNode): int =
case f.kind
of nkIntLit..nkUInt64Lit: result = int(f.intVal)
of nkSym: result = f.sym.position
else:
result = 0
internalError(p.config, f.info, "genFieldPosition")
else: internalError(p.config, f.info, "genFieldPosition")
proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes = default(TCompRes)
var a: TCompRes
r.typ = etyBaseIndex
let b = if n.kind == nkHiddenAddr: n[0] else: n
gen(p, b[0], a)
@@ -1399,10 +1365,10 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
internalAssert p.config, disc.kind == skField
if disc.loc.r == "": disc.loc.r = mangleName(p.module, disc)
var setx: TCompRes = default(TCompRes)
var setx: TCompRes
gen(p, checkExpr[1], setx)
var obj: TCompRes = default(TCompRes)
var obj: TCompRes
gen(p, accessExpr[0], obj)
# Avoid evaluating the LHS twice (one to read the discriminant and one to read
# the field)
@@ -1428,8 +1394,8 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
var
a, b: TCompRes = default(TCompRes)
first: Int128 = Zero
a, b: TCompRes
first: Int128
r.typ = etyBaseIndex
let m = if n.kind == nkHiddenAddr: n[0] else: n
gen(p, m[0], a)
@@ -1553,15 +1519,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:
@@ -1676,7 +1635,7 @@ proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
if t == etyObject or it.typ.kind == tyLent:
gen(p, it, r)
else:
var a: TCompRes = default(TCompRes)
var a: TCompRes
gen(p, it, a)
r.kind = a.kind
r.typ = mapType(p, n.typ)
@@ -1693,7 +1652,7 @@ proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
internalError(p.config, n.info, "genDeref")
proc genArgNoParam(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes = default(TCompRes)
var a: TCompRes
gen(p, n, a)
if a.typ == etyBaseIndex:
r.res.add(a.address)
@@ -1703,7 +1662,7 @@ proc genArgNoParam(p: PProc, n: PNode, r: var TCompRes) =
r.res.add(a.res)
proc genArg(p: PProc, n: PNode, param: PSym, r: var TCompRes; emitted: ptr int = nil) =
var a: TCompRes = default(TCompRes)
var a: TCompRes
gen(p, n, a)
if skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs} and
a.typ == etyBaseIndex:
@@ -1827,7 +1786,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
r.address = ""
r.typ = etyNone
r.res.add(".")
var op: TCompRes = default(TCompRes)
var op: TCompRes
gen(p, n[0], op)
r.res.add(op.res)
genArgs(p, n, r, 2)
@@ -1975,7 +1934,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
result.add("}")
if indirect: result = "[$1]" % [result]
of tyObject:
var initList: Rope = ""
var initList: Rope
createObjInitList(p, t, initIntSet(), initList)
result = ("({$1})") % [initList]
if indirect: result = "[$1]" % [result]
@@ -1986,7 +1945,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
result = putToSeq("null", indirect)
of tySequence, tyString:
result = putToSeq("[]", indirect)
of tyCstring, tyProc:
of tyCstring, tyProc, tyOpenArray:
result = putToSeq("null", indirect)
of tyStatic:
if t.n != nil:
@@ -2002,7 +1961,7 @@ template returnType: untyped = ""
proc genVarInit(p: PProc, v: PSym, n: PNode) =
var
a: TCompRes = default(TCompRes)
a: TCompRes
s: Rope
varCode: string
varName = mangleName(p.module, v)
@@ -2103,7 +2062,7 @@ proc genConstant(p: PProc, c: PSym) =
p.body = oldBody
proc genNew(p: PProc, n: PNode) =
var a: TCompRes = default(TCompRes)
var a: TCompRes
gen(p, n[1], a)
var t = skipTypes(n[1].typ, abstractVar)[0]
if mapType(t) == etyObject:
@@ -2114,7 +2073,7 @@ proc genNew(p: PProc, n: PNode) =
lineF(p, "$1 = [[$2], 0];$n", [a.rdLoc, createVar(p, t, false)])
proc genNewSeq(p: PProc, n: PNode) =
var x, y: TCompRes = default(TCompRes)
var x, y: TCompRes
gen(p, n[1], x)
gen(p, n[2], y)
let t = skipTypes(n[1].typ, abstractVar)[0]
@@ -2132,7 +2091,7 @@ proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
else: internalError(p.config, n.info, "genOrd")
proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes = default(TCompRes)
var a: TCompRes
gen(p, n[1], a)
r.kind = resExpr
@@ -2157,7 +2116,7 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = "") =
useMagic(p, magic)
r.res.add(magic & "(")
var a: TCompRes = default(TCompRes)
var a: TCompRes
gen(p, n[1], a)
if magic == "reprAny":
@@ -2204,7 +2163,7 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
r.kind = resExpr
proc genOf(p: PProc, n: PNode, r: var TCompRes) =
var x: TCompRes = default(TCompRes)
var x: TCompRes
let t = skipTypes(n[2].typ,
abstractVarRange+{tyRef, tyPtr, tyLent, tyTypeDesc, tyOwned})
gen(p, n[1], x)
@@ -2220,7 +2179,7 @@ proc genDefault(p: PProc, n: PNode; r: var TCompRes) =
r.kind = resExpr
proc genReset(p: PProc, n: PNode) =
var x: TCompRes = default(TCompRes)
var x: TCompRes
useMagic(p, "genericReset")
gen(p, n[1], x)
if x.typ == etyBaseIndex:
@@ -2231,7 +2190,7 @@ proc genReset(p: PProc, n: PNode) =
genTypeInfo(p, n[1].typ), tmp])
proc genMove(p: PProc; n: PNode; r: var TCompRes) =
var a: TCompRes = default(TCompRes)
var a: TCompRes
r.kind = resVal
r.res = p.getTemp()
gen(p, n[1], a)
@@ -2240,14 +2199,14 @@ proc genMove(p: PProc; n: PNode; r: var TCompRes) =
#lineF(p, "$1 = $2;$n", [dest.rdLoc, src.rdLoc])
proc genDup(p: PProc; n: PNode; r: var TCompRes) =
var a: TCompRes = default(TCompRes)
var a: TCompRes
r.kind = resVal
r.res = p.getTemp()
gen(p, n[1], a)
lineF(p, "$1 = $2;$n", [r.rdLoc, a.rdLoc])
proc genJSArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes = default(TCompRes)
var a: TCompRes
r.res = rope("[")
r.kind = resExpr
for i in 0 ..< n.len:
@@ -2278,7 +2237,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
binaryExpr(p, n, r, "addChar",
"addChar($1, $2);")
of mAppendStrStr:
var lhs, rhs: TCompRes = default(TCompRes)
var lhs, rhs: TCompRes
gen(p, n[1], lhs)
gen(p, n[2], rhs)
@@ -2291,7 +2250,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
r.res = "$1.push.apply($3, $2);" % [a, rhs.rdLoc, tmp]
r.kind = resExpr
of mAppendSeqElem:
var x, y: TCompRes = default(TCompRes)
var x, y: TCompRes
gen(p, n[1], x)
gen(p, n[2], y)
if mapType(n[2].typ) == etyBaseIndex:
@@ -2319,7 +2278,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
if mapType(n[1].typ) != etyBaseIndex:
unaryExpr(p, n, r, "", "($1 == null)")
else:
var x: TCompRes = default(TCompRes)
var x: TCompRes
gen(p, n[1], x)
r.res = "($# == null && $# === 0)" % [x.address, x.res]
of mEnumToStr: genRepr(p, n, r)
@@ -2330,7 +2289,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
if n[1].kind == nkBracket:
genJSArrayConstr(p, n[1], r)
else:
var x: TCompRes = default(TCompRes)
var x: TCompRes
gen(p, n[1], x)
useMagic(p, "nimCopy")
r.res = "nimCopy(null, $1, $2)" % [x.rdLoc, genTypeInfo(p, n.typ)]
@@ -2339,7 +2298,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mDestroy, mTrace: discard "ignore calls to the default destructor"
of mOrd: genOrd(p, n, r)
of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray:
var x: TCompRes = default(TCompRes)
var x: TCompRes
gen(p, n[1], x)
if skipTypes(n[1].typ, abstractInst).kind == tyCstring:
let (a, tmp) = maybeMakeTemp(p, n[1], x)
@@ -2348,7 +2307,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
r.res = "($1).length" % [x.rdLoc]
r.kind = resExpr
of mHigh:
var x: TCompRes = default(TCompRes)
var x: TCompRes
gen(p, n[1], x)
if skipTypes(n[1].typ, abstractInst).kind == tyCstring:
let (a, tmp) = maybeMakeTemp(p, n[1], x)
@@ -2380,7 +2339,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of tyUInt64:
if optJsBigInt64 in p.config.globalOptions:
binaryExpr(p, n, r, "", "$1 = BigInt.asUintN(64, $3 - BigInt($2))", true)
else: binaryUintExpr(p, n, r, "-", true)
else: binaryUintExpr(p, n, r, "+", true)
elif typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
if optOverflowCheck notin p.options:
binaryExpr(p, n, r, "", "$1 = BigInt.asIntN(64, $3 - BigInt($2))", true)
@@ -2393,7 +2352,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
"""if ($1.length < $2) { for (var i = $3.length; i < $4; ++i) $3.push(0); }
else {$3.length = $4; }""")
of mSetLengthSeq:
var x, y: TCompRes = default(TCompRes)
var x, y: TCompRes
gen(p, n[1], x)
gen(p, n[2], y)
let t = skipTypes(n[1].typ, abstractVar)[0]
@@ -2432,7 +2391,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
genCall(p, n, r)
of mSlice:
# arr.slice([begin[, end]]): 'end' is exclusive
var x, y, z: TCompRes = default(TCompRes)
var x, y, z: TCompRes
gen(p, n[1], x)
gen(p, n[2], y)
gen(p, n[3], z)
@@ -2450,7 +2409,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
var
a, b: TCompRes = default(TCompRes)
a, b: TCompRes
useMagic(p, "setConstr")
r.res = rope("setConstr(")
r.kind = resExpr
@@ -2487,7 +2446,7 @@ proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
# generate typed array
# for example Nim generates `new Uint8Array([1, 2, 3])` for `[byte(1), 2, 3]`
# TODO use `set` or loop to initialize typed array which improves performances in some situations
var a: TCompRes = default(TCompRes)
var a: TCompRes
r.res = "new $1([" % [rope(jsTyp)]
r.kind = resExpr
for i in 0 ..< n.len:
@@ -2499,7 +2458,7 @@ proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
genJSArrayConstr(p, n, r)
proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes = default(TCompRes)
var a: TCompRes
r.res = rope("{")
r.kind = resExpr
for i in 0..<n.len:
@@ -2518,9 +2477,9 @@ proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
r.res.add("}")
proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes = default(TCompRes)
var a: TCompRes
r.kind = resExpr
var initList : Rope = ""
var initList : Rope
var fieldIDs = initIntSet()
let nTyp = n.typ.skipTypes(abstractInst)
for i in 1..<n.len:
@@ -2594,23 +2553,16 @@ proc upConv(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n[0], r) # XXX
proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) =
var a, b: TCompRes = default(TCompRes)
var a, b: TCompRes
gen(p, n[0], r)
let src = skipTypes(n[0].typ, abstractVarRange)
let dest = skipTypes(n.typ, abstractVarRange)
if optRangeCheck notin p.options:
return
elif dest.kind in {tyUInt..tyUInt64} and checkUnsignedConversions notin p.config.legacyFeatures:
if src.kind in {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
r.res = "BigInt.asUintN($1, $2)" % [$(dest.size * 8), r.res]
else:
r.res = "BigInt.asUintN($1, BigInt($2))" % [$(dest.size * 8), r.res]
if not (dest.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions):
r.res = "Number($1)" % [r.res]
if src.kind in {tyInt64, tyUInt64} and dest.kind notin {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
r.res = "Number($1)" % [r.res]
if optRangeCheck notin p.options or (dest.kind in {tyUInt..tyUInt64} and
checkUnsignedConversions notin p.config.legacyFeatures):
discard "XXX maybe emit masking instructions here"
else:
if src.kind in {tyInt64, tyUInt64} and dest.kind notin {tyInt64, tyUInt64} and optJsBigInt64 in p.config.globalOptions:
# we do a range check anyway, so it's ok if the number gets rounded
r.res = "Number($1)" % [r.res]
gen(p, n[1], a)
gen(p, n[2], b)
useMagic(p, "chckRange")
@@ -2687,10 +2639,9 @@ proc optionalLine(p: Rope): Rope =
proc genProc(oldProc: PProc, prc: PSym): Rope =
## Generate a JS procedure ('function').
result = ""
var
resultSym: PSym
a: TCompRes = default(TCompRes)
a: TCompRes
#if gVerbosity >= 3:
# echo "BEGIN generating code for: " & prc.name.s
var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options)
@@ -2718,7 +2669,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
else:
returnStmt = "return $#;$n" % [a.res]
var transformedBody = transformBody(p.module.graph, p.module.idgen, prc, {})
var transformedBody = transformBody(p.module.graph, p.module.idgen, prc, dontUseCache)
if sfInjectDestructors in prc.flags:
transformedBody = injectDestructorCalls(p.module.graph, p.module.idgen, prc, transformedBody)
@@ -2770,7 +2721,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
# echo "END generated code for: " & prc.name.s
proc genStmt(p: PProc, n: PNode) =
var r: TCompRes = default(TCompRes)
var r: TCompRes
gen(p, n, r)
if r.res != "": lineF(p, "$#;$n", [r.res])
@@ -2901,11 +2852,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
r.res = rope"Infinity"
of fcNegInf:
r.res = rope"-Infinity"
else:
if n.typ.skipTypes(abstractVarRange).kind == tyFloat32:
r.res.addFloatRoundtrip(f.float32)
else:
r.res.addFloatRoundtrip(f)
else: r.res = rope(f.toStrMaxPrecision)
r.kind = resExpr
of nkCallKinds:
if isEmptyType(n.typ):
@@ -3006,11 +2953,13 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
proc newModule(g: ModuleGraph; module: PSym): BModule =
## Create a new JS backend module node.
new(result)
result.module = module
result.sigConflicts = initCountTable[SigHash]()
if g.backend == nil:
g.backend = newGlobals()
result = BModule(module: module, sigConflicts: initCountTable[SigHash](),
graph: g, config: g.config
)
result.graph = g
result.config = g.config
if sfSystemModule in module.flags:
PGlobals(g.backend).inSystem = true
@@ -3097,8 +3046,9 @@ proc wholeCode(graph: ModuleGraph; m: BModule): Rope =
var p = newInitProc(globals, m)
attachProc(p, prc)
generateIfMethodDispatchers(graph, m.idgen)
for prc in getDispatchers(graph):
var disp = generateMethodDispatchers(graph, m.idgen)
for i in 0..<disp.len:
let prc = disp[i].sym
if not globals.generatedSyms.containsOrIncl(prc.id):
var p = newInitProc(globals, m)
attachProc(p, prc)

View File

@@ -10,12 +10,10 @@
# This file implements lambda lifting for the transformator.
import
options, ast, astalgo, msgs,
idents, renderer, types, magicsys, lowerings, modulegraphs, lineinfos,
intsets, strutils, options, ast, astalgo, msgs,
idents, renderer, types, magicsys, lowerings, tables, modulegraphs, lineinfos,
transf, liftdestructors, typeallowed
import std/[strutils, tables, intsets]
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -135,10 +133,10 @@ proc createClosureIterStateType*(g: ModuleGraph; iter: PSym; idgen: IdGenerator)
var n = newNodeI(nkRange, iter.info)
n.add newIntNode(nkIntLit, -1)
n.add newIntNode(nkIntLit, 0)
result = newType(tyRange, idgen, iter)
result = newType(tyRange, nextTypeId(idgen), iter)
result.n = n
var intType = nilOrSysInt(g)
if intType.isNil: intType = newType(tyInt, idgen, iter)
if intType.isNil: intType = newType(tyInt, nextTypeId(idgen), iter)
rawAddSon(result, intType)
proc createStateField(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym =
@@ -189,8 +187,6 @@ proc getEnvParam*(routine: PSym): PSym =
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
result = hidden.sym
assert sfFromGeneric in result.flags
else:
result = nil
proc interestingVar(s: PSym): bool {.inline.} =
result = s.kind in {skVar, skLet, skTemp, skForVar, skParam, skResult} and
@@ -203,8 +199,6 @@ proc illegalCapture(s: PSym): bool {.inline.} =
proc isInnerProc(s: PSym): bool =
if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator} and s.magic == mNone:
result = s.skipGenericOwner.kind in routineKinds
else:
result = false
proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
# Bugfix: unfortunately we cannot use 'nkFastAsgn' here as that would
@@ -264,8 +258,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PN
let iter = n.sym
assert iter.isIterator
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
result = newNodeIT(nkStmtListExpr, n.info, iter.typ)
let hp = getHiddenParam(g, iter)
var env: PNode
if owner.isIterator:
@@ -323,10 +316,12 @@ type
idgen: IdGenerator
proc initDetectionPass(g: ModuleGraph; fn: PSym; idgen: IdGenerator): DetectionPass =
result = DetectionPass(processed: toIntSet([fn.id]),
capturedVars: initIntSet(), ownerToType: initTable[int, PType](),
graph: g, idgen: idgen
)
result.processed = initIntSet()
result.capturedVars = initIntSet()
result.ownerToType = initTable[int, PType]()
result.processed.incl(fn.id)
result.graph = g
result.idgen = idgen
discard """
proc outer =
@@ -342,7 +337,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
info: TLineInfo): PType =
result = c.ownerToType.getOrDefault(owner.id)
if result.isNil:
result = newType(tyRef, c.idgen, owner)
result = newType(tyRef, nextTypeId(c.idgen), owner)
let obj = createEnvObj(c.graph, c.idgen, owner, info)
rawAddSon(result, obj)
c.ownerToType[owner.id] = result
@@ -350,7 +345,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
proc asOwnedRef(c: var DetectionPass; t: PType): PType =
if optOwnedRefs in c.graph.config.globalOptions:
assert t.kind == tyRef
result = newType(tyOwned, c.idgen, t.owner)
result = newType(tyOwned, nextTypeId(c.idgen), t.owner)
result.flags.incl tfHasOwned
result.rawAddSon t
else:
@@ -359,7 +354,7 @@ proc asOwnedRef(c: var DetectionPass; t: PType): PType =
proc getEnvTypeForOwnerUp(c: var DetectionPass; owner: PSym;
info: TLineInfo): PType =
var r = c.getEnvTypeForOwner(owner, info)
result = newType(tyPtr, c.idgen, owner)
result = newType(tyPtr, nextTypeId(c.idgen), owner)
rawAddSon(result, r.skipTypes({tyOwned, tyRef, tyPtr}))
proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
@@ -451,7 +446,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
if innerProc:
if s.isIterator: c.somethingToDo = true
if not c.processed.containsOrIncl(s.id):
let body = transformBody(c.graph, c.idgen, s, {useCache})
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
@@ -542,8 +537,9 @@ type
unownedEnvVars: Table[int, PNode] # only required for --newruntime
proc initLiftingPass(fn: PSym): LiftingPass =
result = LiftingPass(processed: toIntSet([fn.id]),
envVars: initTable[int, PNode]())
result.processed = initIntSet()
result.processed.incl(fn.id)
result.envVars = initTable[int, PNode]()
proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
let s = n.sym
@@ -730,7 +726,6 @@ proc symToClosure(n: PNode; owner: PSym; d: var DetectionPass;
# direct dependency, so use the outer's env variable:
result = makeClosure(d.graph, d.idgen, s, setupEnvVar(owner, d, c, n.info), n.info)
else:
result = nil
let available = getHiddenParam(d.graph, owner)
let wanted = getHiddenParam(d.graph, s).typ
# ugh: call through some other inner proc;
@@ -757,7 +752,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass;
# echo renderTree(s.getBody, {renderIds})
let oldInContainer = c.inContainer
c.inContainer = 0
var body = transformBody(d.graph, d.idgen, s, {})
var body = transformBody(d.graph, d.idgen, s, dontUseCache)
body = liftCapturedVars(body, s, d, c)
if c.envVars.getOrDefault(s.id).isNil:
s.transformedBody = body
@@ -881,7 +876,7 @@ proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType;
fn.typ.callConv = oldCC
proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
idgen: IdGenerator; flags: TransformFlags): PNode =
idgen: IdGenerator, force: bool): PNode =
# XXX backend == backendJs does not suffice! The compiletime stuff needs
# the transformation even when compiling to JS ...
@@ -890,7 +885,7 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
if body.kind == nkEmpty or (
g.config.backend == backendJs and not isCompileTime) or
(fn.skipGenericOwner.kind != skModule and force notin flags):
(fn.skipGenericOwner.kind != skModule and not force):
# ignore forward declaration:
result = body
@@ -958,7 +953,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym):
result = newNodeI(nkStmtList, body.info)
# static binding?
var env: PSym = nil
var env: PSym
let op = call[0]
if op.kind == nkSym and op.sym.isIterator:
# createClosure()
@@ -993,12 +988,15 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym):
# gather vars in a tuple:
var v2 = newNodeI(nkLetSection, body.info)
var vpart = newNodeI(if body.len == 3: nkIdentDefs else: nkVarTuple, body.info)
for i in 0..<body.len-2:
if body[i].kind == nkSym:
body[i].sym.transitionToLet()
vpart.add body[i]
if body.len == 3 and body[0].kind == nkVarTuple:
vpart = body[0] # fixes for (i,j) in walk() # bug #15924
else:
for i in 0..<body.len-2:
if body[i].kind == nkSym:
body[i].sym.transitionToLet()
vpart.add body[i]
vpart.add newNodeI(nkEmpty, body.info) # no explicit type
vpart.add newNodeI(nkEmpty, body.info) # no explicit type
if not env.isNil:
call[0] = makeClosure(g, idgen, call[0].sym, env.newSymNode, body.info)
vpart.add call

View File

@@ -16,10 +16,8 @@
# DOS or Macintosh text files, even when it is not the native format.
import
options, msgs, platform, idents, nimlexbase, llstream,
wordrecg, lineinfos, pathutils
import std/[hashes, parseutils, strutils]
hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
wordrecg, lineinfos, pathutils, parseutils
when defined(nimPreviewSlimSystem):
import std/[assertions, formatfloat]
@@ -122,6 +120,7 @@ type
# this is needed because scanning comments
# needs so much look-ahead
currLineIndent*: int
strongSpaces*, allowTabs*: bool
errorHandler*: ErrorHandler
cache*: IdentCache
when defined(nimsuggest):
@@ -149,11 +148,9 @@ proc isNimIdentifier*(s: string): bool =
var i = 1
while i < sLen:
if s[i] == '_': inc(i)
if i < sLen and s[i] notin SymChars: return false
if i < sLen and s[i] notin SymChars: return
inc(i)
result = true
else:
result = false
proc `$`*(tok: Token): string =
case tok.tokType
@@ -175,6 +172,32 @@ proc printTok*(conf: ConfigRef; tok: Token) =
# xxx factor with toLocation
msgWriteln(conf, $tok.line & ":" & $tok.col & "\t" & $tok.tokType & " " & $tok)
proc initToken*(L: var Token) =
L.tokType = tkInvalid
L.iNumber = 0
L.indent = 0
L.spacing = {}
L.literal = ""
L.fNumber = 0.0
L.base = base10
L.ident = nil
when defined(nimpretty):
L.commentOffsetA = 0
L.commentOffsetB = 0
proc fillToken(L: var Token) =
L.tokType = tkInvalid
L.iNumber = 0
L.indent = 0
L.spacing = {}
setLen(L.literal, 0)
L.fNumber = 0.0
L.base = base10
L.ident = nil
when defined(nimpretty):
L.commentOffsetA = 0
L.commentOffsetB = 0
proc openLexer*(lex: var Lexer, fileIdx: FileIndex, inputstream: PLLStream;
cache: IdentCache; config: ConfigRef) =
openBaseLexer(lex, inputstream)
@@ -514,8 +537,8 @@ proc getNumber(L: var Lexer, result: var Token) =
of floatTypes:
result.fNumber = parseFloat(result.literal)
of tkUInt64Lit, tkUIntLit:
var iNumber: uint64 = uint64(0)
var len: int = 0
var iNumber: uint64
var len: int
try:
len = parseBiggestUInt(result.literal, iNumber)
except ValueError:
@@ -524,8 +547,8 @@ proc getNumber(L: var Lexer, result: var Token) =
raise newException(ValueError, "invalid integer: " & result.literal)
result.iNumber = cast[int64](iNumber)
else:
var iNumber: int64 = int64(0)
var len: int = 0
var iNumber: int64
var len: int
try:
len = parseBiggestInt(result.literal, iNumber)
except ValueError:
@@ -771,7 +794,7 @@ proc getString(L: var Lexer, tok: var Token, mode: StringMode) =
if mode != normal: tok.tokType = tkRStrLit
else: tok.tokType = tkStrLit
while true:
let c = L.buf[pos]
var c = L.buf[pos]
if c == '\"':
if mode != normal and L.buf[pos+1] == '\"':
inc(pos, 2)
@@ -797,7 +820,7 @@ proc getCharacter(L: var Lexer; tok: var Token) =
tokenBegin(tok, L.bufpos)
let startPos = L.bufpos
inc(L.bufpos) # skip '
let c = L.buf[L.bufpos]
var c = L.buf[L.bufpos]
case c
of '\0'..pred(' '), '\'':
lexMessage(L, errGenerated, "invalid character literal")
@@ -915,7 +938,7 @@ proc getOperator(L: var Lexer, tok: var Token) =
tokenBegin(tok, pos)
var h: Hash = 0
while true:
let c = L.buf[pos]
var c = L.buf[pos]
if c in OpChars:
h = h !& ord(c)
inc(pos)
@@ -983,6 +1006,22 @@ proc getPrecedence*(tok: Token): int =
of tkOr, tkXor, tkPtr, tkRef: result = 3
else: return -10
proc newlineFollows*(L: Lexer): bool =
var pos = L.bufpos
while true:
case L.buf[pos]
of ' ', '\t':
inc(pos)
of CR, LF:
result = true
break
of '#':
inc(pos)
if L.buf[pos] == '#': inc(pos)
if L.buf[pos] != '[': return true
else:
break
proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int;
isDoc: bool) =
var pos = start
@@ -1074,7 +1113,9 @@ proc scanComment(L: var Lexer, tok: var Token) =
toStrip = 0
else: # found first non-whitespace character
stripInit = true
var lastBackslash = -1
while L.buf[pos] notin {CR, LF, nimlexbase.EndOfFile}:
if L.buf[pos] == '\\': lastBackslash = pos+1
tok.literal.add(L.buf[pos])
inc(pos)
tokenEndIgnore(tok, pos)
@@ -1117,7 +1158,7 @@ proc skip(L: var Lexer, tok: var Token) =
inc(pos)
tok.spacing.incl(tsLeading)
of '\t':
lexMessagePos(L, errGenerated, pos, "tabs are not allowed, use spaces instead")
if not L.allowTabs: lexMessagePos(L, errGenerated, pos, "tabs are not allowed, use spaces instead")
inc(pos)
of CR, LF:
tokenEndPrevious(tok, pos)
@@ -1185,7 +1226,7 @@ proc rawGetTok*(L: var Lexer, tok: var Token) =
L.previousToken.line = tok.line.uint16
L.previousToken.col = tok.col.int16
reset(tok)
fillToken(tok)
if L.indentAhead >= 0:
tok.indent = L.indentAhead
L.currLineIndent = L.indentAhead
@@ -1197,7 +1238,7 @@ proc rawGetTok*(L: var Lexer, tok: var Token) =
if tok.tokType == tkComment:
L.indentAhead = L.currLineIndent
return
let c = L.buf[L.bufpos]
var c = L.buf[L.bufpos]
tok.line = L.lineNumber
tok.col = getColNumber(L, L.bufpos)
if c in SymStartChars - {'r', 'R'} - UnicodeOperatorStartChars:
@@ -1353,9 +1394,9 @@ proc rawGetTok*(L: var Lexer, tok: var Token) =
proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream;
cache: IdentCache; config: ConfigRef): int =
result = 0
var lex: Lexer = default(Lexer)
var tok: Token = default(Token)
var lex: Lexer
var tok: Token
initToken(tok)
openLexer(lex, fileIdx, inputstream, cache, config)
var prevToken = tkEof
while tok.tokType != tkEof:
@@ -1368,11 +1409,11 @@ proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream;
proc getPrecedence*(ident: PIdent): int =
## assumes ident is binary operator already
let
tokType =
if ident.id in ord(tokKeywordLow) - ord(tkSymbol)..ord(tokKeywordHigh) - ord(tkSymbol):
TokType(ident.id + ord(tkSymbol))
else: tkOpr
tok = Token(ident: ident, tokType: tokType)
var tok: Token
initToken(tok)
tok.ident = ident
tok.tokType =
if tok.ident.id in ord(tokKeywordLow) - ord(tkSymbol)..ord(tokKeywordHigh) - ord(tkSymbol):
TokType(tok.ident.id + ord(tkSymbol))
else: tkOpr
getPrecedence(tok)

View File

@@ -11,9 +11,8 @@
## (`=sink`, `=copy`, `=destroy`, `=deepCopy`, `=wasMoved`, `=dup`).
import modulegraphs, lineinfos, idents, ast, renderer, semdata,
sighashes, lowerings, options, types, msgs, magicsys, ccgutils
sighashes, lowerings, options, types, msgs, magicsys, tables, ccgutils
import std/tables
from trees import isCaseObj
when defined(nimPreviewSlimSystem):
@@ -157,7 +156,7 @@ proc genWasMovedCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
result.add(newSymNode(op))
result.add genAddr(c, x)
proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) =
proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool, enforceWasMoved = false) =
case n.kind
of nkSym:
if c.filterDiscriminator != nil: return
@@ -167,6 +166,8 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
enforceDefaultOp:
defaultOp(c, f.typ, body, x.dotField(f), b)
else:
if enforceWasMoved:
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x.dotField(f))
fillBody(c, f.typ, body, x.dotField(f), b)
of nkNilLit: discard
of nkRecCase:
@@ -205,7 +206,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
branch[^1] = newNodeI(nkStmtList, c.info)
fillBodyObj(c, n[i].lastSon, branch[^1], x, y,
enforceDefaultOp = localEnforceDefaultOp)
enforceDefaultOp = localEnforceDefaultOp, enforceWasMoved = c.kind == attachedAsgn)
if branch[^1].len == 0: inc emptyBranches
caseStmt.add(branch)
if emptyBranches != n.len-1:
@@ -216,14 +217,38 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
fillBodyObj(c, n[0], body, x, y, enforceDefaultOp = false)
c.filterDiscriminator = oldfilterDiscriminator
of nkRecList:
for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp)
# destroys in reverse order #24719
if c.kind == attachedDestructor:
for i in countdown(n.len-1, 0):
fillBodyObj(c, n[i], body, x, y, enforceDefaultOp, enforceWasMoved)
else:
for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp, enforceWasMoved)
else:
illFormedAstLocal(n, c.g.config)
proc fillBodyObjTImpl(c: var TLiftCtx; t: PType, body, x, y: PNode) =
if t.len > 0 and t[0] != nil:
fillBody(c, skipTypes(t[0], abstractPtrs), body, x, y)
fillBodyObj(c, t.n, body, x, y, enforceDefaultOp = false)
template fillBase =
if t.len > 0 and t[0] != nil:
let dest = newNodeIT(nkHiddenSubConv, c.info, t[0])
dest.add newNodeI(nkEmpty, c.info)
dest.add x
var src = y
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink}:
src = newNodeIT(nkHiddenSubConv, c.info, t[0])
src.add newNodeI(nkEmpty, c.info)
src.add y
fillBody(c, skipTypes(t[0], abstractPtrs), body, dest, src)
template fillFields =
fillBodyObj(c, t.n, body, x, y, enforceDefaultOp = false)
if c.kind == attachedDestructor:
# destroys in reverse order #24719
fillFields()
fillBase()
else:
fillBase()
fillFields()
proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
var hasCase = isCaseObj(t.n)
@@ -279,6 +304,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
c.kind = attachedDestructor
fillBodyObjTImpl(c, t, body, blob, y)
c.kind = prevKind
else:
fillBodyObjTImpl(c, t, body, x, y)
@@ -302,7 +328,7 @@ proc newHookCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
result.add newSymNode(op)
if sfNeverRaises notin op.flags:
c.canRaise = true
if op.typ[1].kind == tyVar:
if op.typ.sons[1].kind == tyVar:
result.add genAddr(c, x)
else:
result.add x
@@ -367,8 +393,6 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
op = produceSym(c.g, c.c, t, c.kind, c.info, c.idgen)
body.add newHookCall(c, op, x, y)
result = true
else:
result = false
elif tfHasAsgn in t.flags:
var op: PSym
if sameType(t, c.asgnForType):
@@ -398,8 +422,6 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
assert op.ast[genericParamsPos].kind == nkEmpty
body.add newHookCall(c, op, x, y)
result = true
else:
result = false
proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) =
let t = orig.skipTypes(abstractInst - {tyDistinct})
@@ -439,8 +461,6 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
onUse(c.info, op)
body.add destructorCall(c, op, x)
result = true
else:
result = false
#result = addDestructorCall(c, t, body, x)
of attachedAsgn, attachedSink, attachedTrace:
var op = getAttachedOp(c.g, t, c.kind)
@@ -461,8 +481,6 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
onUse(c.info, op)
body.add newDeepCopyCall(c, op, x, y)
result = true
else:
result = false
of attachedWasMoved:
var op = getAttachedOp(c.g, t, attachedWasMoved)
@@ -477,8 +495,6 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
onUse(c.info, op)
body.add genWasMovedCall(c, op, x)
result = true
else:
result = false
of attachedDup:
var op = getAttachedOp(c.g, t, attachedDup)
@@ -493,8 +509,6 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
onUse(c.info, op)
body.add newDupCall(c, op, x, y)
result = true
else:
result = false
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
@@ -1035,7 +1049,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of tyOrdinal, tyRange, tyInferred,
tyGenericInst, tyAlias, tySink:
fillBody(c, lastSon(t), body, x, y)
of tyConcept, tyIterable: raiseAssert "unreachable"
of tyConcept, tyIterable: doAssert false
proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
kind: TTypeAttachedOp; info: TLineInfo;
@@ -1057,7 +1071,7 @@ proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttache
res.typ = typ
src.typ = typ
result.typ = newType(tyProc, idgen, owner)
result.typ = newType(tyProc, nextTypeId idgen, owner)
result.typ.n = newNodeI(nkFormalParams, info)
rawAddSon(result.typ, res.typ)
result.typ.n.add newNodeI(nkEffectList, info)
@@ -1091,9 +1105,8 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
let dest = newSym(skParam, getIdent(g.cache, "dest"), idgen, result, info)
let src = newSym(skParam, getIdent(g.cache, if kind == attachedTrace: "env" else: "src"),
idgen, result, info)
if kind == attachedDestructor and g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc} and
((g.config.isDefined("nimPreviewNonVarDestructor") and not isDiscriminant) or typ.kind in {tyRef, tyString, tySequence}):
((g.config.isDefined("nimPreviewNonVarDestructor") and not isDiscriminant) or (typ.kind in {tyRef, tyString, tySequence})):
dest.typ = typ
else:
dest.typ = makeVarType(typ.owner, typ, idgen)
@@ -1103,7 +1116,7 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
else:
src.typ = typ
result.typ = newProcType(info, idgen, owner)
result.typ = newProcType(info, nextTypeId(idgen), owner)
result.typ.addParam dest
if kind notin {attachedDestructor, attachedWasMoved}:
result.typ.addParam src
@@ -1179,7 +1192,14 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
# bug #19205: Do not forget to also copy the hidden type field:
genTypeFieldCopy(a, typ, result.ast[bodyPos], d, src)
if not a.canRaise: incl result.flags, sfNeverRaises
if not a.canRaise:
incl result.flags, sfNeverRaises
result.ast[pragmasPos] = newNodeI(nkPragma, info)
result.ast[pragmasPos].add newTree(nkExprColonExpr,
newIdentNode(g.cache.getIdent("raises"), info), newNodeI(nkBracket, info))
if kind == attachedDestructor:
incl result.options, optQuirky
completePartialOp(g, idgen.module, typ, kind, result)
@@ -1239,7 +1259,7 @@ proc inst(g: ModuleGraph; c: PContext; t: PType; kind: TTypeAttachedOp; idgen: I
else:
localError(g.config, info, "unresolved generic parameter")
proc isTrival(s: PSym): bool {.inline.} =
proc isTrival*(s: PSym): bool {.inline.} =
s == nil or (s.ast != nil and s.ast[bodyPos].len == 0)
proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInfo;
@@ -1274,7 +1294,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
# bug #15122: We need to produce all prototypes before entering the
# mind boggling recursion. Hacks like these imply we should rewrite
# this module.
var generics: array[attachedWasMoved..attachedTrace, bool] = default(array[attachedWasMoved..attachedTrace, bool])
var generics: array[attachedWasMoved..attachedTrace, bool]
for k in attachedWasMoved..lastAttached:
generics[k] = getAttachedOp(g, canon, k) != nil
if not generics[k]:

View File

@@ -10,11 +10,9 @@
## This module implements the '.liftLocals' pragma.
import
options, ast, msgs,
strutils, options, ast, msgs,
idents, renderer, types, lowerings, lineinfos
import std/strutils
from pragmas import getPragmaVal
from wordrecg import wLiftLocals
@@ -51,7 +49,6 @@ proc liftLocals(n: PNode; i: int; c: var Ctx) =
liftLocals(it, i, c)
proc lookupParam(params, dest: PNode): PSym =
result = nil
if dest.kind != nkIdent: return nil
for i in 1..<params.len:
if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id:

View File

@@ -7,11 +7,10 @@
# distribution, for details about the copyright.
#
## This module contains the `TMsgKind` enum as well as the
## `TLineInfo` object.
## This module contains the ``TMsgKind`` enum as well as the
## ``TLineInfo`` object.
import ropes, pathutils
import std/[hashes, tables]
import ropes, tables, pathutils, hashes
const
explanationsBaseUrl* = "https://nim-lang.github.io/Nim"
@@ -92,7 +91,7 @@ type
warnStmtListLambda = "StmtListLambda",
warnBareExcept = "BareExcept",
warnImplicitDefaultValue = "ImplicitDefaultValue",
warnStdPrefix = "StdPrefix"
warnIgnoredSymbolInjection = "IgnoredSymbolInjection",
warnUser = "User",
# hints
hintSuccess = "Success", hintSuccessX = "SuccessX",
@@ -196,7 +195,7 @@ const
warnStmtListLambda: "statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead",
warnBareExcept: "$1",
warnImplicitDefaultValue: "$1",
warnStdPrefix: "$1 needs the 'std' prefix",
warnIgnoredSymbolInjection: "$1",
warnUser: "$1",
hintSuccess: "operation successful: $#",
# keep in sync with `testament.isSuccess`
@@ -251,8 +250,7 @@ type
TNoteKinds* = set[TNoteKind]
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
result = default(array[0..3, TNoteKinds])
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept, warnStdPrefix}
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept}
result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt}
result[1] = result[2] - {warnProveField, warnProveIndex,
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
@@ -314,7 +312,7 @@ proc `==`*(a, b: FileIndex): bool {.borrow.}
proc hash*(i: TLineInfo): Hash =
hash (i.line.int, i.col.int, i.fileIndex.int)
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
proc raiseRecoverableError*(msg: string) {.noinline.} =
raise newException(ERecoverableError, msg)
const
@@ -345,8 +343,9 @@ type
proc initMsgConfig*(): MsgConfig =
result = MsgConfig(msgContext: @[], lastError: unknownLineInfo,
filenameToIndexTbl: initTable[string, FileIndex](),
fileInfos: @[], errorOutputs: {eStdOut, eStdErr}
)
result.msgContext = @[]
result.lastError = unknownLineInfo
result.filenameToIndexTbl = initTable[string, FileIndex]()
result.fileInfos = @[]
result.errorOutputs = {eStdOut, eStdErr}
result.filenameToIndexTbl["???"] = FileIndex(-1)

View File

@@ -12,19 +12,17 @@
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
Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
proc identLen*(line: string, start: int): int =
result = 0
while start+result < line.len and line[start+result] in Letters:
inc result
proc `=~`(s: string, a: openArray[string]): bool =
result = false
for x in a:
if s.startsWith(x): return true
@@ -97,7 +95,7 @@ template styleCheckDef*(ctx: PContext; info: TLineInfo; sym: PSym; k: TSymKind)
if optStyleCheck in ctx.config.options and # ignore if styleChecks are off
{optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # check only if hint/error is enabled
hintName in ctx.config.notes and # ignore if name checks are not requested
ctx.config.belongsToProjectPackage(sym) and # ignore foreign packages
ctx.config.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 +136,7 @@ template styleCheckUse*(ctx: PContext; info: TLineInfo; sym: PSym) =
## Check symbol uses match their definition's style.
if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
hintName in ctx.config.notes and # ignore if name checks are not requested
ctx.config.belongsToProjectPackage(sym) and # ignore foreign packages
ctx.config.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 +152,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

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

View File

@@ -14,10 +14,8 @@ when defined(nimPreviewSlimSystem):
import std/assertions
import
ast, astalgo, idents, semdata, types, msgs, options,
renderer, lineinfos, modulegraphs, astmsgs, wordrecg
import std/[intsets, sets]
intsets, ast, astalgo, idents, semdata, types, msgs, options,
renderer, lineinfos, modulegraphs, astmsgs, sets, wordrecg
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope)
@@ -50,7 +48,7 @@ proc considerQuotedIdent*(c: PContext; n: PNode, origin: PNode = nil): PIdent =
case x.kind
of nkIdent: id.add(x.ident.s)
of nkSym: id.add(x.sym.name.s)
of nkSymChoices:
of nkSymChoices, nkOpenSym:
if x[0].kind == nkSym:
id.add(x[0].sym.name.s)
else:
@@ -63,6 +61,8 @@ proc considerQuotedIdent*(c: PContext; n: PNode, origin: PNode = nil): PIdent =
result = n[0].sym.name
else:
handleError(n, origin)
of nkOpenSym:
result = considerQuotedIdent(c, n[0], origin)
else:
handleError(n, origin)
@@ -74,7 +74,7 @@ proc addUniqueSym*(scope: PScope, s: PSym): PSym =
proc openScope*(c: PContext): PScope {.discardable.} =
result = PScope(parent: c.currentScope,
symbols: initStrTable(),
symbols: newStrTable(),
depthLevel: c.scopeDepth + 1)
c.currentScope = result
@@ -137,7 +137,7 @@ proc nextIdentIter(ti: var ModuleIter; marked: var IntSet; im: ImportedModule;
return result
iterator symbols(im: ImportedModule; marked: var IntSet; name: PIdent; g: ModuleGraph): PSym =
var ti: ModuleIter
var ti: ModuleIter = default(ModuleIter)
var candidate = initIdentIter(ti, marked, im, name, g)
while candidate != nil:
yield candidate
@@ -150,7 +150,7 @@ iterator importedItems*(c: PContext; name: PIdent): PSym =
yield s
proc allPureEnumFields(c: PContext; name: PIdent): seq[PSym] =
var ti: TIdentIter
var ti: TIdentIter = default(TIdentIter)
result = @[]
var res = initIdentIter(ti, c.pureEnumFields, name)
while res != nil:
@@ -222,7 +222,7 @@ proc debugScopes*(c: PContext; limit=0, max = int.high) {.deprecated.} =
proc searchInScopesAllCandidatesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSym] =
result = @[]
for scope in allScopes(c.currentScope):
var ti: TIdentIter
var ti: TIdentIter = default(TIdentIter)
var candidate = initIdentIter(ti, scope.symbols, s)
while candidate != nil:
if candidate.kind in filter:
@@ -240,7 +240,7 @@ proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSy
result = @[]
block outer:
for scope in allScopes(c.currentScope):
var ti: TIdentIter
var ti: TIdentIter = default(TIdentIter)
var candidate = initIdentIter(ti, scope.symbols, s)
while candidate != nil:
if candidate.kind in filter:
@@ -256,11 +256,23 @@ proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSy
if s.kind in filter:
result.add s
proc cmpScopes*(ctx: PContext, s: PSym): int =
# Do not return a negative number
if s.originatingModule == ctx.module:
result = 2
var owner = s
while true:
owner = owner.skipGenericOwner
if owner.kind == skModule: break
inc result
else:
result = 1
proc isAmbiguous*(c: PContext, s: PIdent, filter: TSymKinds, sym: var PSym): bool =
result = false
block outer:
for scope in allScopes(c.currentScope):
var ti: TIdentIter
var ti: TIdentIter = default(TIdentIter)
var candidate = initIdentIter(ti, scope.symbols, s)
var scopeHasCandidate = false
while candidate != nil:
@@ -291,8 +303,16 @@ proc isAmbiguous*(c: PContext, s: PIdent, filter: TSymKinds, sym: var PSym): boo
# imports had a candidate but wasn't ambiguous
return false
proc errorSym*(c: PContext, n: PNode): PSym =
proc errorSym*(c: PContext, ident: PIdent, info: TLineInfo): PSym =
## creates an error symbol to avoid cascading errors (for IDE support)
result = newSym(skError, ident, c.idgen, getCurrOwner(c), info, {})
result.typ = errorType(c)
incl(result.flags, sfDiscardable)
# pretend it's from the top level scope to prevent cascading errors:
if c.config.cmd != cmdInteractive and c.compilesContextId == 0:
c.moduleScope.addSym(result)
proc errorSym*(c: PContext, n: PNode): PSym =
var m = n
# ensure that 'considerQuotedIdent' can't fail:
if m.kind == nkDotExpr: m = m[1]
@@ -300,12 +320,7 @@ proc errorSym*(c: PContext, n: PNode): PSym =
considerQuotedIdent(c, m)
else:
getIdent(c.cache, "err:" & renderTree(m))
result = newSym(skError, ident, c.idgen, getCurrOwner(c), n.info, {})
result.typ = errorType(c)
incl(result.flags, sfDiscardable)
# pretend it's from the top level scope to prevent cascading errors:
if c.config.cmd != cmdInteractive and c.compilesContextId == 0:
c.moduleScope.addSym(result)
result = errorSym(c, ident, n.info)
type
TOverloadIterMode* = enum
@@ -332,10 +347,10 @@ proc getSymRepr*(conf: ConfigRef; s: PSym, getDeclarationPath = true): string =
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) =
# check if all symbols have been used and defined:
var it: TTabIter
var it: TTabIter = default(TTabIter)
var s = initTabIter(it, scope.symbols)
var missingImpls = 0
var unusedSyms: seq[tuple[sym: PSym, key: string]] = @[]
var unusedSyms: seq[tuple[sym: PSym, key: string]]
while s != nil:
if sfForward in s.flags and s.kind notin {skType, skModule}:
# too many 'implementation of X' errors are annoying
@@ -441,7 +456,7 @@ proc openShadowScope*(c: PContext) =
## opens a shadow scope, just like any other scope except the depth is the
## same as the parent -- see `isShadowScope`.
c.currentScope = PScope(parent: c.currentScope,
symbols: initStrTable(),
symbols: newStrTable(),
depthLevel: c.scopeDepth)
proc closeShadowScope*(c: PContext) =
@@ -466,7 +481,7 @@ proc mergeShadowScope*(c: PContext) =
c.addInterfaceDecl(sym)
import std/[editdistance, heapqueue]
import std/editdistance, heapqueue
type SpellCandidate = object
dist: int
@@ -487,7 +502,7 @@ proc mustFixSpelling(c: PContext): bool {.inline.} =
result = c.config.spellSuggestMax != 0 and c.compilesContextId == 0
# don't slowdown inside compiles()
proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) =
proc fixSpelling(c: PContext, ident: PIdent, result: var string) =
## when we cannot find the identifier, suggest nearby spellings
var list = initHeapQueue[SpellCandidate]()
let name0 = ident.s.nimIdentNormalize
@@ -495,7 +510,7 @@ proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) =
for (sym, depth, isLocal) in allSyms(c):
let depth = -depth - 1
let dist = editDistance(name0, sym.name.s.nimIdentNormalize)
var msg: string = ""
var msg: string
msg.add "\n ($1, $2): '$3'" % [$dist, $depth, sym.name.s]
list.push SpellCandidate(dist: dist, depth: depth, msg: msg, sym: sym)
@@ -525,7 +540,6 @@ proc errorUseQualifier(c: PContext; info: TLineInfo; s: PSym; amb: var bool): PS
var err = "ambiguous identifier: '" & s.name.s & "'"
var i = 0
var ignoredModules = 0
result = nil
for candidate in importedItems(c, s.name):
if i == 0: err.add " -- use one of the following:\n"
else: err.add "\n"
@@ -543,10 +557,10 @@ proc errorUseQualifier(c: PContext; info: TLineInfo; s: PSym; amb: var bool): PS
amb = false
proc errorUseQualifier*(c: PContext; info: TLineInfo; s: PSym) =
var amb: bool
var amb: bool = false
discard errorUseQualifier(c, info, s, amb)
proc errorUseQualifier(c: PContext; info: TLineInfo; candidates: seq[PSym]; prefix = "use one of") =
proc errorUseQualifier*(c: PContext; info: TLineInfo; candidates: seq[PSym]; prefix = "use one of") =
var err = "ambiguous identifier: '" & candidates[0].name.s & "'"
var i = 0
for candidate in candidates:
@@ -569,7 +583,11 @@ proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string, extr
if name == "_":
err = "the special identifier '_' is ignored in declarations and cannot be used"
else:
err = "undeclared identifier: '" & name & "'" & extra
err = "undeclared identifier: '" & name & "'"
if "`gensym" in name:
err.add "; if declared in a template, this identifier may be inconsistently marked inject or gensym"
if extra.len != 0:
err.add extra
if c.recursiveDep.len > 0:
err.add "\nThis might be caused by a recursive module dependency:\n"
err.add c.recursiveDep
@@ -577,11 +595,11 @@ proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string, extr
c.recursiveDep = ""
localError(c.config, info, errGenerated, err)
proc errorUndeclaredIdentifierHint*(c: PContext; n: PNode, ident: PIdent): PSym =
proc errorUndeclaredIdentifierHint*(c: PContext; ident: PIdent; info: TLineInfo): PSym =
var extra = ""
if c.mustFixSpelling: fixSpelling(c, n, ident, extra)
errorUndeclaredIdentifier(c, n.info, ident.s, extra)
result = errorSym(c, n)
if c.mustFixSpelling: fixSpelling(c, ident, extra)
errorUndeclaredIdentifier(c, info, ident.s, extra)
result = errorSym(c, ident, info)
proc lookUp*(c: PContext, n: PNode): PSym =
# Looks up a symbol. Generates an error in case of nil.
@@ -589,13 +607,13 @@ proc lookUp*(c: PContext, n: PNode): PSym =
case n.kind
of nkIdent:
result = searchInScopes(c, n.ident, amb)
if result == nil: result = errorUndeclaredIdentifierHint(c, n, n.ident)
if result == nil: result = errorUndeclaredIdentifierHint(c, n.ident, n.info)
of nkSym:
result = n.sym
of nkAccQuoted:
var ident = considerQuotedIdent(c, n)
result = searchInScopes(c, ident, amb)
if result == nil: result = errorUndeclaredIdentifierHint(c, n, ident)
if result == nil: result = errorUndeclaredIdentifierHint(c, ident, n.info)
else:
internalError(c.config, n.info, "lookUp")
return nil
@@ -609,16 +627,29 @@ type
TLookupFlag* = enum
checkAmbiguity, checkUndeclared, checkModule, checkPureEnumFields
const allExceptModule = {low(TSymKind)..high(TSymKind)} - {skModule, skPackage}
proc lookUpCandidates*(c: PContext, ident: PIdent, filter: set[TSymKind]): seq[PSym] =
result = searchInScopesFilterBy(c, ident, filter)
if result.len == 0:
result.add allPureEnumFields(c, ident)
proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
const allExceptModule = {low(TSymKind)..high(TSymKind)} - {skModule, skPackage}
case n.kind
of nkIdent, nkAccQuoted:
var amb = false
var ident = considerQuotedIdent(c, n)
if checkModule in flags:
result = searchInScopes(c, ident, amb)
if result == nil:
let candidates = allPureEnumFields(c, ident)
if candidates.len > 0:
result = candidates[0]
amb = candidates.len > 1
if amb and checkAmbiguity in flags:
errorUseQualifier(c, n.info, candidates)
else:
let candidates = searchInScopesFilterBy(c, ident, allExceptModule)
let candidates = lookUpCandidates(c, ident, allExceptModule)
if candidates.len > 0:
result = candidates[0]
amb = candidates.len > 1
@@ -626,21 +657,15 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
errorUseQualifier(c, n.info, candidates)
else:
result = nil
if result == nil:
let candidates = allPureEnumFields(c, ident)
if candidates.len > 0:
result = candidates[0]
amb = candidates.len > 1
if amb and checkAmbiguity in flags:
errorUseQualifier(c, n.info, candidates)
if result == nil and checkUndeclared in flags:
result = errorUndeclaredIdentifierHint(c, n, ident)
result = errorUndeclaredIdentifierHint(c, ident, n.info)
elif checkAmbiguity in flags and result != nil and amb:
result = errorUseQualifier(c, n.info, result, amb)
c.isAmbiguous = amb
of nkSym:
result = n.sym
of nkOpenSym:
result = qualifiedLookUp(c, n[0], flags)
of nkDotExpr:
result = nil
var m = qualifiedLookUp(c, n[0], (flags * {checkUndeclared}) + {checkModule})
@@ -655,17 +680,17 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
result = strTableGet(c.topLevelScope.symbols, ident)
else:
if c.importModuleLookup.getOrDefault(m.name.id).len > 1:
var amb: bool
var amb: bool = false
result = errorUseQualifier(c, n.info, m, amb)
else:
result = someSym(c.graph, m, ident)
if result == nil and checkUndeclared in flags:
result = errorUndeclaredIdentifierHint(c, n[1], ident)
result = errorUndeclaredIdentifierHint(c, ident, n[1].info)
elif n[1].kind == nkSym:
result = n[1].sym
if result.owner != nil and result.owner != m and checkUndeclared in flags:
# dotExpr in templates can end up here
result = errorUndeclaredIdentifierHint(c, n[1], considerQuotedIdent(c, n[1]))
result = errorUndeclaredIdentifierHint(c, result.name, n[1].info)
elif checkUndeclared in flags and
n[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
localError(c.config, n[1].info, "identifier expected, but got: " &
@@ -677,11 +702,14 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
if result != nil and result.kind == skStub: loadStub(result)
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`
return initOverloadIter(o, c, n[0])
o.importIdx = -1
o.marked = initIntSet()
case n.kind
of nkIdent, nkAccQuoted:
result = nil
var ident = considerQuotedIdent(c, n)
var scope = c.currentScope
o.mode = oimNoQualifier
@@ -705,7 +733,6 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
result = n.sym
o.mode = oimDone
of nkDotExpr:
result = nil
o.mode = oimOtherModule
o.m = qualifiedLookUp(c, n[0], {checkUndeclared, checkModule})
if o.m != nil and o.m.kind == skModule:
@@ -735,7 +762,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
o.symChoiceIndex = 1
o.marked = initIntSet()
incl(o.marked, result.id)
else: result = nil
else: discard
when false:
if result != nil and result.kind == skStub: loadStub(result)
@@ -750,7 +777,6 @@ proc lastOverloadScope*(o: TOverloadIter): int =
else: result = -1
proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym =
result = nil
assert o.currentScope == nil
var idx = o.importIdx+1
o.importIdx = c.imports.len # assume the other imported modules lack this symbol too
@@ -763,7 +789,6 @@ proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym
inc idx
proc symChoiceExtension(o: var TOverloadIter; c: PContext; n: PNode): PSym =
result = nil
assert o.currentScope == nil
while o.importIdx < c.imports.len:
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph)
@@ -826,8 +851,6 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
break
if result != nil:
incl o.marked, result.id
else:
result = nil
of oimSymChoiceLocalLookup:
if o.currentScope != nil:
result = nextIdentExcluding(o.it, o.currentScope.symbols, o.marked)
@@ -851,16 +874,13 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
if result == nil:
inc o.importIdx
result = symChoiceExtension(o, c, n)
else:
result = nil
when false:
if result != nil and result.kind == skStub: loadStub(result)
proc pickSym*(c: PContext, n: PNode; kinds: set[TSymKind];
flags: TSymFlags = {}): PSym =
result = nil
var o: TOverloadIter = default(TOverloadIter)
var o: TOverloadIter
var a = initOverloadIter(o, c, n)
while a != nil:
if a.kind in kinds and flags <= a.flags:

View File

@@ -144,7 +144,7 @@ proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNod
result.add newFastAsgnStmt(n[2], tempAsNode)
proc createObj*(g: ModuleGraph; idgen: IdGenerator; owner: PSym, info: TLineInfo; final=true): PType =
result = newType(tyObject, idgen, owner)
result = newType(tyObject, nextTypeId(idgen), owner)
if final:
rawAddSon(result, nil)
incl result.flags, tfFinal
@@ -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, nextTypeId(idgen), n.typ.owner)
result.typ.rawAddSon(n.typ)
proc genDeref*(n: PNode; k = nkHiddenDeref): PNode =

View File

@@ -18,7 +18,7 @@ export createMagic
proc nilOrSysInt*(g: ModuleGraph): PType = g.sysTypes[tyInt]
proc newSysType(g: ModuleGraph; kind: TTypeKind, size: int): PType =
result = newType(kind, g.idgen, g.systemModule)
result = newType(kind, nextTypeId(g.idgen), g.systemModule)
result.size = size
result.align = size.int16
@@ -27,10 +27,9 @@ proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym =
if result == nil:
localError(g.config, info, "system module needs: " & name)
result = newSym(skError, getIdent(g.cache, name), g.idgen, g.systemModule, g.systemModule.info, {})
result.typ = newType(tyError, g.idgen, g.systemModule)
result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule)
proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym =
result = nil
let id = getIdent(g.cache, name)
for r in systemModuleSyms(g, id):
if r.magic == m:
@@ -40,7 +39,7 @@ proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSy
if result != nil: return result
localError(g.config, info, "system module needs: " & name)
result = newSym(skError, id, g.idgen, g.systemModule, g.systemModule.info, {})
result.typ = newType(tyError, g.idgen, g.systemModule)
result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule)
proc sysTypeFromName*(g: ModuleGraph; info: TLineInfo; name: string): PType =
result = getSysSym(g, info, name).typ
@@ -81,8 +80,8 @@ proc getSysType*(g: ModuleGraph; info: TLineInfo; kind: TTypeKind): PType =
proc resetSysTypes*(g: ModuleGraph) =
g.systemModule = nil
g.compilerprocs = initStrTable()
g.exposed = initStrTable()
initStrTable(g.compilerprocs)
initStrTable(g.exposed)
for i in low(g.sysTypes)..high(g.sysTypes):
g.sysTypes[i] = nil
@@ -93,23 +92,16 @@ proc getFloatLitType*(g: ModuleGraph; literal: PNode): PType =
proc skipIntLit*(t: PType; id: IdGenerator): PType {.inline.} =
if t.n != nil and t.kind in {tyInt, tyFloat}:
result = copyType(t, id, t.owner)
result = copyType(t, nextTypeId(id), t.owner)
result.n = nil
else:
result = t
proc addSonSkipIntLit*(father, son: PType; id: IdGenerator) =
let s = son.skipIntLit(id)
father.add(s)
father.sons.add(s)
propagateToOwner(father, s)
proc makeVarType*(owner: PSym; baseType: PType; idgen: IdGenerator; kind = tyVar): PType =
if baseType.kind == kind:
result = baseType
else:
result = newType(kind, idgen, owner)
addSonSkipIntLit(result, baseType, idgen)
proc getCompilerProc*(g: ModuleGraph; name: string): PSym =
let ident = getIdent(g.cache, name)
result = strTableGet(g.compilerprocs, ident)
@@ -131,7 +123,7 @@ proc registerNimScriptSymbol*(g: ModuleGraph; s: PSym) =
proc getNimScriptSymbol*(g: ModuleGraph; name: string): PSym =
strTableGet(g.exposed, getIdent(g.cache, name))
proc resetNimScriptSymbols*(g: ModuleGraph) = g.exposed = initStrTable()
proc resetNimScriptSymbols*(g: ModuleGraph) = initStrTable(g.exposed)
proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym =
case t.kind
@@ -153,17 +145,7 @@ proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym =
of tyProc:
result = getSysMagic(g, info, "==", mEqProc)
else:
result = nil
globalError(g.config, info,
"can't find magic equals operator for type kind " & $t.kind)
proc makePtrType*(baseType: PType; idgen: IdGenerator): PType =
result = newType(tyPtr, idgen, baseType.owner)
addSonSkipIntLit(result, baseType, idgen)
proc makeAddr*(n: PNode; idgen: IdGenerator): PNode =
if n.kind == nkHiddenAddr:
result = n
else:
result = newTree(nkHiddenAddr, n)
result.typ = makePtrType(n.typ, idgen)

View File

@@ -22,13 +22,12 @@ import
modules,
modulegraphs, lineinfos, pathutils, vmprofiler
# ensure NIR compiles:
import nir / nir
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
import ic / [cbackend, integrity, navigator, ic]
import ic / [cbackend, integrity, navigator]
from ic / ic import rodViewer
import ../dist/checksums/src/checksums/sha1
@@ -48,9 +47,6 @@ proc writeDepsFile(g: ModuleGraph) =
f.writeLine(toFullPath(g.config, k))
f.close()
proc writeNinjaFile(g: ModuleGraph) =
discard "to implement"
proc writeCMakeDepsFile(conf: ConfigRef) =
## write a list of C files for build systems like CMake.
## only updated when the C file list changes.
@@ -60,7 +56,7 @@ proc writeCMakeDepsFile(conf: ConfigRef) =
for it in conf.toCompile: cfiles.add(it.cname.string)
let fileset = cfiles.toCountTable()
# read old cfiles list
var fl: File = default(File)
var fl: File
var prevset = initCountTable[string]()
if open(fl, fname.string, fmRead):
for line in fl.lines: prevset.inc(line)
@@ -119,7 +115,7 @@ when not defined(leanCompiler):
setPipeLinePass(graph, Docgen2JsonPass)
of HtmlExt:
setPipeLinePass(graph, Docgen2Pass)
else: raiseAssert $ext
else: doAssert false, $ext
compilePipelineProject(graph)
proc commandCompileToC(graph: ModuleGraph) =
@@ -155,32 +151,12 @@ proc commandCompileToC(graph: ModuleGraph) =
extccomp.callCCompiler(conf)
# for now we do not support writing out a .json file with the build instructions when HCR is on
if not conf.hcrOn:
extccomp.writeJsonBuildInstructions(conf)
extccomp.writeJsonBuildInstructions(conf, graph.cachedFiles)
if optGenScript in graph.config.globalOptions:
writeDepsFile(graph)
if optGenCDeps in graph.config.globalOptions:
writeCMakeDepsFile(conf)
proc commandCompileToNir(graph: ModuleGraph) =
let conf = graph.config
extccomp.initVars(conf)
if conf.symbolFiles == disabledSf:
if {optRun, optForceFullMake} * conf.globalOptions == {optRun}:
if not changeDetectedViaJsonBuildInstructions(conf, conf.jsonBuildInstructionsFile):
# nothing changed
graph.config.notes = graph.config.mainPackageNotes
return
if not extccomp.ccHasSaneOverflow(conf):
conf.symbols.defineSymbol("nimEmulateOverflowChecks")
if conf.symbolFiles == disabledSf:
setPipeLinePass(graph, NirPass)
else:
setPipeLinePass(graph, SemPass)
compilePipelineProject(graph)
writeNinjaFile(graph)
proc commandJsonScript(graph: ModuleGraph) =
extccomp.runJsonBuildInstructions(graph.config, graph.config.jsonBuildInstructionsFile)
@@ -197,16 +173,13 @@ proc commandCompileToJS(graph: ModuleGraph) =
if optGenScript in conf.globalOptions:
writeDepsFile(graph)
proc commandInteractive(graph: ModuleGraph; useNir: bool) =
proc commandInteractive(graph: ModuleGraph) =
graph.config.setErrorMaxHighMaybe
initDefines(graph.config.symbols)
if useNir:
defineSymbol(graph.config.symbols, "noSignalHandler")
else:
defineSymbol(graph.config.symbols, "nimscript")
defineSymbol(graph.config.symbols, "nimscript")
# note: seems redundant with -d:nimHasLibFFI
when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
setPipeLinePass(graph, if useNir: NirReplPass else: InterpreterPass)
setPipeLinePass(graph, InterpreterPass)
compilePipelineSystemModule(graph)
if graph.config.commandArgs.len > 0:
discard graph.compilePipelineModule(fileInfoIdx(graph.config, graph.config.projectFull), {})
@@ -222,8 +195,9 @@ proc commandScan(cache: IdentCache, config: ConfigRef) =
var stream = llStreamOpen(f, fmRead)
if stream != nil:
var
L: Lexer
L: Lexer = default(Lexer)
tok: Token = default(Token)
initToken(tok)
openLexer(L, f, stream, cache, config)
while true:
rawGetTok(L, tok)
@@ -293,9 +267,7 @@ proc mainCommand*(graph: ModuleGraph) =
# and it has added this define implictly, so we must undo that here.
# A better solution might be to fix system.nim
undefSymbol(conf.symbols, "useNimRtl")
of backendNir:
if conf.exc == excNone: conf.exc = excGoto
of backendInvalid: raiseAssert "unreachable"
of backendInvalid: doAssert false
proc compileToBackend() =
customizeForBackend(conf.backend)
@@ -305,8 +277,7 @@ proc mainCommand*(graph: ModuleGraph) =
of backendCpp: commandCompileToC(graph)
of backendObjc: commandCompileToC(graph)
of backendJs: commandCompileToJS(graph)
of backendNir: commandCompileToNir(graph)
of backendInvalid: raiseAssert "unreachable"
of backendInvalid: doAssert false
template docLikeCmd(body) =
when defined(leanCompiler):
@@ -333,10 +304,7 @@ proc mainCommand*(graph: ModuleGraph) =
## process all commands
case conf.cmd
of cmdBackends:
compileToBackend()
when BenchIC:
echoTimes graph.packed
of cmdBackends: compileToBackend()
of cmdTcc:
when hasTinyCBackend:
extccomp.setCC(conf, "tcc", unknownLineInfo)
@@ -432,10 +400,6 @@ proc mainCommand*(graph: ModuleGraph) =
for it in conf.searchPaths: msgWriteln(conf, it.string)
of cmdCheck:
commandCheck(graph)
of cmdM:
graph.config.symbolFiles = v2Sf
setUseIc(graph.config.symbolFiles != disabledSf)
commandCheck(graph)
of cmdParse:
wantMainModule(conf)
discard parseFile(conf.projectMainIdx, cache, conf)
@@ -443,7 +407,7 @@ proc mainCommand*(graph: ModuleGraph) =
wantMainModule(conf)
commandView(graph)
#msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!")
of cmdInteractive: commandInteractive(graph, isDefined(conf, "nir"))
of cmdInteractive: commandInteractive(graph)
of cmdNimscript:
if conf.projectIsCmd or conf.projectIsStdin: discard
elif not fileExists(conf.projectFull):

View File

@@ -11,12 +11,11 @@
## represents a complete Nim project. Single modules can either be kept in RAM
## or stored in a rod-file.
import std/[intsets, tables, hashes]
import std/[intsets, tables, hashes, strtabs]
import ../dist/checksums/src/checksums/md5
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages
import ic / [packed_ast, ic]
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -67,8 +66,6 @@ type
CgenPass
EvalPass
InterpreterPass
NirPass
NirReplPass
GenDependPass
Docgen2TexPass
Docgen2JsonPass
@@ -82,9 +79,8 @@ type
typeInstCache*: Table[ItemId, seq[LazyType]] # A symbol's ItemId.
procInstCache*: Table[ItemId, seq[LazyInstantiation]] # A symbol's ItemId.
attachedOps*: array[TTypeAttachedOp, Table[ItemId, LazySym]] # Type ID, destructors, etc.
methodsPerGenericType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods
memberProcsPerType*: Table[ItemId, seq[PSym]] # Type ID, attached member procs (only c++, virtual,member and ctor so far).
initializersPerType*: Table[ItemId, PNode] # Type ID, AST call to the default ctor (c++ only)
methodsPerType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods
memberProcsPerType*: Table[ItemId, seq[PSym]] # Type ID, attached member procs (only c++, virtual and ctor so far)
enumToStringProcs*: Table[ItemId, LazySym]
emittedTypeInfo*: Table[string, FileIndex]
@@ -94,7 +90,6 @@ type
importDeps*: Table[FileIndex, seq[FileIndex]] # explicit import module dependencies
suggestMode*: bool # whether we are in nimsuggest mode or not.
invalidTransitiveClosure: bool
interactive*: bool
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
@@ -104,18 +99,12 @@ type
cache*: IdentCache
vm*: RootRef # unfortunately the 'vm' state is shared project-wise, this will
# be clarified in later compiler implementations.
repl*: RootRef # REPL state is shared project-wise.
doStopCompile*: proc(): bool {.closure.}
usageSym*: PSym # for nimsuggest
owners*: seq[PSym]
suggestSymbols*: Table[FileIndex, seq[SymInfoPair]]
suggestErrors*: Table[FileIndex, seq[Suggest]]
methods*: seq[tuple[methods: seq[PSym], dispatcher: PSym]] # needs serialization!
bucketTable*: CountTable[ItemId]
objectTree*: Table[ItemId, seq[tuple[depth: int, value: PType]]]
methodsPerType*: Table[ItemId, seq[LazySym]]
dispatchers*: seq[LazySym]
systemModule*: PSym
sysTypes*: array[TTypeKind, PType]
compilerprocs*: TStrTable
@@ -140,6 +129,8 @@ type
idgen*: IdGenerator
operators*: Operators
cachedFiles*: StringTableRef
TPassContext* = object of RootObj # the pass's context
idgen*: IdGenerator
PPassContext* = ref TPassContext
@@ -154,15 +145,13 @@ type
isFrontend: bool]
proc resetForBackend*(g: ModuleGraph) =
g.compilerprocs = initStrTable()
initStrTable(g.compilerprocs)
g.typeInstCache.clear()
g.procInstCache.clear()
for a in mitems(g.attachedOps):
a.clear()
g.methodsPerGenericType.clear()
g.enumToStringProcs.clear()
g.dispatchers.setLen(0)
g.methodsPerType.clear()
g.enumToStringProcs.clear()
const
cb64 = [
@@ -210,8 +199,8 @@ template semtabAll*(g: ModuleGraph, m: PSym): TStrTable =
g.ifaces[m.position].interfHidden
proc initStrTables*(g: ModuleGraph, m: PSym) =
semtab(g, m) = initStrTable()
semtabAll(g, m) = initStrTable()
initStrTable(semtab(g, m))
initStrTable(semtabAll(g, m))
proc strTableAdds*(g: ModuleGraph, m: PSym, s: PSym) =
strTableAdd(semtab(g, m), s)
@@ -220,10 +209,10 @@ proc strTableAdds*(g: ModuleGraph, m: PSym, s: PSym) =
proc isCachedModule(g: ModuleGraph; module: int): bool {.inline.} =
result = module < g.packed.len and g.packed[module].status == loaded
proc isCachedModule*(g: ModuleGraph; m: PSym): bool {.inline.} =
proc isCachedModule(g: ModuleGraph; m: PSym): bool {.inline.} =
isCachedModule(g, m.position)
proc simulateCachedModule(g: ModuleGraph; moduleSym: PSym; m: PackedModule) =
proc simulateCachedModule*(g: ModuleGraph; moduleSym: PSym; m: PackedModule) =
when false:
echo "simulating ", moduleSym.name.s, " ", moduleSym.position
simulateLoadedModule(g.packed, g.config, g.cache, moduleSym, m)
@@ -262,7 +251,7 @@ proc nextModuleIter*(mi: var ModuleIter; g: ModuleGraph): PSym =
iterator allSyms*(g: ModuleGraph; m: PSym): PSym =
let importHidden = optImportHidden in m.options
if isCachedModule(g, m):
var rodIt: RodIter
var rodIt: RodIter = default(RodIter)
var r = initRodIterAllSyms(rodIt, g.config, g.cache, g.packed, FileIndex m.position, importHidden)
while r != nil:
yield r
@@ -283,7 +272,7 @@ proc systemModuleSym*(g: ModuleGraph; name: PIdent): PSym =
result = someSym(g, g.systemModule, name)
iterator systemModuleSyms*(g: ModuleGraph; name: PIdent): PSym =
var mi: ModuleIter
var mi: ModuleIter = default(ModuleIter)
var r = initModuleIter(mi, g, g.systemModule, name)
while r != nil:
yield r
@@ -333,7 +322,6 @@ iterator procInstCacheItems*(g: ModuleGraph; s: PSym): PInstantiation =
for t in mitems(x[]):
yield resolveInst(g, t)
proc getAttachedOp*(g: ModuleGraph; t: PType; op: TTypeAttachedOp): PSym =
## returns the requested attached operation for type `t`. Can return nil
## if no such operation exists.
@@ -357,27 +345,6 @@ proc completePartialOp*(g: ModuleGraph; module: int; t: PType; op: TTypeAttached
toPackedGeneratedProcDef(value, g.encoders[module], g.packed[module].fromDisk)
#storeAttachedProcDef(t, op, value, g.encoders[module], g.packed[module].fromDisk)
iterator getDispatchers*(g: ModuleGraph): PSym =
for i in g.dispatchers.mitems:
yield resolveSym(g, i)
proc addDispatchers*(g: ModuleGraph, value: PSym) =
# TODO: add it for packed modules
g.dispatchers.add LazySym(sym: value)
iterator resolveLazySymSeq(g: ModuleGraph, list: var seq[LazySym]): PSym =
for it in list.mitems:
yield resolveSym(g, it)
proc setMethodsPerType*(g: ModuleGraph; id: ItemId, methods: seq[LazySym]) =
# TODO: add it for packed modules
g.methodsPerType[id] = methods
iterator getMethodsPerType*(g: ModuleGraph; t: PType): PSym =
if g.methodsPerType.contains(t.itemId):
for it in mitems g.methodsPerType[t.itemId]:
yield resolveSym(g, it)
proc getToStringProc*(g: ModuleGraph; t: PType): PSym =
result = resolveSym(g, g.enumToStringProcs[t.itemId])
assert result != nil
@@ -386,12 +353,12 @@ proc setToStringProc*(g: ModuleGraph; t: PType; value: PSym) =
g.enumToStringProcs[t.itemId] = LazySym(sym: value)
iterator methodsForGeneric*(g: ModuleGraph; t: PType): (int, PSym) =
if g.methodsPerGenericType.contains(t.itemId):
for it in mitems g.methodsPerGenericType[t.itemId]:
if g.methodsPerType.contains(t.itemId):
for it in mitems g.methodsPerType[t.itemId]:
yield (it[0], resolveSym(g, it[1]))
proc addMethodToGeneric*(g: ModuleGraph; module: int; t: PType; col: int; m: PSym) =
g.methodsPerGenericType.mgetOrPut(t.itemId, @[]).add (col, LazySym(sym: m))
g.methodsPerType.mgetOrPut(t.itemId, @[]).add (col, LazySym(sym: m))
proc hasDisabledAsgn*(g: ModuleGraph; t: PType): bool =
let op = getAttachedOp(g, t, attachedAsgn)
@@ -404,11 +371,10 @@ proc copyTypeProps*(g: ModuleGraph; module: int; dest, src: PType) =
setAttachedOp(g, module, dest, k, op)
proc loadCompilerProc*(g: ModuleGraph; name: string): PSym =
result = nil
if g.config.symbolFiles == disabledSf: return nil
# slow, linear search, but the results are cached:
for module in 0..<len(g.packed):
for module in 0..high(g.packed):
#if isCachedModule(g, module):
let x = searchForCompilerproc(g.packed[module], name)
if x >= 0:
@@ -465,7 +431,7 @@ proc registerModule*(g: ModuleGraph; m: PSym) =
setLen(g.ifaces, m.position + 1)
if m.position >= g.packed.len:
setLen(g.packed.pm, m.position + 1)
setLen(g.packed, m.position + 1)
g.ifaces[m.position] = Iface(module: m, converters: @[], patterns: @[],
uniqueName: rope(uniqueModuleName(g.config, FileIndex(m.position))))
@@ -495,7 +461,7 @@ proc initModuleGraphFields(result: ModuleGraph) =
# A module ID of -1 means that the symbol is not attached to a module at all,
# but to the module graph:
result.idgen = IdGenerator(module: -1'i32, symId: 0'i32, typeId: 0'i32)
result.packageSyms = initStrTable()
initStrTable(result.packageSyms)
result.deps = initIntSet()
result.importDeps = initTable[FileIndex, seq[FileIndex]]()
result.ifaces = @[]
@@ -505,9 +471,9 @@ proc initModuleGraphFields(result: ModuleGraph) =
result.suggestSymbols = initTable[FileIndex, seq[SymInfoPair]]()
result.suggestErrors = initTable[FileIndex, seq[Suggest]]()
result.methods = @[]
result.compilerprocs = initStrTable()
result.exposed = initStrTable()
result.packageTypes = initStrTable()
initStrTable(result.compilerprocs)
initStrTable(result.exposed)
initStrTable(result.packageTypes)
result.emptyNode = newNode(nkEmpty)
result.cacheSeqs = initTable[string, PNode]()
result.cacheCounters = initTable[string, BiggestInt]()
@@ -516,6 +482,7 @@ proc initModuleGraphFields(result: ModuleGraph) =
result.symBodyHashes = initTable[int, SigHash]()
result.operators = initOperators(result)
result.emittedTypeInfo = initTable[string, FileIndex]()
result.cachedFiles = newStringTable()
proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
result = ModuleGraph()
@@ -524,7 +491,7 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
initModuleGraphFields(result)
proc resetAllModules*(g: ModuleGraph) =
g.packageSyms = initStrTable()
initStrTable(g.packageSyms)
g.deps = initIntSet()
g.ifaces = @[]
g.importStack = @[]
@@ -532,12 +499,11 @@ proc resetAllModules*(g: ModuleGraph) =
g.usageSym = nil
g.owners = @[]
g.methods = @[]
g.compilerprocs = initStrTable()
g.exposed = initStrTable()
initStrTable(g.compilerprocs)
initStrTable(g.exposed)
initModuleGraphFields(g)
proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
result = nil
if fileIdx.int32 >= 0:
if isCachedModule(g, fileIdx.int32):
result = g.packed[fileIdx.int32].module
@@ -617,7 +583,6 @@ proc markDirty*(g: ModuleGraph; fileIdx: FileIndex) =
if m != nil:
g.suggestSymbols.del(fileIdx)
g.suggestErrors.del(fileIdx)
g.resetForBackend
incl m.flags, sfDirty
proc unmarkAllDirty*(g: ModuleGraph) =
@@ -644,7 +609,6 @@ proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) =
proc needsCompilation*(g: ModuleGraph): bool =
# every module that *depends* on this file is also dirty:
result = false
for i in 0i32..<g.ifaces.len.int32:
let m = g.ifaces[i].module
if m != nil:
@@ -652,7 +616,6 @@ proc needsCompilation*(g: ModuleGraph): bool =
return true
proc needsCompilation*(g: ModuleGraph, fileIdx: FileIndex): bool =
result = false
let module = g.getModule(fileIdx)
if module != nil and g.isDirty(module):
return true
@@ -674,8 +637,6 @@ proc moduleFromRodFile*(g: ModuleGraph; fileIdx: FileIndex;
## Returns 'nil' if the module needs to be recompiled.
if g.config.symbolFiles in {readOnlySf, v2Sf, stressTest}:
result = moduleFromRodFile(g.packed, g.config, g.cache, fileIdx, cachedModules)
else:
result = nil
proc configComplete*(g: ModuleGraph) =
rememberStartupConfig(g.startupPackedConfig, g.config)

View File

@@ -7,11 +7,9 @@
# distribution, for details about the copyright.
#
import ast, renderer, msgs, options, idents, lineinfos,
import ast, renderer, strutils, msgs, options, idents, os, lineinfos,
pathutils
import std/[strutils, os]
proc getModuleName*(conf: ConfigRef; n: PNode): string =
# This returns a short relative module name without the nim extension
# e.g. like "system", "importer" or "somepath/module"
@@ -38,11 +36,18 @@ proc getModuleName*(conf: ConfigRef; n: PNode): string =
localError(n.info, "only '/' supported with $package notation")
result = ""
else:
let modname = getModuleName(conf, n[2])
# hacky way to implement 'x / y /../ z':
result = getModuleName(conf, n1)
result.add renderTree(n0, {renderNoComments}).replace(" ")
result.add modname
if n0.kind in nkIdentKinds:
let ident = n0.getPIdent
if ident != nil and ident.s[0] == '/':
let modname = getModuleName(conf, n[2])
# hacky way to implement 'x / y /../ z':
result = getModuleName(conf, n1)
result.add renderTree(n0, {renderNoComments}).replace(" ")
result.add modname
else:
result = ""
else:
result = ""
of nkPrefix:
when false:
if n[0].kind == nkIdent and n[0].ident.s == "$":

View File

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

View File

@@ -60,22 +60,6 @@ proc makeCString*(s: string): Rope =
toCChar(s[i], result)
result.add('\"')
proc makeCCharArray*(s: string): Rope =
result = newStringOfCap(int(s.len.toFloat * 1.1) + 1)
result.add("{")
for i in 0..<s.len:
# line wrapping of string litterals in cgen'd code was a bad idea, e.g. causes: bug #16265
# It also makes reading c sources or grepping harder, for zero benefit.
# const MaxLineLength = 64
# if (i + 1) mod MaxLineLength == 0:
# res.add("\"\L\"")
if i != 0:
result.add ", "
result.add '\''
toCChar(s[i], result)
result.add '\''
result.add('}')
proc newFileInfo(fullPath: AbsoluteFile, projPath: RelativeFile): TFileInfo =
result.fullPath = fullPath
#shallow(result.fullPath)
@@ -141,14 +125,14 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile; isKnownFile: var bool
conf.m.filenameToIndexTbl[canon2] = result
proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex =
var dummy: bool
var dummy: bool = false
result = fileInfoIdx(conf, filename, dummy)
proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile; isKnownFile: var bool): FileIndex =
fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), isKnownFile)
proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile): FileIndex =
var dummy: bool
var dummy: bool = false
fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), dummy)
proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
@@ -310,11 +294,9 @@ proc toColumn*(info: TLineInfo): int {.inline.} =
result = info.col
proc toFileLineCol(info: InstantiationInfo): string {.inline.} =
result = ""
result.toLocation(info.filename, info.line, info.column + ColOffset)
proc toFileLineCol*(conf: ConfigRef; info: TLineInfo): string {.inline.} =
result = ""
result.toLocation(toMsgFilename(conf, info), info.line.int, info.col.int + ColOffset)
proc `$`*(conf: ConfigRef; info: TLineInfo): string = toFileLineCol(conf, info)
@@ -426,7 +408,7 @@ proc getMessageStr(msg: TMsgKind, arg: string): string = msgKindToString(msg) %
type TErrorHandling* = enum doNothing, doAbort, doRaise
proc log*(s: string) =
var f: File = default(File)
var f: File
if open(f, getHomeDir() / "nimsuggest.log", fmAppend):
f.writeLine(s)
close(f)
@@ -447,7 +429,8 @@ To create a stacktrace, rerun compilation with './koch temp $1 <file>', see $2 f
proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string, ignoreMsg: bool) =
if msg in fatalMsgs:
if conf.cmd == cmdIdeTools: log(s)
quit(conf, msg)
if conf.cmd != cmdIdeTools or msg != errFatal:
quit(conf, msg)
if msg >= errMin and msg <= errMax or
(msg in warnMin..hintMax and msg in conf.warningAsErrors and not ignoreMsg):
inc(conf.errorCounter)
@@ -455,7 +438,11 @@ proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string,
if conf.errorCounter >= conf.errorMax:
# only really quit when we're not in the new 'nim check --def' mode:
if conf.ideCmd == ideNone:
quit(conf, msg)
when defined(nimsuggest):
#we need to inform the user that something went wrong when initializing NimSuggest
raiseRecoverableError(s)
else:
quit(conf, msg)
elif eh == doAbort and conf.cmd != cmdIdeTools:
quit(conf, msg)
elif eh == doRaise:
@@ -520,8 +507,6 @@ proc getSurroundingSrc(conf: ConfigRef; info: TLineInfo): string =
result = "\n" & indent & $sourceLine(conf, info)
if info.col >= 0:
result.add "\n" & indent & spaces(info.col) & '^'
else:
result = ""
proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): string =
let title = case msg
@@ -573,9 +558,10 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
ignoreMsg = not conf.hasHint(msg)
if not ignoreMsg and msg in conf.warningAsErrors:
title = ErrorTitle
color = ErrorColor
else:
title = HintTitle
color = HintColor
color = HintColor
inc(conf.hintCounter)
let s = if isRaw: arg else: getMessageStr(msg, arg)
@@ -663,13 +649,16 @@ template lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string, extraM
let msg = if optStyleError in conf.globalOptions: errGenerated else: hintName
liMessage(conf, info, msg, m, doNothing, instLoc())
proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
if i.fileIndex.int32 < 0:
proc quotedFilename*(conf: ConfigRef; fi: FileIndex): Rope =
if fi.int32 < 0:
result = makeCString "???"
elif optExcessiveStackTrace in conf.globalOptions:
result = conf.m.fileInfos[i.fileIndex.int32].quotedFullName
result = conf.m.fileInfos[fi.int32].quotedFullName
else:
result = conf.m.fileInfos[i.fileIndex.int32].quotedName
result = conf.m.fileInfos[fi.int32].quotedName
proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
quotedFilename(conf, i.fileIndex)
template listMsg(title, r) =
msgWriteln(conf, title, {msgNoUnitSep})
@@ -741,8 +730,6 @@ proc genSuccessX*(conf: ConfigRef) =
elif conf.outFile.isEmpty and conf.cmd notin {cmdJsonscript} + cmdDocLike + cmdBackends:
# for some cmd we expect a valid absOutFile
output = "unknownOutput"
elif optStdout in conf.globalOptions:
output = "stdout"
else:
output = $conf.absOutFile
if conf.filenameOption != foAbs: output = output.AbsoluteFile.extractFilename

View File

@@ -7,8 +7,8 @@
# distribution, for details about the copyright.
#
import ast, renderer, msgs, options, lineinfos, idents, treetab
import std/[intsets, tables, sequtils, strutils, sets, strformat, hashes]
import ast, renderer, intsets, tables, msgs, options, lineinfos, strformat, idents, treetab, hashes
import sequtils, strutils, sets
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -309,7 +309,6 @@ proc symbol(n: PNode): Symbol =
# echo "symbol ", n, " ", n.kind, " ", result.int
func `$`(map: NilMap): string =
result = ""
var now = map
var stack: seq[NilMap] = @[]
while not now.isNil:
@@ -417,7 +416,7 @@ proc moveOut(ctx: NilCheckerContext, map: NilMap, target: PNode) =
if targetSetIndex != noSetIndex:
var targetSet = map.sets[targetSetIndex]
if targetSet.len > 1:
var other: ExprIndex = default(ExprIndex)
var other: ExprIndex
for element in targetSet:
if element.ExprIndex != targetIndex:
@@ -562,7 +561,7 @@ proc derefWarning(n, ctx, map; kind: Nilability) =
if n.info in ctx.warningLocations:
return
ctx.warningLocations.incl(n.info)
var a: seq[History] = @[]
var a: seq[History]
if n.kind == nkSym:
a = history(map, ctx.index(n))
var res = ""
@@ -766,7 +765,7 @@ proc checkIf(n, ctx, map): Check =
# the state of the conditions: negating conditions before the current one
var layerHistory = newNilMap(mapIf)
# the state after branch effects
var afterLayer: NilMap = nil
var afterLayer: NilMap
# the result nilability for expressions
var nilability = Safe
@@ -863,10 +862,9 @@ proc checkInfix(n, ctx, map): Check =
## a or b : map is an union of a and b's
## a == b : use checkCondition
## else: no change, just check args
result = default(Check)
if n[0].kind == nkSym:
var mapL: NilMap = nil
var mapR: NilMap = nil
var mapL: NilMap
var mapR: NilMap
if n[0].sym.magic notin {mAnd, mEqRef}:
mapL = checkCondition(n[1], ctx, map, false, false)
mapR = checkCondition(n[2], ctx, map, false, false)
@@ -918,7 +916,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, nextTypeId ctx.idgen, nil)
proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode =
var cache = newIdentCache()
@@ -928,7 +926,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, nextTypeId ctx.idgen, nil)
proc infixEq(ctx: NilCheckerContext, l: PNode, r: PNode): PNode =
infix(ctx, l, r, mEqRef)
@@ -949,7 +947,7 @@ proc checkCase(n, ctx, map): Check =
let base = n[0]
result.map = map.copyMap()
result.nilability = Safe
var a: PNode = nil
var a: PNode
for child in n:
case child.kind:
of nkOfBranch:
@@ -1224,7 +1222,7 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check =
# TODO deeper nested elements?
# A(field: B()) #
# field: Safe ->
var elements: seq[(PNode, Nilability)] = @[]
var elements: seq[(PNode, Nilability)]
for i, child in n:
result = check(child, ctx, result.map)
if i > 0:
@@ -1335,7 +1333,7 @@ proc preVisit(ctx: NilCheckerContext, s: PSym, body: PNode, conf: ConfigRef) =
ctx.symbolIndices = {resultId: resultExprIndex}.toTable()
var cache = newIdentCache()
ctx.expressions = SeqOfDistinct[ExprIndex, PNode](@[newIdentNode(cache.getIdent("result"), s.ast.info)])
var emptySet: IntSet = initIntSet() # set[ExprIndex]
var emptySet: IntSet # set[ExprIndex]
ctx.dependants = SeqOfDistinct[ExprIndex, IntSet](@[emptySet])
for i, arg in s.typ.n.sons:
if i > 0:

View File

@@ -42,22 +42,5 @@ define:useStdoutAsStdmsg
@end
@if nimHasWarnBareExcept:
warning[BareExcept]:on
warningAserror[BareExcept]:on
@end
@if nimUseStrictDefs:
experimental:strictDefs
warningAsError[Uninit]:on
warningAsError[ProveInit]:on
@end
@if nimHasWarnStdPrefix:
warning[StdPrefix]:on
warningAsError[StdPrefix]:on
@end
@if nimHasVtables:
experimental:vtables
@end

View File

@@ -28,7 +28,7 @@ import
commands, options, msgs, extccomp, main, idents, lineinfos, cmdlinehelper,
pathutils, modulegraphs
from std/browsers import openDefaultBrowser
from browsers import openDefaultBrowser
from nodejs import findNodeJs
when hasTinyCBackend:
@@ -91,9 +91,6 @@ proc getNimRunExe(conf: ConfigRef): string =
if conf.isDefined("mingw"):
if conf.isDefined("i386"): result = "wine"
elif conf.isDefined("amd64"): result = "wine64"
else: result = ""
else:
result = ""
proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
let self = NimProg(
@@ -116,8 +113,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
conf.backend = backendC
if conf.selectedGC == gcUnselected:
if conf.backend in {backendC, backendCpp, backendObjc, backendNir} or
(conf.cmd == cmdInteractive and isDefined(conf, "nir")):
if conf.backend in {backendC, backendCpp, backendObjc}:
initOrcDefines(conf)
mainCommand(graph)
@@ -141,7 +137,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
# tasyncjs_fail` would fail, refs https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode
if cmdPrefix.len == 0: cmdPrefix = findNodeJs().quoteShell
cmdPrefix.add " --unhandled-rejections=strict"
else: raiseAssert $conf.backend
else: doAssert false, $conf.backend
if cmdPrefix.len > 0: cmdPrefix.add " "
# without the `cmdPrefix.len > 0` check, on windows you'd get a cryptic:
# `The parameter is incorrect`

View File

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

View File

@@ -10,10 +10,8 @@
# This module handles the reading of the config file.
import
llstream, commands, msgs, lexer, ast,
options, idents, wordrecg, lineinfos, pathutils, scriptconfig
import std/[os, strutils, strtabs]
llstream, commands, os, strutils, msgs, lexer, ast,
options, idents, wordrecg, strtabs, lineinfos, pathutils, scriptconfig
when defined(nimPreviewSlimSystem):
import std/syncio
@@ -164,7 +162,7 @@ proc checkSymbol(L: Lexer, tok: Token) =
lexMessage(L, errGenerated, "expected identifier, but got: " & $tok)
proc parseAssignment(L: var Lexer, tok: var Token;
config: ConfigRef; filename: AbsoluteFile; condStack: var seq[bool]) =
config: ConfigRef; condStack: var seq[bool]) =
if tok.ident != nil:
if tok.ident.s == "-" or tok.ident.s == "--":
confTok(L, tok, config, condStack) # skip unnecessary prefix
@@ -207,7 +205,6 @@ proc parseAssignment(L: var Lexer, tok: var Token;
checkSymbol(L, tok)
val.add($tok)
confTok(L, tok, config, condStack)
config.currentConfigDir = parentDir(filename.string)
if percent:
processSwitch(s, strtabs.`%`(val, config.configVars,
{useEnvironment, useEmpty}), passPP, info, config)
@@ -217,21 +214,20 @@ proc parseAssignment(L: var Lexer, tok: var Token;
proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
config: ConfigRef): bool =
var
L: Lexer = default(Lexer)
L: Lexer
tok: Token
stream: PLLStream
stream = llStreamOpen(filename, fmRead)
if stream != nil:
initToken(tok)
openLexer(L, filename, stream, cache, config)
tok.tokType = tkEof # to avoid a pointless warning
var condStack: seq[bool] = @[]
confTok(L, tok, config, condStack) # read in the first token
while tok.tokType != tkEof: parseAssignment(L, tok, config, filename, condStack)
while tok.tokType != tkEof: parseAssignment(L, tok, config, condStack)
if condStack.len > 0: lexMessage(L, errGenerated, "expected @end")
closeLexer(L)
return true
else:
result = false
proc getUserConfigPath*(filename: RelativeFile): AbsoluteFile =
result = getConfigDir().AbsoluteDir / RelativeDir"nim" / filename
@@ -254,7 +250,7 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen:
template runNimScriptIfExists(path: AbsoluteFile, isMain = false) =
let p = path # eval once
var s: PLLStream = nil
var s: PLLStream
if isMain and optWasNimscript in conf.globalOptions:
if conf.projectIsStdin: s = stdin.llStreamOpen
elif conf.projectIsCmd: s = llStreamOpen(conf.cmdInput)

View File

@@ -40,7 +40,7 @@ proc selectUniqueSymbol*(i: Interpreter; name: string;
assert i != nil
assert i.mainModule != nil, "no main module selected"
let n = getIdent(i.graph.cache, name)
var it: ModuleIter
var it: ModuleIter = default(ModuleIter)
var s = initModuleIter(it, i.graph, i.mainModule, n)
result = nil
while s != nil:

View File

@@ -12,9 +12,8 @@
# handling that exists! Only at line endings checks are necessary
# if the buffer needs refilling.
import llstream
import std/strutils
import
llstream, strutils
when defined(nimPreviewSlimSystem):
import std/assertions

View File

@@ -17,7 +17,7 @@ interpolation variables:
Unstable API
]##
import std/[os, strutils]
import os, strutils
when defined(nimPreviewSlimSystem):
import std/assertions

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,983 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# We produce C code as a list of tokens.
import std / [assertions, syncio, tables, intsets, formatfloat]
from std / strutils import toOctal
import .. / ic / [bitabs, rodfiles]
import nirtypes, nirinsts, nirfiles
import ../../dist/checksums/src/checksums/md5
type
Token = LitId # indexing into the tokens BiTable[string]
PredefinedToken = enum
IgnoreMe = "<unused>"
EmptyToken = ""
CurlyLe = "{"
CurlyRi = "}"
ParLe = "("
ParRi = ")"
BracketLe = "["
BracketRi = "]"
NewLine = "\n"
Semicolon = ";"
Comma = ", "
Space = " "
Colon = ": "
Dot = "."
Arrow = "->"
Star = "*"
Amp = "&"
AsgnOpr = " = "
ScopeOpr = "::"
ConstKeyword = "const "
StaticKeyword = "static "
ExternKeyword = "extern "
WhileKeyword = "while "
IfKeyword = "if ("
ElseKeyword = "else "
SwitchKeyword = "switch "
CaseKeyword = "case "
DefaultKeyword = "default:"
BreakKeyword = "break"
NullPtr = "nullptr"
IfNot = "if (!("
ReturnKeyword = "return "
TypedefStruct = "typedef struct "
TypedefUnion = "typedef union "
IncludeKeyword = "#include "
proc fillTokenTable(tab: var BiTable[string]) =
for e in EmptyToken..high(PredefinedToken):
let id = tab.getOrIncl $e
assert id == LitId(e), $(id, " ", ord(e))
type
GeneratedCode* = object
m: NirModule
includes: seq[LitId]
includedHeaders: IntSet
data: seq[LitId]
protos: seq[LitId]
code: seq[LitId]
init: seq[LitId]
tokens: BiTable[string]
emittedStrings: IntSet
needsPrefix: IntSet
generatedTypes: IntSet
mangledModules: Table[LitId, LitId]
proc initGeneratedCode*(m: sink NirModule): GeneratedCode =
result = GeneratedCode(m: m, code: @[], tokens: initBiTable[string]())
fillTokenTable(result.tokens)
proc add*(g: var GeneratedCode; t: PredefinedToken) {.inline.} =
g.code.add Token(t)
proc add*(g: var GeneratedCode; s: string) {.inline.} =
g.code.add g.tokens.getOrIncl(s)
proc mangleModuleName(c: var GeneratedCode; key: LitId): LitId =
result = c.mangledModules.getOrDefault(key, LitId(0))
if result == LitId(0):
let u {.cursor.} = c.m.lit.strings[key]
var last = u.len - len(".nim") - 1
var start = last
while start >= 0 and u[start] != '/': dec start
var sum = getMD5(u)
sum.setLen(8)
let dest = u.substr(start+1, last) & sum
result = c.tokens.getOrIncl(dest)
c.mangledModules[key] = result
type
CppFile = object
f: File
proc write(f: var CppFile; s: string) = write(f.f, s)
proc write(f: var CppFile; c: char) = write(f.f, c)
proc writeTokenSeq(f: var CppFile; s: seq[Token]; c: GeneratedCode) =
var indent = 0
for i in 0..<s.len:
let x = s[i]
case x
of Token(CurlyLe):
inc indent
write f, c.tokens[x]
write f, "\n"
for i in 1..indent*2: write f, ' '
of Token(CurlyRi):
dec indent
write f, c.tokens[x]
if i+1 < s.len and s[i+1] == Token(CurlyRi):
discard
else:
write f, "\n"
for i in 1..indent*2: write f, ' '
of Token(Semicolon):
write f, c.tokens[x]
if i+1 < s.len and s[i+1] == Token(CurlyRi):
discard "no newline before }"
else:
write f, "\n"
for i in 1..indent*2: write f, ' '
of Token(NewLine):
write f, c.tokens[x]
for i in 1..indent*2: write f, ' '
else:
write f, c.tokens[x]
# Type graph
type
TypeList = object
processed: IntSet
s: seq[(TypeId, PredefinedToken)]
proc add(dest: var TypeList; elem: TypeId; decl: PredefinedToken) =
if not containsOrIncl(dest.processed, int(elem)):
dest.s.add (elem, decl)
type
TypeOrder = object
forwardedDecls, ordered: TypeList
typeImpls: Table[string, TypeId]
lookedAt: IntSet
proc traverseObject(types: TypeGraph; lit: Literals; c: var TypeOrder; t: TypeId)
proc recordDependency(types: TypeGraph; lit: Literals; c: var TypeOrder; parent, child: TypeId) =
var ch = child
var viaPointer = false
while true:
case types[ch].kind
of APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy:
viaPointer = true
ch = elementType(types, ch)
of LastArrayTy:
ch = elementType(types, ch)
else:
break
case types[ch].kind
of ObjectTy, UnionTy:
let decl = if types[ch].kind == ObjectTy: TypedefStruct else: TypedefUnion
let obj = c.typeImpls.getOrDefault(lit.strings[types[ch].litId])
if viaPointer:
c.forwardedDecls.add obj, decl
else:
if not containsOrIncl(c.lookedAt, obj.int):
traverseObject(types, lit, c, obj)
c.ordered.add obj, decl
of ArrayTy:
if viaPointer:
c.forwardedDecls.add ch, TypedefStruct
else:
if not containsOrIncl(c.lookedAt, ch.int):
traverseObject(types, lit, c, ch)
c.ordered.add ch, TypedefStruct
else:
discard "uninteresting type as we only focus on the required struct declarations"
proc traverseObject(types: TypeGraph; lit: Literals; c: var TypeOrder; t: TypeId) =
for x in sons(types, t):
case types[x].kind
of FieldDecl:
recordDependency types, lit, c, t, x.firstSon
of ObjectTy:
# inheritance
recordDependency types, lit, c, t, x
else: discard
proc traverseTypes(types: TypeGraph; lit: Literals; c: var TypeOrder) =
for t in allTypes(types):
if types[t].kind in {ObjectDecl, UnionDecl}:
assert types[t.firstSon].kind == NameVal
c.typeImpls[lit.strings[types[t.firstSon].litId]] = t
for t in allTypesIncludingInner(types):
case types[t].kind
of ObjectDecl, UnionDecl:
traverseObject types, lit, c, t
let decl = if types[t].kind == ObjectDecl: TypedefStruct else: TypedefUnion
c.ordered.add t, decl
of ArrayTy:
traverseObject types, lit, c, t
c.ordered.add t, TypedefStruct
else: discard
when false:
template emitType(s: string) = c.types.add c.tokens.getOrIncl(s)
template emitType(t: Token) = c.types.add t
template emitType(t: PredefinedToken) = c.types.add Token(t)
proc genType(g: var GeneratedCode; types: TypeGraph; lit: Literals; t: TypeId; name = "") =
template maybeAddName =
if name != "":
g.add Space
g.add name
template atom(s: string) =
g.add s
maybeAddName()
case types[t].kind
of VoidTy: atom "void"
of IntTy: atom "NI" & $types[t].integralBits
of UIntTy: atom "NU" & $types[t].integralBits
of FloatTy: atom "NF" & $types[t].integralBits
of BoolTy: atom "NB" & $types[t].integralBits
of CharTy: atom "NC" & $types[t].integralBits
of ObjectTy, UnionTy, NameVal, AnnotationVal:
atom lit.strings[types[t].litId]
of VarargsTy:
g.add "..."
of APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy:
genType g, types, lit, elementType(types, t)
g.add Star
maybeAddName()
of ArrayTy:
genType g, types, lit, arrayName(types, t)
maybeAddName()
of LastArrayTy:
genType g, types, lit, elementType(types, t)
maybeAddName()
g.add BracketLe
g.add BracketRi
of ProcTy:
let (retType, callConv) = returnType(types, t)
genType g, types, lit, retType
g.add Space
g.add ParLe
genType g, types, lit, callConv
g.add Star # "(*fn)"
maybeAddName()
g.add ParRi
g.add ParLe
var i = 0
for ch in params(types, t):
if i > 0: g.add Comma
genType g, types, lit, ch
inc i
g.add ParRi
of ObjectDecl, UnionDecl:
atom lit.strings[types[t.firstSon].litId]
of IntVal, SizeVal, AlignVal, OffsetVal, FieldDecl:
#raiseAssert "did not expect: " & $types[t].kind
g.add "BUG "
atom $types[t].kind
proc generateTypes(g: var GeneratedCode; types: TypeGraph; lit: Literals; c: TypeOrder) =
for (t, declKeyword) in c.forwardedDecls.s:
let name = if types[t].kind == ArrayTy: arrayName(types, t) else: t.firstSon
let s {.cursor.} = lit.strings[types[name].litId]
g.add declKeyword
g.add s
g.add Space
g.add s
g.add Semicolon
for (t, declKeyword) in c.ordered.s:
let name = if types[t].kind == ArrayTy: arrayName(types, t) else: t.firstSon
let litId = types[name].litId
if not g.generatedTypes.containsOrIncl(litId.int):
let s {.cursor.} = lit.strings[litId]
g.add declKeyword
g.add CurlyLe
if types[t].kind == ArrayTy:
genType g, types, lit, elementType(types, t), "a"
g.add BracketLe
g.add $arrayLen(types, t)
g.add BracketRi
g.add Semicolon
else:
var i = 0
for x in sons(types, t):
case types[x].kind
of FieldDecl:
genType g, types, lit, x.firstSon, "F" & $i
g.add Semicolon
inc i
of ObjectTy:
genType g, types, lit, x, "P"
g.add Semicolon
else: discard
g.add CurlyRi
g.add s
g.add Semicolon
# Procs
proc toCChar*(c: char; result: var string) {.inline.} =
case c
of '\0'..'\x1F', '\x7F'..'\xFF':
result.add '\\'
result.add toOctal(c)
of '\'', '\"', '\\', '?':
result.add '\\'
result.add c
else:
result.add c
proc makeCString(s: string): string =
result = newStringOfCap(s.len + 10)
result.add('"')
for c in s: toCChar(c, result)
result.add('"')
template emitData(s: string) = c.data.add c.tokens.getOrIncl(s)
template emitData(t: Token) = c.data.add t
template emitData(t: PredefinedToken) = c.data.add Token(t)
proc genStrLit(c: var GeneratedCode; lit: Literals; litId: LitId): Token =
result = Token(c.tokens.getOrIncl "QStr" & $litId)
if not containsOrIncl(c.emittedStrings, int(litId)):
let s {.cursor.} = lit.strings[litId]
emitData "static const struct "
emitData CurlyLe
emitData "NI cap"
emitData Semicolon
emitData "NC8 data"
emitData BracketLe
emitData $s.len
emitData "+1"
emitData BracketRi
emitData Semicolon
emitData CurlyRi
emitData result
emitData AsgnOpr
emitData CurlyLe
emitData $s.len
emitData " | NIM_STRLIT_FLAG"
emitData Comma
emitData makeCString(s)
emitData CurlyRi
emitData Semicolon
proc genIntLit(c: var GeneratedCode; lit: Literals; litId: LitId) =
let i = lit.numbers[litId]
if i > low(int32) and i <= high(int32):
c.add $i
elif i == low(int32):
# Nim has the same bug for the same reasons :-)
c.add "(-2147483647 -1)"
elif i > low(int64):
c.add "IL64("
c.add $i
c.add ")"
else:
c.add "(IL64(-9223372036854775807) - IL64(1))"
proc gen(c: var GeneratedCode; t: Tree; n: NodePos)
proc genDisplayName(c: var GeneratedCode; symId: SymId) =
let displayName = c.m.symnames[symId]
if displayName != LitId(0):
c.add "/*"
c.add c.m.lit.strings[displayName]
c.add "*/"
proc genSymDef(c: var GeneratedCode; t: Tree; n: NodePos) =
if t[n].kind == SymDef:
let symId = t[n].symId
c.needsPrefix.incl symId.int
genDisplayName c, symId
gen c, t, n
proc genGlobal(c: var GeneratedCode; t: Tree; name, typ: NodePos; annotation: string) =
c.add annotation
let m: string
if t[name].kind == SymDef:
let symId = t[name].symId
m = c.tokens[mangleModuleName(c, c.m.namespace)] & "__" & $symId
genDisplayName c, symId
else:
assert t[name].kind == ModuleSymUse
let (x, y) = sons2(t, name)
m = c.tokens[mangleModuleName(c, t[x].litId)] & "__" & $t[y].immediateVal
genType c, c.m.types, c.m.lit, t[typ].typeId, m
proc genLocal(c: var GeneratedCode; t: Tree; name, typ: NodePos; annotation: string) =
assert t[name].kind == SymDef
c.add annotation
let symId = t[name].symId
genType c, c.m.types, c.m.lit, t[typ].typeId, "q" & $symId
genDisplayName c, symId
proc genProcDecl(c: var GeneratedCode; t: Tree; n: NodePos; isExtern: bool) =
let signatureBegin = c.code.len
let name = n.firstSon
var prc = n.firstSon
next t, prc
while true:
case t[prc].kind
of PragmaPair:
let (x, y) = sons2(t, prc)
let key = cast[PragmaKey](t[x].rawOperand)
case key
of HeaderImport:
let lit = t[y].litId
let headerAsStr {.cursor.} = c.m.lit.strings[lit]
let header = c.tokens.getOrIncl(headerAsStr)
# headerAsStr can be empty, this has the semantics of the `nodecl` pragma:
if headerAsStr.len > 0 and not c.includedHeaders.containsOrIncl(int header):
if headerAsStr[0] == '#':
discard "skip the #include"
else:
c.includes.add Token(IncludeKeyword)
c.includes.add header
c.includes.add Token NewLine
# do not generate code for importc'ed procs:
return
of DllImport:
let lit = t[y].litId
raiseAssert "cannot eval: " & c.m.lit.strings[lit]
else: discard
of PragmaId: discard
else: break
next t, prc
var resultDeclPos = NodePos(-1)
if t[prc].kind == SummonResult:
resultDeclPos = prc
gen c, t, prc.firstSon
next t, prc
else:
c.add "void"
c.add Space
genSymDef c, t, name
c.add ParLe
var params = 0
while t[prc].kind == SummonParam:
if params > 0: c.add Comma
let (typ, sym) = sons2(t, prc)
genLocal c, t, sym, typ, ""
next t, prc
inc params
if params == 0:
c.add "void"
c.add ParRi
for i in signatureBegin ..< c.code.len:
c.protos.add c.code[i]
c.protos.add Token Semicolon
if isExtern:
c.code.setLen signatureBegin
else:
c.add CurlyLe
if resultDeclPos.int >= 0:
gen c, t, resultDeclPos
for ch in sonsRest(t, n, prc):
gen c, t, ch
c.add CurlyRi
template triop(opr) =
let (typ, a, b) = sons3(t, n)
c.add ParLe
c.add ParLe
gen c, t, typ
c.add ParRi
gen c, t, a
c.add opr
gen c, t, b
c.add ParRi
template cmpop(opr) =
let (_, a, b) = sons3(t, n)
c.add ParLe
gen c, t, a
c.add opr
gen c, t, b
c.add ParRi
template binaryop(opr) =
let (typ, a) = sons2(t, n)
c.add ParLe
c.add ParLe
gen c, t, typ
c.add ParRi
c.add opr
gen c, t, a
c.add ParRi
template checkedBinaryop(opr) =
let (typ, labIdx, a, b) = sons4(t, n)
let bits = integralBits(c.m.types[t[typ].typeId])
let lab = t[labIdx].label
c.add (opr & $bits)
c.add ParLe
c.gen t, a
c.add Comma
c.gen t, b
c.add Comma
c.add "L" & $lab.int
c.add ParRi
proc genNumberConv(c: var GeneratedCode; t: Tree; n: NodePos) =
let (typ, arg) = sons2(t, n)
if t[arg].kind == IntVal:
let litId = t[arg].litId
c.add ParLe
c.add ParLe
gen c, t, typ
c.add ParRi
case c.m.types[t[typ].typeId].kind
of UIntTy:
let x = cast[uint64](c.m.lit.numbers[litId])
c.add $x
of FloatTy:
let x = cast[float64](c.m.lit.numbers[litId])
c.add $x
else:
gen c, t, arg
c.add ParRi
else:
binaryop ""
template moveToDataSection(body: untyped) =
let oldLen = c.code.len
body
for i in oldLen ..< c.code.len:
c.data.add c.code[i]
setLen c.code, oldLen
proc gen(c: var GeneratedCode; t: Tree; n: NodePos) =
case t[n].kind
of Nop:
discard "nothing to emit"
of ImmediateVal:
c.add $t[n].immediateVal
of IntVal:
genIntLit c, c.m.lit, t[n].litId
of StrVal:
c.code.add genStrLit(c, c.m.lit, t[n].litId)
of Typed:
genType c, c.m.types, c.m.lit, t[n].typeId
of SymDef, SymUse:
let s = t[n].symId
if c.needsPrefix.contains(s.int):
c.code.add mangleModuleName(c, c.m.namespace)
c.add "__"
c.add $s
else:
# XXX Use proper names here
c.add "q"
c.add $s
of ModuleSymUse:
let (x, y) = sons2(t, n)
let u = mangleModuleName(c, t[x].litId)
let s = t[y].immediateVal
c.code.add u
c.add "__"
c.add $s
of NilVal:
c.add NullPtr
of LoopLabel:
c.add WhileKeyword
c.add ParLe
c.add "1"
c.add ParRi
c.add CurlyLe
of GotoLoop:
c.add CurlyRi
of Label:
let lab = t[n].label
c.add "L"
c.add $lab.int
c.add Colon
c.add Semicolon
of Goto:
let lab = t[n].label
c.add "goto L"
c.add $lab.int
c.add Semicolon
of CheckedGoto:
discard "XXX todo"
of ArrayConstr:
c.add CurlyLe
c.add ".a = "
c.add CurlyLe
var i = 0
for ch in sonsFrom1(t, n):
if i > 0: c.add Comma
c.gen t, ch
inc i
c.add CurlyRi
c.add CurlyRi
of ObjConstr:
c.add CurlyLe
var i = 0
for ch in sonsFrom1(t, n):
if i mod 2 == 0:
if i > 0: c.add Comma
c.add ".F" & $t[ch].immediateVal
c.add AsgnOpr
else:
c.gen t, ch
inc i
c.add CurlyRi
of Ret:
c.add ReturnKeyword
c.gen t, n.firstSon
c.add Semicolon
of Select:
c.add SwitchKeyword
c.add ParLe
let (_, selector) = sons2(t, n)
c.gen t, selector
c.add ParRi
c.add CurlyLe
for ch in sonsFromN(t, n, 2):
c.gen t, ch
c.add CurlyRi
of SelectPair:
let (le, ri) = sons2(t, n)
c.gen t, le
c.gen t, ri
of SelectList:
for ch in sons(t, n):
c.gen t, ch
of SelectValue:
c.add CaseKeyword
c.gen t, n.firstSon
c.add Colon
of SelectRange:
let (le, ri) = sons2(t, n)
c.add CaseKeyword
c.gen t, le
c.add " ... "
c.gen t, ri
c.add Colon
of ForeignDecl:
c.data.add LitId(ExternKeyword)
c.gen t, n.firstSon
of SummonGlobal:
moveToDataSection:
let (typ, sym) = sons2(t, n)
c.genGlobal t, sym, typ, ""
c.add Semicolon
of SummonThreadLocal:
moveToDataSection:
let (typ, sym) = sons2(t, n)
c.genGlobal t, sym, typ, "__thread "
c.add Semicolon
of SummonConst:
moveToDataSection:
let (typ, sym, val) = sons3(t, n)
c.genGlobal t, sym, typ, "const "
c.add AsgnOpr
c.gen t, val
c.add Semicolon
of Summon, SummonResult:
let (typ, sym) = sons2(t, n)
c.genLocal t, sym, typ, ""
c.add Semicolon
of SummonParam:
raiseAssert "SummonParam should have been handled in genProc"
of Kill:
discard "we don't care about Kill instructions"
of AddrOf:
let (_, arg) = sons2(t, n)
c.add "&"
gen c, t, arg
of DerefArrayAt:
let (_, a, i) = sons3(t, n)
gen c, t, a
c.add BracketLe
gen c, t, i
c.add BracketRi
of ArrayAt:
let (_, a, i) = sons3(t, n)
gen c, t, a
c.add Dot
c.add "a"
c.add BracketLe
gen c, t, i
c.add BracketRi
of FieldAt:
let (_, a, b) = sons3(t, n)
gen c, t, a
let field = t[b].immediateVal
c.add Dot
c.add "F" & $field
of DerefFieldAt:
let (_, a, b) = sons3(t, n)
gen c, t, a
let field = t[b].immediateVal
c.add Arrow
c.add "F" & $field
of Load:
let (_, arg) = sons2(t, n)
c.add ParLe
c.add "*"
gen c, t, arg
c.add ParRi
of Store:
raiseAssert "Assumption was that Store is unused!"
of Asgn:
let (_, dest, src) = sons3(t, n)
gen c, t, dest
c.add AsgnOpr
gen c, t, src
c.add Semicolon
of CheckedRange:
c.add "nimCheckRange"
c.add ParLe
let (_, gotoInstr, x, a, b) = sons5(t, n)
gen c, t, x
c.add Comma
gen c, t, a
c.add Comma
gen c, t, b
c.add Comma
c.add "L" & $t[gotoInstr].label.int
c.add ParRi
of CheckedIndex:
c.add "nimCheckIndex"
c.add ParLe
let (gotoInstr, x, a) = sons3(t, n)
gen c, t, x
c.add Comma
gen c, t, a
c.add Comma
c.add "L" & $t[gotoInstr].label.int
c.add ParRi
of Call, IndirectCall:
let (typ, fn) = sons2(t, n)
gen c, t, fn
c.add ParLe
var i = 0
for ch in sonsFromN(t, n, 2):
if i > 0: c.add Comma
gen c, t, ch
inc i
c.add ParRi
if c.m.types[t[typ].typeId].kind == VoidTy:
c.add Semicolon
of CheckedCall, CheckedIndirectCall:
let (typ, gotoInstr, fn) = sons3(t, n)
gen c, t, fn
c.add ParLe
var i = 0
for ch in sonsFromN(t, n, 3):
if i > 0: c.add Comma
gen c, t, ch
inc i
c.add ParRi
if c.m.types[t[typ].typeId].kind == VoidTy:
c.add Semicolon
of CheckedAdd: checkedBinaryop "nimAddInt"
of CheckedSub: checkedBinaryop "nimSubInt"
of CheckedMul: checkedBinaryop "nimMulInt"
of CheckedDiv: checkedBinaryop "nimDivInt"
of CheckedMod: checkedBinaryop "nimModInt"
of Add: triop " + "
of Sub: triop " - "
of Mul: triop " * "
of Div: triop " / "
of Mod: triop " % "
of BitShl: triop " << "
of BitShr: triop " >> "
of BitAnd: triop " & "
of BitOr: triop " | "
of BitXor: triop " ^ "
of BitNot: binaryop " ~ "
of BoolNot: binaryop " !"
of Eq: cmpop " == "
of Le: cmpop " <= "
of Lt: cmpop " < "
of Cast: binaryop ""
of NumberConv: genNumberConv c, t, n
of CheckedObjConv: binaryop ""
of ObjConv: binaryop ""
of Emit: raiseAssert "cannot interpret: Emit"
of ProcDecl: genProcDecl c, t, n, false
of ForeignProcDecl: genProcDecl c, t, n, true
of PragmaPair, PragmaId, TestOf, Yld, SetExc, TestExc:
c.add "cannot interpret: " & $t[n].kind
const
Prelude = """
/* GENERATED CODE. DO NOT EDIT. */
#ifdef __cplusplus
#define NB8 bool
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901)
// see #13798: to avoid conflicts for code emitting `#include <stdbool.h>`
#define NB8 _Bool
#else
typedef unsigned char NB8; // best effort
#endif
typedef unsigned char NC8;
typedef float NF32;
typedef double NF64;
#if defined(__BORLANDC__) || defined(_MSC_VER)
typedef signed char NI8;
typedef signed short int NI16;
typedef signed int NI32;
typedef __int64 NI64;
/* XXX: Float128? */
typedef unsigned char NU8;
typedef unsigned short int NU16;
typedef unsigned int NU32;
typedef unsigned __int64 NU64;
#elif defined(HAVE_STDINT_H)
#ifndef USE_NIM_NAMESPACE
# include <stdint.h>
#endif
typedef int8_t NI8;
typedef int16_t NI16;
typedef int32_t NI32;
typedef int64_t NI64;
typedef uint8_t NU8;
typedef uint16_t NU16;
typedef uint32_t NU32;
typedef uint64_t NU64;
#elif defined(HAVE_CSTDINT)
#ifndef USE_NIM_NAMESPACE
# include <cstdint>
#endif
typedef std::int8_t NI8;
typedef std::int16_t NI16;
typedef std::int32_t NI32;
typedef std::int64_t NI64;
typedef std::uint8_t NU8;
typedef std::uint16_t NU16;
typedef std::uint32_t NU32;
typedef std::uint64_t NU64;
#else
/* Unknown compiler/version, do our best */
#ifdef __INT8_TYPE__
typedef __INT8_TYPE__ NI8;
#else
typedef signed char NI8;
#endif
#ifdef __INT16_TYPE__
typedef __INT16_TYPE__ NI16;
#else
typedef signed short int NI16;
#endif
#ifdef __INT32_TYPE__
typedef __INT32_TYPE__ NI32;
#else
typedef signed int NI32;
#endif
#ifdef __INT64_TYPE__
typedef __INT64_TYPE__ NI64;
#else
typedef long long int NI64;
#endif
/* XXX: Float128? */
#ifdef __UINT8_TYPE__
typedef __UINT8_TYPE__ NU8;
#else
typedef unsigned char NU8;
#endif
#ifdef __UINT16_TYPE__
typedef __UINT16_TYPE__ NU16;
#else
typedef unsigned short int NU16;
#endif
#ifdef __UINT32_TYPE__
typedef __UINT32_TYPE__ NU32;
#else
typedef unsigned int NU32;
#endif
#ifdef __UINT64_TYPE__
typedef __UINT64_TYPE__ NU64;
#else
typedef unsigned long long int NU64;
#endif
#endif
#ifdef NIM_INTBITS
# if NIM_INTBITS == 64
typedef NI64 NI;
typedef NU64 NU;
# elif NIM_INTBITS == 32
typedef NI32 NI;
typedef NU32 NU;
# elif NIM_INTBITS == 16
typedef NI16 NI;
typedef NU16 NU;
# elif NIM_INTBITS == 8
typedef NI8 NI;
typedef NU8 NU;
# else
# error "invalid bit width for int"
# endif
#endif
#define NIM_STRLIT_FLAG ((NU)(1) << ((NIM_INTBITS) - 2)) /* This has to be the same as system.strlitFlag! */
#define nimAddInt64(a, b, L) ({long long int res; if(__builtin_saddll_overflow(a, b, &res)) goto L; res})
#define nimSubInt64(a, b, L) ({long long int res; if(__builtin_ssubll_overflow(a, b, &res)) goto L; res})
#define nimMulInt64(a, b, L) ({long long int res; if(__builtin_smulll_overflow(a, b, &res)) goto L; res})
#define nimAddInt32(a, b, L) ({long int res; if(__builtin_sadd_overflow(a, b, &res)) goto L; res})
#define nimSubInt32(a, b, L) ({long int res; if(__builtin_ssub_overflow(a, b, &res)) goto L; res})
#define nimMulInt32(a, b, L) ({long int res; if(__builtin_smul_overflow(a, b, &res)) goto L; res})
#define nimCheckRange(x, a, b, L) ({if (x < a || x > b) goto L; x})
#define nimCheckIndex(x, a, L) ({if (x >= a) goto L; x})
"""
proc traverseCode(c: var GeneratedCode) =
const AllowedInToplevelC = {SummonConst, SummonGlobal, SummonThreadLocal,
ProcDecl, ForeignDecl, ForeignProcDecl}
var i = NodePos(0)
while i.int < c.m.code.len:
let oldLen = c.code.len
let moveToInitSection = c.m.code[NodePos(i)].kind notin AllowedInToplevelC
gen c, c.m.code, NodePos(i)
next c.m.code, i
if moveToInitSection:
for i in oldLen ..< c.code.len:
c.init.add c.code[i]
setLen c.code, oldLen
proc generateCode*(inp, outp: string) =
var c = initGeneratedCode(load(inp))
var co = TypeOrder()
traverseTypes(c.m.types, c.m.lit, co)
generateTypes(c, c.m.types, c.m.lit, co)
let typeDecls = move c.code
traverseCode c
var f = CppFile(f: open(outp, fmWrite))
f.write "#define NIM_INTBITS " & $c.m.intbits & "\n"
f.write Prelude
writeTokenSeq f, c.includes, c
writeTokenSeq f, typeDecls, c
writeTokenSeq f, c.data, c
writeTokenSeq f, c.protos, c
writeTokenSeq f, c.code, c
if c.init.len > 0:
f.write "void __attribute__((constructor)) init(void) {"
writeTokenSeq f, c.init, c
f.write "}\n\n"
f.f.close

View File

@@ -1,105 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Nim Intermediate Representation, designed to capture all of Nim's semantics without losing too much
## precious information. Can easily be translated into C. And to JavaScript, hopefully.
from std/os import addFileExt, `/`, createDir
import std / assertions
import ".." / [ast, modulegraphs, renderer, transf, options, msgs, lineinfos]
import nirtypes, nirinsts, ast2ir, nirlineinfos, nirfiles, nirvm
import ".." / ic / [rodfiles, bitabs]
type
PCtx* = ref object of TPassContext
m: ModuleCon
c: ProcCon
oldErrorCount: int
bytecode: Bytecode
proc newCtx*(module: PSym; g: ModuleGraph; idgen: IdGenerator): PCtx =
var lit = Literals()
var nirm = (ref NirModule)(types: initTypeGraph(lit), lit: lit)
var m = initModuleCon(g, g.config, idgen, module, nirm)
m.noModularity = true
PCtx(m: m, c: initProcCon(m, nil, g.config), idgen: idgen, bytecode: initBytecode(nirm))
proc refresh*(c: PCtx; module: PSym; idgen: IdGenerator) =
#c.m = initModuleCon(c.m.graph, c.m.graph.config, idgen, module, c.m.nirm)
#c.m.noModularity = true
c.c = initProcCon(c.m, nil, c.m.graph.config)
c.idgen = idgen
proc setupGlobalCtx*(module: PSym; graph: ModuleGraph; idgen: IdGenerator) =
if graph.repl.isNil:
graph.repl = newCtx(module, graph, idgen)
#registerAdditionalOps(PCtx graph.repl)
else:
refresh(PCtx graph.repl, module, idgen)
proc setupNirReplGen*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
setupGlobalCtx(module, graph, idgen)
result = PCtx graph.repl
proc evalStmt(c: PCtx; n: PNode) =
let n = transformExpr(c.m.graph, c.idgen, c.m.module, n)
let pc = genStmt(c.c, n)
#var res = ""
#toString c.m.nirm.code, NodePos(pc), c.m.nirm.lit.strings, c.m.nirm.lit.numbers, c.m.symnames, res
#res.add "\n--------------------------\n"
#toString res, c.m.types.g
if pc.int < c.m.nirm.code.len:
c.bytecode.interactive = c.m.graph.interactive
execCode c.bytecode, c.m.nirm.code, pc
#echo res
proc runCode*(c: PPassContext; n: PNode): PNode =
let c = PCtx(c)
# don't eval errornous code:
if c.oldErrorCount == c.m.graph.config.errorCounter:
evalStmt(c, n)
result = newNodeI(nkEmpty, n.info)
else:
result = n
c.oldErrorCount = c.m.graph.config.errorCounter
type
NirPassContext* = ref object of TPassContext
m: ModuleCon
c: ProcCon
proc openNirBackend*(g: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
var lit = Literals()
var nirm = (ref NirModule)(types: initTypeGraph(lit), lit: lit)
let m = initModuleCon(g, g.config, idgen, module, nirm)
NirPassContext(m: m, c: initProcCon(m, nil, g.config), idgen: idgen)
proc gen(c: NirPassContext; n: PNode) =
let n = transformExpr(c.m.graph, c.idgen, c.m.module, n)
let pc = genStmt(c.c, n)
proc nirBackend*(c: PPassContext; n: PNode): PNode =
gen(NirPassContext(c), n)
result = n
proc closeNirBackend*(c: PPassContext; finalNode: PNode) =
discard nirBackend(c, finalNode)
let c = NirPassContext(c)
let nimcache = getNimcacheDir(c.c.config).string
createDir nimcache
let outp = nimcache / c.m.module.name.s.addFileExt("nir")
#c.m.nirm.code = move c.c.code
try:
store c.m.nirm[], outp
echo "created: ", outp
except IOError:
rawMessage(c.c.config, errFatal, "serialization failed: " & outp)

View File

@@ -1,52 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Nir Compiler.
import ".." / ic / [bitabs, rodfiles]
import nirinsts, nirtypes, nirlineinfos, nirfiles, cir
proc view(filename: string) =
let m = load(filename)
var res = ""
allTreesToString m.code, m.lit.strings, m.lit.numbers, m.symnames, res
res.add "\n# TYPES\n"
nirtypes.toString res, m.types
echo res
import std / [syncio, parseopt]
proc writeHelp =
echo """Usage: nirc view|c <file.nir>"""
quit 0
proc main =
var inp = ""
var cmd = ""
for kind, key, val in getopt():
case kind
of cmdArgument:
if cmd.len == 0: cmd = key
elif inp.len == 0: inp = key
else: quit "Error: too many arguments"
of cmdLongOption, cmdShortOption:
case key
of "help", "h": writeHelp()
of "version", "v": stdout.write "1.0\n"
of cmdEnd: discard
if inp.len == 0:
quit "Error: no input file specified"
case cmd
of "", "view":
view inp
of "c":
let outp = inp & ".c"
cir.generateCode inp, outp
main()

View File

@@ -1,83 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
import ".." / ic / [bitabs, rodfiles]
import nirinsts, nirtypes, nirlineinfos
type
NirModule* = object
code*: Tree
man*: LineInfoManager
types*: TypeGraph
lit*: Literals
namespace*: LitId
intbits*: uint32
symnames*: SymNames
proc load*(filename: string): NirModule =
let lit = Literals()
result = NirModule(lit: lit, types: initTypeGraph(lit))
var r = rodfiles.open(filename)
try:
r.loadHeader(nirCookie)
r.loadSection stringsSection
r.load result.lit.strings
r.loadSection numbersSection
r.load result.lit.numbers
r.loadSection bodiesSection
r.load result.code
r.loadSection typesSection
r.load result.types
r.loadSection sideChannelSection
r.load result.man
r.loadSection namespaceSection
r.loadPrim result.namespace
r.loadPrim result.intbits
r.loadSection symnamesSection
r.load result.symnames
finally:
r.close()
proc store*(m: NirModule; outp: string) =
var r = rodfiles.create(outp)
try:
r.storeHeader(nirCookie)
r.storeSection stringsSection
r.store m.lit.strings
r.storeSection numbersSection
r.store m.lit.numbers
r.storeSection bodiesSection
r.store m.code
r.storeSection typesSection
r.store m.types
r.storeSection sideChannelSection
r.store m.man
r.storeSection namespaceSection
r.storePrim m.namespace
r.storePrim m.intbits
r.storeSection symnamesSection
r.store m.symnames
finally:
r.close()
if r.err != ok:
raise newException(IOError, "could store into: " & outp)

View File

@@ -1,582 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## NIR instructions. Somewhat inspired by LLVM's instructions.
import std / [assertions, hashes]
import .. / ic / [bitabs, rodfiles]
import nirlineinfos, nirtypes
const
NirVersion = 1
nirCookie* = [byte(0), byte('N'), byte('I'), byte('R'),
byte(sizeof(int)*8), byte(system.cpuEndian), byte(0), byte(NirVersion)]
type
SymId* = distinct int
proc `$`*(s: SymId): string {.borrow.}
proc hash*(s: SymId): Hash {.borrow.}
proc `==`*(a, b: SymId): bool {.borrow.}
type
Opcode* = enum
Nop,
ImmediateVal,
IntVal,
StrVal,
SymDef,
SymUse,
Typed, # with type ID
PragmaId, # with Pragma ID, possible values: see PragmaKey enum
NilVal,
Label,
Goto,
CheckedGoto,
LoopLabel,
GotoLoop, # last atom
ModuleSymUse, # `"module".x`
ArrayConstr,
ObjConstr,
Ret,
Yld,
Select,
SelectPair, # ((values...), Label)
SelectList, # (values...)
SelectValue, # (value)
SelectRange, # (valueA..valueB)
ForeignDecl, # Can wrap SummonGlobal, SummonThreadLocal, SummonConst
SummonGlobal,
SummonThreadLocal,
Summon, # x = Summon Typed <Type ID>; x begins to live
SummonResult,
SummonParam,
SummonConst,
Kill, # `Kill x`: scope end for `x`
AddrOf,
ArrayAt, # a[i]
DerefArrayAt, # a[i] where `a` is a PtrArray; `a[][i]`
FieldAt, # obj.field
DerefFieldAt, # obj[].field
Load, # a[]
Store, # a[] = b
Asgn, # a = b
SetExc,
TestExc,
CheckedRange,
CheckedIndex,
Call,
IndirectCall,
CheckedCall, # call that can raise
CheckedIndirectCall, # call that can raise
CheckedAdd, # with overflow checking etc.
CheckedSub,
CheckedMul,
CheckedDiv,
CheckedMod,
Add,
Sub,
Mul,
Div,
Mod,
BitShl,
BitShr,
BitAnd,
BitOr,
BitXor,
BitNot,
BoolNot,
Eq,
Le,
Lt,
Cast,
NumberConv,
CheckedObjConv,
ObjConv,
TestOf,
Emit,
ProcDecl,
ForeignProcDecl,
PragmaPair
type
PragmaKey* = enum
FastCall, StdCall, CDeclCall, SafeCall, SysCall, InlineCall, NoinlineCall, ThisCall, NoCall,
CoreName,
ExternName,
HeaderImport,
DllImport,
DllExport,
ObjExport
const
LastAtomicValue = GotoLoop
OpcodeBits = 8'u32
OpcodeMask = (1'u32 shl OpcodeBits) - 1'u32
ValueProducingAtoms = {ImmediateVal, IntVal, StrVal, SymUse, NilVal}
ValueProducing* = {
ImmediateVal,
IntVal,
StrVal,
SymUse,
NilVal,
ModuleSymUse,
ArrayConstr,
ObjConstr,
CheckedAdd,
CheckedSub,
CheckedMul,
CheckedDiv,
CheckedMod,
Add,
Sub,
Mul,
Div,
Mod,
BitShl,
BitShr,
BitAnd,
BitOr,
BitXor,
BitNot,
BoolNot,
Eq,
Le,
Lt,
Cast,
NumberConv,
CheckedObjConv,
ObjConv,
AddrOf,
Load,
ArrayAt,
DerefArrayAt,
FieldAt,
DerefFieldAt,
TestOf
}
type
Instr* = object # 8 bytes
x: uint32
info*: PackedLineInfo
template kind*(n: Instr): Opcode = Opcode(n.x and OpcodeMask)
template operand(n: Instr): uint32 = (n.x shr OpcodeBits)
template rawOperand*(n: Instr): uint32 = (n.x shr OpcodeBits)
template toX(k: Opcode; operand: uint32): uint32 =
uint32(k) or (operand shl OpcodeBits)
template toX(k: Opcode; operand: LitId): uint32 =
uint32(k) or (operand.uint32 shl OpcodeBits)
type
Tree* = object
nodes: seq[Instr]
Values* = object
numbers: BiTable[int64]
strings: BiTable[string]
type
PatchPos* = distinct int
NodePos* = distinct int
const
InvalidPatchPos* = PatchPos(-1)
proc isValid(p: PatchPos): bool {.inline.} = p.int != -1
proc prepare*(tree: var Tree; info: PackedLineInfo; kind: Opcode): PatchPos =
result = PatchPos tree.nodes.len
tree.nodes.add Instr(x: toX(kind, 1'u32), info: info)
proc isAtom(tree: Tree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue
proc isAtom(tree: Tree; pos: NodePos): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue
proc patch*(tree: var Tree; pos: PatchPos) =
let pos = pos.int
let k = tree.nodes[pos].kind
assert k > LastAtomicValue
let distance = int32(tree.nodes.len - pos)
assert distance > 0
tree.nodes[pos].x = toX(k, cast[uint32](distance))
template build*(tree: var Tree; info: PackedLineInfo; kind: Opcode; body: untyped) =
let pos = prepare(tree, info, kind)
body
patch(tree, pos)
template buildTyped*(tree: var Tree; info: PackedLineInfo; kind: Opcode; typ: TypeId; body: untyped) =
let pos = prepare(tree, info, kind)
tree.addTyped info, typ
body
patch(tree, pos)
proc len*(tree: Tree): int {.inline.} = tree.nodes.len
template rawSpan(n: Instr): int = int(operand(n))
proc nextChild(tree: Tree; pos: var int) {.inline.} =
if tree.nodes[pos].kind > LastAtomicValue:
assert tree.nodes[pos].operand > 0'u32
inc pos, tree.nodes[pos].rawSpan
else:
inc pos
proc next*(tree: Tree; pos: var NodePos) {.inline.} = nextChild tree, int(pos)
template firstSon*(n: NodePos): NodePos = NodePos(n.int+1)
template skipTyped*(n: NodePos): NodePos = NodePos(n.int+2)
iterator sons*(tree: Tree; n: NodePos): NodePos =
var pos = n.int
assert tree.nodes[pos].kind > LastAtomicValue
let last = pos + tree.nodes[pos].rawSpan
inc pos
while pos < last:
yield NodePos pos
nextChild tree, pos
iterator sonsFrom1*(tree: Tree; n: NodePos): NodePos =
var pos = n.int
assert tree.nodes[pos].kind > LastAtomicValue
let last = pos + tree.nodes[pos].rawSpan
inc pos
nextChild tree, pos
while pos < last:
yield NodePos pos
nextChild tree, pos
iterator sonsFromN*(tree: Tree; n: NodePos; toSkip = 2): NodePos =
var pos = n.int
assert tree.nodes[pos].kind > LastAtomicValue
let last = pos + tree.nodes[pos].rawSpan
inc pos
for i in 1..toSkip:
nextChild tree, pos
while pos < last:
yield NodePos pos
nextChild tree, pos
template `[]`*(t: Tree; n: NodePos): Instr = t.nodes[n.int]
iterator sonsRest*(tree: Tree; parent, n: NodePos): NodePos =
var pos = n.int
assert tree[parent].kind > LastAtomicValue
let last = parent.int + tree[parent].rawSpan
while pos < last:
yield NodePos pos
nextChild tree, pos
proc span(tree: Tree; pos: int): int {.inline.} =
if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand)
proc copyTree*(dest: var Tree; src: Tree) =
let pos = 0
let L = span(src, pos)
let d = dest.nodes.len
dest.nodes.setLen(d + L)
assert L > 0
for i in 0..<L:
dest.nodes[d+i] = src.nodes[pos+i]
proc sons2*(tree: Tree; n: NodePos): (NodePos, NodePos) {.inline.} =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
result = (NodePos a, NodePos b)
proc sons3*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos) {.inline.} =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
let c = b + span(tree, b)
result = (NodePos a, NodePos b, NodePos c)
proc sons4*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos, NodePos) {.inline.} =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
let c = b + span(tree, b)
let d = c + span(tree, c)
result = (NodePos a, NodePos b, NodePos c, NodePos d)
proc sons5*(tree: Tree; n: NodePos): (NodePos, NodePos, NodePos, NodePos, NodePos) {.inline.} =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
let c = b + span(tree, b)
let d = c + span(tree, c)
let e = d + span(tree, d)
result = (NodePos a, NodePos b, NodePos c, NodePos d, NodePos e)
proc typeId*(ins: Instr): TypeId {.inline.} =
assert ins.kind == Typed
result = TypeId(ins.operand)
proc symId*(ins: Instr): SymId {.inline.} =
assert ins.kind in {SymUse, SymDef}
result = SymId(ins.operand)
proc immediateVal*(ins: Instr): int {.inline.} =
assert ins.kind == ImmediateVal
result = cast[int](ins.operand)
proc litId*(ins: Instr): LitId {.inline.} =
assert ins.kind in {StrVal, IntVal}
result = LitId(ins.operand)
type
LabelId* = distinct int
proc `==`*(a, b: LabelId): bool {.borrow.}
proc hash*(a: LabelId): Hash {.borrow.}
proc label*(ins: Instr): LabelId {.inline.} =
assert ins.kind in {Label, LoopLabel, Goto, GotoLoop, CheckedGoto}
result = LabelId(ins.operand)
proc newLabel*(labelGen: var int): LabelId {.inline.} =
result = LabelId labelGen
inc labelGen
proc newLabels*(labelGen: var int; n: int): LabelId {.inline.} =
result = LabelId labelGen
inc labelGen, n
proc addNewLabel*(t: var Tree; labelGen: var int; info: PackedLineInfo; k: Opcode): LabelId =
assert k in {Label, LoopLabel}
result = LabelId labelGen
t.nodes.add Instr(x: toX(k, uint32(result)), info: info)
inc labelGen
proc gotoLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) =
assert k in {Goto, GotoLoop, CheckedGoto}
t.nodes.add Instr(x: toX(k, uint32(L)), info: info)
proc addLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) {.inline.} =
assert k in {Label, LoopLabel, Goto, GotoLoop, CheckedGoto}
t.nodes.add Instr(x: toX(k, uint32(L)), info: info)
proc addSymUse*(t: var Tree; info: PackedLineInfo; s: SymId) {.inline.} =
t.nodes.add Instr(x: toX(SymUse, uint32(s)), info: info)
proc addSymDef*(t: var Tree; info: PackedLineInfo; s: SymId) {.inline.} =
t.nodes.add Instr(x: toX(SymDef, uint32(s)), info: info)
proc addNop*(t: var Tree; info: PackedLineInfo) {.inline.} =
t.nodes.add Instr(x: toX(Nop, 0'u32), info: info)
proc addTyped*(t: var Tree; info: PackedLineInfo; typ: TypeId) {.inline.} =
assert typ.int >= 0
t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info)
proc addSummon*(t: var Tree; info: PackedLineInfo; s: SymId; typ: TypeId; opc = Summon) {.inline.} =
assert typ.int >= 0
assert opc in {Summon, SummonConst, SummonGlobal, SummonThreadLocal, SummonParam, SummonResult}
let x = prepare(t, info, opc)
t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info)
t.nodes.add Instr(x: toX(SymDef, uint32(s)), info: info)
patch t, x
proc addImmediateVal*(t: var Tree; info: PackedLineInfo; x: int) =
assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int)
t.nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info)
proc addPragmaId*(t: var Tree; info: PackedLineInfo; x: PragmaKey) =
t.nodes.add Instr(x: toX(PragmaId, uint32(x)), info: info)
proc addIntVal*(t: var Tree; integers: var BiTable[int64]; info: PackedLineInfo; typ: TypeId; x: int64) =
buildTyped t, info, NumberConv, typ:
t.nodes.add Instr(x: toX(IntVal, uint32(integers.getOrIncl(x))), info: info)
proc boolVal*(t: var Tree; integers: var BiTable[int64]; info: PackedLineInfo; b: bool) =
buildTyped t, info, NumberConv, Bool8Id:
t.nodes.add Instr(x: toX(IntVal, uint32(integers.getOrIncl(ord b))), info: info)
proc addStrVal*(t: var Tree; strings: var BiTable[string]; info: PackedLineInfo; s: string) =
t.nodes.add Instr(x: toX(StrVal, uint32(strings.getOrIncl(s))), info: info)
proc addStrLit*(t: var Tree; info: PackedLineInfo; s: LitId) =
t.nodes.add Instr(x: toX(StrVal, uint32(s)), info: info)
proc addNilVal*(t: var Tree; info: PackedLineInfo; typ: TypeId) =
buildTyped t, info, NumberConv, typ:
t.nodes.add Instr(x: toX(NilVal, uint32(0)), info: info)
proc store*(r: var RodFile; t: Tree) = storeSeq r, t.nodes
proc load*(r: var RodFile; t: var Tree) = loadSeq r, t.nodes
proc escapeToNimLit*(s: string; result: var string) =
result.add '"'
for c in items s:
if c < ' ' or int(c) >= 128:
result.add '\\'
result.addInt int(c)
elif c == '\\':
result.add r"\\"
elif c == '\n':
result.add r"\n"
elif c == '\r':
result.add r"\r"
elif c == '\t':
result.add r"\t"
else:
result.add c
result.add '"'
type
SymNames* = object
s: seq[LitId]
proc `[]=`*(t: var SymNames; key: SymId; val: LitId) =
let k = int(key)
if k >= t.s.len: t.s.setLen k+1
t.s[k] = val
proc `[]`*(t: SymNames; key: SymId): LitId =
let k = int(key)
if k < t.s.len: result = t.s[k]
else: result = LitId(0)
template localName(s: SymId): string =
let name = names[s]
if name != LitId(0):
strings[name]
else:
$s.int
proc store*(r: var RodFile; t: SymNames) = storeSeq(r, t.s)
proc load*(r: var RodFile; t: var SymNames) = loadSeq(r, t.s)
proc toString*(t: Tree; pos: NodePos; strings: BiTable[string]; integers: BiTable[int64];
names: SymNames;
r: var string; nesting = 0) =
if r.len > 0 and r[r.len-1] notin {' ', '\n', '(', '[', '{'}:
r.add ' '
case t[pos].kind
of Nop: r.add "Nop"
of ImmediateVal:
r.add $t[pos].operand
of IntVal:
r.add "IntVal "
r.add $integers[LitId t[pos].operand]
of StrVal:
escapeToNimLit(strings[LitId t[pos].operand], r)
of SymDef:
r.add "SymDef "
r.add localName(SymId t[pos].operand)
of SymUse:
r.add "SymUse "
r.add localName(SymId t[pos].operand)
of PragmaId:
r.add $cast[PragmaKey](t[pos].operand)
of Typed:
r.add "T<"
r.add $t[pos].operand
r.add ">"
of NilVal:
r.add "NilVal"
of Label:
# undo the nesting:
var spaces = r.len-1
while spaces >= 0 and r[spaces] == ' ': dec spaces
r.setLen spaces+1
r.add "\n L"
r.add $t[pos].operand
of Goto, CheckedGoto, LoopLabel, GotoLoop:
r.add $t[pos].kind
r.add " L"
r.add $t[pos].operand
else:
r.add $t[pos].kind
r.add "{\n"
for i in 0..<(nesting+1)*2: r.add ' '
for p in sons(t, pos):
toString t, p, strings, integers, names, r, nesting+1
r.add "\n"
for i in 0..<nesting*2: r.add ' '
r.add "}"
proc allTreesToString*(t: Tree; strings: BiTable[string]; integers: BiTable[int64];
names: SymNames;
r: var string) =
var i = 0
while i < t.len:
toString t, NodePos(i), strings, integers, names, r
nextChild t, i
type
Value* = distinct Tree
proc prepare*(dest: var Value; info: PackedLineInfo; k: Opcode): PatchPos {.inline.} =
assert k in ValueProducing - ValueProducingAtoms
result = prepare(Tree(dest), info, k)
proc patch*(dest: var Value; pos: PatchPos) {.inline.} =
patch(Tree(dest), pos)
proc localToValue*(info: PackedLineInfo; s: SymId): Value =
result = Value(Tree())
Tree(result).addSymUse info, s
proc hasValue*(v: Value): bool {.inline.} = Tree(v).len > 0
proc isEmpty*(v: Value): bool {.inline.} = Tree(v).len == 0
proc extractTemp*(v: Value): SymId =
if hasValue(v) and Tree(v)[NodePos 0].kind == SymUse:
result = SymId(Tree(v)[NodePos 0].operand)
else:
result = SymId(-1)
proc copyTree*(dest: var Tree; src: Value) = copyTree dest, Tree(src)
proc addImmediateVal*(t: var Value; info: PackedLineInfo; x: int) =
assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int)
Tree(t).nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info)
template build*(tree: var Value; info: PackedLineInfo; kind: Opcode; body: untyped) =
let pos = prepare(Tree(tree), info, kind)
body
patch(tree, pos)
proc addTyped*(t: var Value; info: PackedLineInfo; typ: TypeId) {.inline.} =
addTyped(Tree(t), info, typ)
template buildTyped*(tree: var Value; info: PackedLineInfo; kind: Opcode; typ: TypeId; body: untyped) =
let pos = prepare(tree, info, kind)
tree.addTyped info, typ
body
patch(tree, pos)
proc addStrVal*(t: var Value; strings: var BiTable[string]; info: PackedLineInfo; s: string) =
addStrVal(Tree(t), strings, info, s)
proc addNilVal*(t: var Value; info: PackedLineInfo; typ: TypeId) =
addNilVal Tree(t), info, typ
proc addIntVal*(t: var Value; integers: var BiTable[int64]; info: PackedLineInfo; typ: TypeId; x: int64) =
addIntVal Tree(t), integers, info, typ, x

View File

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

View File

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

View File

@@ -1,475 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Type system for NIR. Close to C's type system but without its quirks.
import std / [assertions, hashes]
import .. / ic / [bitabs, rodfiles]
type
NirTypeKind* = enum
VoidTy, IntTy, UIntTy, FloatTy, BoolTy, CharTy, NameVal,
IntVal, SizeVal, AlignVal, OffsetVal,
AnnotationVal,
ObjectTy,
UnionTy,
VarargsTy, # the `...` in a C prototype; also the last "atom"
APtrTy, # pointer to aliasable memory
UPtrTy, # pointer to unique/unaliasable memory
AArrayPtrTy, # pointer to array of aliasable memory
UArrayPtrTy, # pointer to array of unique/unaliasable memory
ArrayTy,
LastArrayTy, # array of unspecified size as a last field inside an object
ProcTy,
ObjectDecl,
UnionDecl,
FieldDecl
const
TypeKindBits = 8'u32
TypeKindMask = (1'u32 shl TypeKindBits) - 1'u32
type
TypeNode* = object # 4 bytes
x: uint32
template kind*(n: TypeNode): NirTypeKind = NirTypeKind(n.x and TypeKindMask)
template operand(n: TypeNode): uint32 = (n.x shr TypeKindBits)
proc integralBits*(n: TypeNode): int {.inline.} =
# Number of bits in the IntTy, etc. Only valid for integral types.
assert n.kind in {IntTy, UIntTy, FloatTy, BoolTy, CharTy}
result = int(n.operand)
template toX(k: NirTypeKind; operand: uint32): uint32 =
uint32(k) or (operand shl TypeKindBits)
template toX(k: NirTypeKind; operand: LitId): uint32 =
uint32(k) or (operand.uint32 shl TypeKindBits)
type
TypeId* = distinct int
proc `==`*(a, b: TypeId): bool {.borrow.}
proc hash*(a: TypeId): Hash {.borrow.}
type
Literals* = ref object
strings*: BiTable[string]
numbers*: BiTable[int64]
TypeGraph* = object
nodes: seq[TypeNode]
lit: Literals
const
VoidId* = TypeId 0
Bool8Id* = TypeId 1
Char8Id* = TypeId 2
Int8Id* = TypeId 3
Int16Id* = TypeId 4
Int32Id* = TypeId 5
Int64Id* = TypeId 6
UInt8Id* = TypeId 7
UInt16Id* = TypeId 8
UInt32Id* = TypeId 9
UInt64Id* = TypeId 10
Float32Id* = TypeId 11
Float64Id* = TypeId 12
VoidPtrId* = TypeId 13
LastBuiltinId* = 13
proc initTypeGraph*(lit: Literals): TypeGraph =
result = TypeGraph(nodes: @[
TypeNode(x: toX(VoidTy, 0'u32)),
TypeNode(x: toX(BoolTy, 8'u32)),
TypeNode(x: toX(CharTy, 8'u32)),
TypeNode(x: toX(IntTy, 8'u32)),
TypeNode(x: toX(IntTy, 16'u32)),
TypeNode(x: toX(IntTy, 32'u32)),
TypeNode(x: toX(IntTy, 64'u32)),
TypeNode(x: toX(UIntTy, 8'u32)),
TypeNode(x: toX(UIntTy, 16'u32)),
TypeNode(x: toX(UIntTy, 32'u32)),
TypeNode(x: toX(UIntTy, 64'u32)),
TypeNode(x: toX(FloatTy, 32'u32)),
TypeNode(x: toX(FloatTy, 64'u32)),
TypeNode(x: toX(APtrTy, 2'u32)),
TypeNode(x: toX(VoidTy, 0'u32))
], lit: lit)
assert result.nodes.len == LastBuiltinId+2
type
TypePatchPos* = distinct int
const
InvalidTypePatchPos* = TypePatchPos(-1)
LastAtomicValue = VarargsTy
proc isValid(p: TypePatchPos): bool {.inline.} = p.int != -1
proc prepare(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
result = TypePatchPos tree.nodes.len
tree.nodes.add TypeNode(x: toX(kind, 1'u32))
proc isAtom(tree: TypeGraph; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue
proc isAtom(tree: TypeGraph; pos: TypeId): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue
proc patch(tree: var TypeGraph; pos: TypePatchPos) =
let pos = pos.int
let k = tree.nodes[pos].kind
assert k > LastAtomicValue
let distance = int32(tree.nodes.len - pos)
assert distance > 0
tree.nodes[pos].x = toX(k, cast[uint32](distance))
proc len*(tree: TypeGraph): int {.inline.} = tree.nodes.len
template rawSpan(n: TypeNode): int = int(operand(n))
proc nextChild(tree: TypeGraph; pos: var int) {.inline.} =
if tree.nodes[pos].kind > LastAtomicValue:
assert tree.nodes[pos].operand > 0'u32
inc pos, tree.nodes[pos].rawSpan
else:
inc pos
iterator sons*(tree: TypeGraph; n: TypeId): TypeId =
var pos = n.int
assert tree.nodes[pos].kind > LastAtomicValue
let last = pos + tree.nodes[pos].rawSpan
inc pos
while pos < last:
yield TypeId pos
nextChild tree, pos
template `[]`*(t: TypeGraph; n: TypeId): TypeNode = t.nodes[n.int]
proc elementType*(tree: TypeGraph; n: TypeId): TypeId {.inline.} =
assert tree[n].kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, ArrayTy, LastArrayTy}
result = TypeId(n.int+1)
proc litId*(n: TypeNode): LitId {.inline.} =
assert n.kind in {NameVal, IntVal, SizeVal, AlignVal, OffsetVal, AnnotationVal, ObjectTy, UnionTy}
result = LitId(n.operand)
proc kind*(tree: TypeGraph; n: TypeId): NirTypeKind {.inline.} = tree[n].kind
proc span(tree: TypeGraph; pos: int): int {.inline.} =
if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand)
proc sons2(tree: TypeGraph; n: TypeId): (TypeId, TypeId) =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
result = (TypeId a, TypeId b)
proc sons3(tree: TypeGraph; n: TypeId): (TypeId, TypeId, TypeId) =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
let c = b + span(tree, b)
result = (TypeId a, TypeId b, TypeId c)
proc arrayName*(tree: TypeGraph; n: TypeId): TypeId {.inline.} =
assert tree[n].kind == ArrayTy
let (_, _, c) = sons3(tree, n)
result = c
proc arrayLen*(tree: TypeGraph; n: TypeId): BiggestInt =
assert tree[n].kind == ArrayTy
let (_, b) = sons2(tree, n)
result = tree.lit.numbers[LitId tree[b].operand]
proc returnType*(tree: TypeGraph; n: TypeId): (TypeId, TypeId) =
# Returns the positions of the return type + calling convention.
var pos = n.int
assert tree.nodes[pos].kind == ProcTy
let a = n.int+1
let b = a + span(tree, a)
result = (TypeId b, TypeId a) # not a typo, order is reversed
iterator params*(tree: TypeGraph; n: TypeId): TypeId =
var pos = n.int
assert tree.nodes[pos].kind == ProcTy
let last = pos + tree.nodes[pos].rawSpan
inc pos
nextChild tree, pos
nextChild tree, pos
while pos < last:
yield TypeId pos
nextChild tree, pos
proc openType*(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
assert kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy,
ArrayTy, LastArrayTy, ProcTy, ObjectDecl, UnionDecl,
FieldDecl}
result = prepare(tree, kind)
template typeInvariant(p: TypePatchPos) =
when false:
if tree[TypeId(p)].kind == FieldDecl:
var k = 0
for ch in sons(tree, TypeId(p)):
inc k
assert k > 2, "damn! " & $k
proc sealType*(tree: var TypeGraph; p: TypePatchPos) =
patch tree, p
typeInvariant(p)
proc finishType*(tree: var TypeGraph; p: TypePatchPos): TypeId =
# Search for an existing instance of this type in
# order to reduce memory consumption:
patch tree, p
typeInvariant(p)
let s = span(tree, p.int)
var i = 0
while i < p.int:
if tree.nodes[i].x == tree.nodes[p.int].x:
var isMatch = true
for j in 1..<s:
if tree.nodes[j+i].x == tree.nodes[j+p.int].x:
discard "still a match"
else:
isMatch = false
break
if isMatch:
if p.int+s == tree.len:
setLen tree.nodes, p.int
return TypeId(i)
nextChild tree, i
result = TypeId(p)
proc nominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string): TypeId =
assert kind in {ObjectTy, UnionTy}
let content = TypeNode(x: toX(kind, tree.lit.strings.getOrIncl(name)))
for i in 0..<tree.len:
if tree.nodes[i].x == content.x:
return TypeId(i)
result = TypeId tree.nodes.len
tree.nodes.add content
proc addNominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string) =
assert kind in {ObjectTy, UnionTy}
tree.nodes.add TypeNode(x: toX(kind, tree.lit.strings.getOrIncl(name)))
proc getTypeTag*(tree: TypeGraph; t: TypeId): string =
assert tree[t].kind in {ObjectTy, UnionTy}
result = tree.lit.strings[LitId tree[t].operand]
proc addVarargs*(tree: var TypeGraph) =
tree.nodes.add TypeNode(x: toX(VarargsTy, 0'u32))
proc getFloat128Type*(tree: var TypeGraph): TypeId =
result = TypeId tree.nodes.len
tree.nodes.add TypeNode(x: toX(FloatTy, 128'u32))
proc addBuiltinType*(g: var TypeGraph; id: TypeId) =
g.nodes.add g[id]
template firstSon*(n: TypeId): TypeId = TypeId(n.int+1)
proc addType*(g: var TypeGraph; t: TypeId) =
# We cannot simply copy `*Decl` nodes. We have to introduce `*Ty` nodes instead:
if g[t].kind in {ObjectDecl, UnionDecl}:
assert g[t.firstSon].kind == NameVal
let name = LitId g[t.firstSon].operand
if g[t].kind == ObjectDecl:
g.nodes.add TypeNode(x: toX(ObjectTy, name))
else:
g.nodes.add TypeNode(x: toX(UnionTy, name))
else:
let pos = t.int
let L = span(g, pos)
let d = g.nodes.len
g.nodes.setLen(d + L)
assert L > 0
for i in 0..<L:
g.nodes[d+i] = g.nodes[pos+i]
proc addArrayLen*(g: var TypeGraph; len: int64) =
g.nodes.add TypeNode(x: toX(IntVal, g.lit.numbers.getOrIncl(len)))
proc addSize*(g: var TypeGraph; s: int64) =
g.nodes.add TypeNode(x: toX(SizeVal, g.lit.numbers.getOrIncl(s)))
proc addOffset*(g: var TypeGraph; offset: int64) =
g.nodes.add TypeNode(x: toX(OffsetVal, g.lit.numbers.getOrIncl(offset)))
proc addAlign*(g: var TypeGraph; a: int64) =
g.nodes.add TypeNode(x: toX(AlignVal, g.lit.numbers.getOrIncl(a)))
proc addName*(g: var TypeGraph; name: string) =
g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl(name)))
proc addAnnotation*(g: var TypeGraph; name: string) =
g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl(name)))
proc addField*(g: var TypeGraph; name: string; typ: TypeId; offset: int64) =
let f = g.openType FieldDecl
g.addType typ
g.addOffset offset
g.addName name
sealType(g, f)
proc ptrTypeOf*(g: var TypeGraph; t: TypeId): TypeId =
let f = g.openType APtrTy
g.addType t
result = finishType(g, f)
proc arrayPtrTypeOf*(g: var TypeGraph; t: TypeId): TypeId =
let f = g.openType AArrayPtrTy
g.addType t
result = finishType(g, f)
proc store*(r: var RodFile; g: TypeGraph) =
storeSeq r, g.nodes
proc load*(r: var RodFile; g: var TypeGraph) =
loadSeq r, g.nodes
proc toString*(dest: var string; g: TypeGraph; i: TypeId) =
case g[i].kind
of VoidTy: dest.add "void"
of IntTy:
dest.add "i"
dest.addInt g[i].operand
of UIntTy:
dest.add "u"
dest.addInt g[i].operand
of FloatTy:
dest.add "f"
dest.addInt g[i].operand
of BoolTy:
dest.add "b"
dest.addInt g[i].operand
of CharTy:
dest.add "c"
dest.addInt g[i].operand
of NameVal, AnnotationVal:
dest.add g.lit.strings[LitId g[i].operand]
of IntVal, SizeVal, AlignVal, OffsetVal:
dest.add $g[i].kind
dest.add ' '
dest.add $g.lit.numbers[LitId g[i].operand]
of VarargsTy:
dest.add "..."
of APtrTy:
dest.add "aptr["
toString(dest, g, g.elementType(i))
dest.add "]"
of UPtrTy:
dest.add "uptr["
toString(dest, g, g.elementType(i))
dest.add "]"
of AArrayPtrTy:
dest.add "aArrayPtr["
toString(dest, g, g.elementType(i))
dest.add "]"
of UArrayPtrTy:
dest.add "uArrayPtr["
toString(dest, g, g.elementType(i))
dest.add "]"
of ArrayTy:
dest.add "Array["
let (elems, len, name) = g.sons3(i)
toString(dest, g, elems)
dest.add ", "
toString(dest, g, len)
dest.add ", "
toString(dest, g, name)
dest.add "]"
of LastArrayTy:
# array of unspecified size as a last field inside an object
dest.add "LastArrayTy["
toString(dest, g, g.elementType(i))
dest.add "]"
of ObjectTy:
dest.add "object "
dest.add g.lit.strings[LitId g[i].operand]
of UnionTy:
dest.add "union "
dest.add g.lit.strings[LitId g[i].operand]
of ProcTy:
dest.add "proc["
for t in sons(g, i):
dest.add ' '
toString(dest, g, t)
dest.add "]"
of ObjectDecl:
dest.add "object["
for t in sons(g, i):
toString(dest, g, t)
dest.add '\n'
dest.add "]"
of UnionDecl:
dest.add "union["
for t in sons(g, i):
toString(dest, g, t)
dest.add '\n'
dest.add "]"
of FieldDecl:
dest.add "field["
for t in sons(g, i):
toString(dest, g, t)
dest.add ' '
dest.add "]"
when false:
let (typ, offset, name) = g.sons3(i)
toString(dest, g, typ)
dest.add ' '
toString(dest, g, offset)
dest.add ' '
toString(dest, g, name)
proc toString*(dest: var string; g: TypeGraph) =
var i = 0
while i < g.len:
dest.add "T<"
dest.addInt i
dest.add "> "
toString(dest, g, TypeId i)
dest.add '\n'
nextChild g, i
iterator allTypes*(g: TypeGraph; start = 0): TypeId =
var i = start
while i < g.len:
yield TypeId i
nextChild g, i
iterator allTypesIncludingInner*(g: TypeGraph; start = 0): TypeId =
var i = start
while i < g.len:
yield TypeId i
inc i
proc `$`(g: TypeGraph): string =
result = ""
toString(result, g)
when isMainModule:
var g = initTypeGraph(Literals())
let a = g.openType ArrayTy
g.addBuiltinType Int8Id
g.addArrayLen 5
g.addName "SomeArray"
let finalArrayType = finishType(g, a)
let obj = g.openType ObjectDecl
g.nodes.add TypeNode(x: toX(NameVal, g.lit.strings.getOrIncl("MyType")))
g.addField "p", finalArrayType, 0
sealType(g, obj)
echo g

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