Compare commits

...

504 Commits

Author SHA1 Message Date
narimiran
336dc9d827 more removing of failing packages 2026-05-22 11:22:54 +02:00
narimiran
3fe329dbd1 remove failing packages 2026-05-22 10:02:48 +02:00
Juan Carlos
9ef34c3589 Fix Bisect (#25218)
- Nim requires `SSL_library_init`, OpenSSL 3.x removed
`SSL_library_init`, Windows defaults to OpenSSL 3.x, then install
OpenSSL 1.x on Windows.
- Keep `jiro4989/setup-nim-action` at `v1`, because `v2` uses a YAML
"hardcoded" matrix of Nim versions, but this Bisect "dynamically" finds
the Nim version with a bug, therefore we cant hardcode Nim versions in
the YAML, the Bisect programmatically installs required Nim versions as
it goes bisecting commit-by-commit.
- Update `actions/checkout` from `v4` to `v5`.
- Add support for Nim `2.2.4`.

@ringabout

(cherry picked from commit 1ef81f4190)
2026-05-22 09:24:05 +02:00
dependabot[bot]
fda07a76fd update actions' versions 2026-05-22 09:19:52 +02:00
ringabout
19dc02e1bb updates to macos-15 (#25278)
ref https://github.com/actions/runner-images/issues/13046

(cherry picked from commit d5549a3c65)
2026-05-22 09:15:01 +02:00
Andreas Rumpf
0a6f1b44dc fixes DOS via malformed HTTP protocol (#25793)
refs https://github.com/nim-lang/Nim/pull/25568

(cherry picked from commit f0077a12b2)
2026-05-22 08:55:39 +02:00
Miran
a837ee7800 replace outdated macos-13 runner (#25155)
(cherry picked from commit c49fb5ac5f)
2025-09-17 08:59:09 +02:00
ringabout
2fbb793f4e fixes #25173; SinglyLinkedList.remove broken / AssertionDefect (#25175)
fixes #25173

(cherry picked from commit 51a9ada043)
2025-09-16 20:13:12 +02:00
ringabout
edeac84e47 fixes #24725; Invalid =sink generated for pure inheritable object (#24726)
fixes #24725

`lacksMTypeField` doesn't take the base types into consideration. And
for ` {.inheritable, pure.}`, it shouldn't generate a `m_type` field.

(cherry picked from commit e449813c61)
2025-08-05 08:33:50 +02:00
Juan M Gómez
d2b8c3c0d5 Bumps nimble 0.20.1 (#25062)
(cherry picked from commit cd806f9dbe)
2025-07-19 11:49:25 +02:00
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
574 changed files with 12987 additions and 4523 deletions

View File

@@ -8,12 +8,18 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6
# nimrun-action requires Nim installed.
- uses: jiro4989/setup-nim-action@v1
with:
nim-version: 'devel'
- name: Install OpenSSL (Windows)
if: |
runner.os == 'Windows'
run: choco install openssl.light --version=1.1.1.0 # OpenSSL 3.x removed SSL_library_init
shell: 'powershell'
# v2 wont work here, because uses "hardcoded" nim versions, action "dynamically" finds version with bug.
- uses: jiro4989/setup-nim-action@v1
with:
nim-version: 'devel'
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends -yq valgrind

View File

@@ -10,7 +10,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04]
os: [ubuntu-24.04]
cpu: [amd64]
name: '${{ matrix.os }}'
runs-on: ${{ matrix.os }}
@@ -21,10 +21,10 @@ jobs:
with:
fetch-depth: 2
- name: 'Install node.js 16.x'
uses: actions/setup-node@v3
- name: 'Install node.js 20.x'
uses: actions/setup-node@v4
with:
node-version: '16.x'
node-version: '20.x'
- name: 'Install dependencies (Linux amd64)'
if: runner.os == 'Linux' && matrix.cpu == 'amd64'

View File

@@ -43,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-15
name: ${{ matrix.target }}
runs-on: ${{ matrix.os }}
@@ -55,7 +55,7 @@ jobs:
steps:
- name: 'Checkout'
uses: actions/checkout@v3
uses: actions/checkout@v6
with:
fetch-depth: 2
@@ -111,7 +111,7 @@ jobs:
if: |
github.event_name == 'push' && github.ref == 'refs/heads/devel' &&
matrix.target == 'linux'
uses: crazy-max/ghaction-github-pages@v3
uses: crazy-max/ghaction-github-pages@v5
with:
build_dir: doc/html
env:

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,9 +17,13 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, macos-11]
cpu: [amd64]
os: [ubuntu-latest, macos-14]
batch: ["allowed_failures", "0_3", "1_3", "2_3"] # list of `index_num`
include:
- os: ubuntu-latest
cpu: amd64
- os: macos-14
cpu: arm64
name: '${{ matrix.os }} (batch: ${{ matrix.batch }})'
runs-on: ${{ matrix.os }}
timeout-minutes: 60 # refs bug #18178
@@ -28,26 +32,27 @@ jobs:
NIM_TESTAMENT_BATCH: ${{ matrix.batch }}
steps:
- name: 'Checkout'
uses: actions/checkout@v3
uses: actions/checkout@v6
with:
fetch-depth: 2
- name: 'Install node.js 16.x'
uses: actions/setup-node@v3
- name: 'Install node.js'
uses: actions/setup-node@v6
with:
node-version: '16.x'
node-version: 24
- name: 'Install dependencies (Linux amd64)'
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
run: |
sudo apt-fast update -qq
sudo apt-get update -qq
DEBIAN_FRONTEND='noninteractive' \
sudo apt-fast install --no-install-recommends -yq \
sudo apt-get install --no-install-recommends -yq \
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \
valgrind libc6-dbg libblas-dev xorg-dev
valgrind libc6-dbg libblas-dev liblapack-dev libpcre3 xorg-dev
- name: 'Install dependencies (macOS)'
if: runner.os == 'macOS'
run: brew install boehmgc make sfml gtk+3
# XXX can't find boehm and gtk on macos 13
- name: 'Install dependencies (Windows)'
if: runner.os == 'Windows'
shell: bash

View File

@@ -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@v3
uses: actions/checkout@v6
with:
fetch-depth: 2
- name: 'Install node.js 16.x'
uses: actions/setup-node@v3
- name: 'Install node.js'
uses: actions/setup-node@v6
with:
node-version: '16.x'
node-version: 24
- name: 'Install dependencies (Linux amd64)'
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
@@ -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
@@ -71,7 +60,7 @@ jobs:
run: nim c -r -d:release ci/action.nim
- name: 'Comment'
uses: actions/github-script@v6
uses: actions/github-script@v9
with:
script: |
const fs = require('fs');
@@ -87,4 +76,3 @@ jobs:
} catch (err) {
console.error(err);
}

View File

@@ -9,7 +9,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v8
- uses: actions/stale@v10
with:
days-before-pr-stale: 365
days-before-pr-close: 30

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:
@@ -28,24 +28,24 @@ jobs:
# # g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed
# vmImage: 'ubuntu-18.04'
# CPU: i386
OSX_amd64:
vmImage: 'macOS-11'
CPU: amd64
OSX_amd64_cpp:
vmImage: 'macOS-11'
CPU: amd64
OSX_arm64:
vmImage: 'macos-15'
CPU: arm64
OSX_arm64_cpp:
vmImage: 'macos-15'
CPU: arm64
NIM_COMPILE_TO_CPP: true
Windows_amd64_batch0_3:
vmImage: 'windows-2019'
vmImage: 'windows-2025'
CPU: amd64
# see also: `NIM_TEST_PACKAGES`
NIM_TESTAMENT_BATCH: "0_3"
Windows_amd64_batch1_3:
vmImage: 'windows-2019'
vmImage: 'windows-2025'
CPU: amd64
NIM_TESTAMENT_BATCH: "1_3"
Windows_amd64_batch2_3:
vmImage: 'windows-2019'
vmImage: 'windows-2025'
CPU: amd64
NIM_TESTAMENT_BATCH: "2_3"
@@ -80,10 +80,12 @@ jobs:
- bash: |
set -e
. ci/funs.sh
echo_run sudo apt-fast update -qq
echo_run sudo add-apt-repository universe
echo_run sudo apt-get update -qq
DEBIAN_FRONTEND='noninteractive' \
echo_run sudo apt-fast install --no-install-recommends -yq \
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev valgrind libc6-dbg
echo_run sudo apt-get install --no-install-recommends -yq \
gcc-14 g++-14 libpcre3 liblapack-dev libpcre3 liblapack-dev libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev valgrind libc6-dbg
echo_run sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 60 --slave /usr/bin/g++ g++ /usr/bin/g++-14
displayName: 'Install dependencies (amd64 Linux)'
condition: and(succeeded(), eq(variables['skipci'], 'false'), eq(variables['Agent.OS'], 'Linux'), eq(variables['CPU'], 'amd64'))
@@ -100,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

@@ -3,6 +3,9 @@
## Changes affecting backward compatibility
- `-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.
- With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default.
## Standard library additions and changes
@@ -11,6 +14,17 @@
[//]: # "Additions:"
- Added `newStringUninit` to system, which creates a new string of length `len` like `newString` but with uninitialized content.
- Added `setLenUninit` to system, which doesn't initalize
slots when enlarging a sequence.
- Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value.
- Added Viewport API for the JavaScript targets in the `dom` module.
- 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:"
@@ -21,10 +35,101 @@
- 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
## Tool changes
- koch now allows bootstrapping with `-d:nimHasLibFFI`, replacing the older option of building the compiler directly w/ the `libffi` nimble package in tow.

View File

@@ -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.

View File

@@ -10,7 +10,7 @@
# abstract syntax tree + symbol table
import
lineinfos, hashes, options, ropes, idents, int128, tables
lineinfos, hashes, options, ropes, idents, int128, tables, wordrecg
from strutils import toLowerAscii
when defined(nimPreviewSlimSystem):
@@ -227,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
@@ -315,6 +316,7 @@ type
sfVirtual # proc is a C++ virtual function
sfByCopy # param is marked as pass bycopy
sfCodegenDecl # type, proc, global or proc param is marked as codegenDecl
sfWasGenSym # symbol was 'gensym'ed
TSymFlags* = set[TSymFlag]
@@ -516,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)
@@ -589,6 +594,7 @@ type
tfEffectSystemWorkaround
tfIsOutParam
tfSendable
tfImplicitStatic
TTypeFlags* = set[TTypeFlag]
@@ -638,7 +644,7 @@ const
skError* = skUnknown
var
eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr, tfGcSafe, tfNoSideEffect, tfIsOutParam, tfSendable}
eqTypeFlags* = {tfIterator, tfNotNil, tfVarIsPtr, tfGcSafe, tfNoSideEffect, tfIsOutParam}
## type flags that are essential for type equality.
## This is now a variable because for emulation of version:1.0 we
## might exclude {tfGcSafe, tfNoSideEffect}.
@@ -898,6 +904,7 @@ type
info*: TLineInfo
when defined(nimsuggest):
endInfo*: TLineInfo
hasUserSpecifiedType*: bool # used for determining whether to display inlay type hints
owner*: PSym
flags*: TSymFlags
ast*: PNode # syntax tree of proc, iterator, etc.:
@@ -1086,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
@@ -1102,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}
@@ -1130,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
@@ -1249,8 +1258,11 @@ 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:
@@ -1448,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
@@ -1456,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
@@ -1464,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
@@ -1523,6 +1573,107 @@ proc `$`*(s: PSym): string =
else:
result = "<nil>"
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 signature*(t: PType): PType =
# yields return type + parameter types
for i in 0..<t.sons.len: yield t.sons[i]
proc newType*(kind: TTypeKind, id: ItemId; owner: PSym): PType =
result = PType(kind: kind, owner: owner, size: defaultSize,
align: defaultAlignment, itemId: id,
@@ -1633,7 +1784,7 @@ 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
@@ -1642,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
@@ -1911,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:
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.} =
@@ -1979,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 =
@@ -1996,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
@@ -2014,7 +2167,7 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool =
result = true
proc isInfixAs*(n: PNode): bool =
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "as"
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.id == ord(wAs)
proc skipColon*(n: PNode): PNode =
result = n
@@ -2022,10 +2175,12 @@ proc skipColon*(n: PNode): PNode =
result = n[1]
proc findUnresolvedStatic*(n: PNode): PNode =
# n.typ == nil: see issue #14802
if n.kind == nkSym and n.typ != nil and n.typ.kind == tyStatic and n.typ.n == nil:
return n
if n.typ != nil and n.typ.kind == tyTypeDesc:
let t = skipTypes(n.typ, {tyTypeDesc})
if t.kind == tyGenericParam and t.len == 0:
return n
for son in n:
let n = son.findUnresolvedStatic
if n != nil: return n
@@ -2063,6 +2218,12 @@ proc isClosureIterator*(typ: PType): bool {.inline.} =
proc isClosure*(typ: PType): bool {.inline.} =
typ.kind == tyProc and typ.callConv == ccClosure
proc isNimcall*(s: PSym): bool {.inline.} =
s.typ.callConv == ccNimCall
proc isExplicitCallConv*(s: PSym): bool {.inline.} =
tfExplicitCallConv in s.typ.flags
proc isSinkParam*(s: PSym): bool {.inline.} =
s.kind == skParam and (s.typ.kind == tySink or tfHasOwned in s.typ.flags)

View File

@@ -890,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
@@ -1054,14 +1054,6 @@ 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 =
for sym in symbols:
if result.len > 0:

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

@@ -24,6 +24,7 @@ proc canRaiseDisp(p: BProc; n: PNode): bool =
proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
proc locationEscapes(p: BProc; le: PNode; inTryStmt: bool): bool =
result = false
var n = le
while true:
# do NOT follow nkHiddenDeref here!
@@ -82,6 +83,10 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
if typ[0] != nil:
var flags: TAssignmentFlags = {}
if typ[0].kind in {tyOpenArray, tyVarargs}:
# perhaps generate no temp if the call doesn't have side effects
flags.incl needTempForOpenArray
if isInvalidReturnType(p.config, typ):
if params.len != 0: pl.add(", ")
# beware of 'result = p(result)'. We may need to allocate a temporary:
@@ -129,7 +134,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
genAssignment(p, d, list, flags) # no need for deep copying
if canRaise: raiseExit(p)
else:
var tmp: TLoc
@@ -137,7 +142,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, tmp, list, {}) # no need for deep copying
genAssignment(p, tmp, list, flags) # no need for deep copying
if canRaise: raiseExit(p)
genAssignment(p, d, tmp, {})
else:
@@ -145,12 +150,18 @@ 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:
@@ -161,12 +172,15 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
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
@@ -301,18 +315,33 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
addAddrLoc(p.config, withTmpIfNeeded(p, a, needsTmp), result)
elif p.module.compileToCpp and param.typ.kind in {tyVar} and
n.kind == nkHiddenAddr:
initLocExprSingleUse(p, n[0], a)
# 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:
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
@@ -394,9 +423,11 @@ proc genParams(p: BProc, ri: PNode, typ: PType; result: var Rope) =
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:

View File

@@ -285,15 +285,23 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(p.config, dest), addrLoc(p.config, src), genTypeInfoV1(p.module, dest.t, dest.lode.info)])
proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) =
proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc; flags: TAssignmentFlags) =
assert d.k != locNone
# getTemp(p, d.t, d)
case a.t.skipTypes(abstractVar).kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(a.lode):
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
[rdLoc(d), a.rdLoc])
if needTempForOpenArray in flags:
var tmp: TLoc
getTemp(p, a.t, tmp)
linefmt(p, cpsStmts, "$2 = $1; $n",
[a.rdLoc, tmp.rdLoc])
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
[rdLoc(d), tmp.rdLoc])
else:
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
[rdLoc(d), a.rdLoc])
else:
linefmt(p, cpsStmts, "$1.Field0 = $2; $1.Field1 = $2Len_0;$n",
[rdLoc(d), a.rdLoc])
@@ -336,7 +344,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
of tyString:
if optSeqDestructors in p.config.globalOptions:
genGenericAsgn(p, dest, src, flags)
elif (needToCopy notin flags and src.storage != OnStatic) or canMove(p, src.lode, dest):
elif ({needToCopy, needToCopySinkParam} * flags == {} and src.storage != OnStatic) or canMove(p, src.lode, dest):
genRefAssign(p, dest, src)
else:
if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config):
@@ -392,7 +400,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# open arrays are always on the stack - really? What if a sequence is
# passed to an open array?
if reifiedOpenArray(dest.lode):
genOpenArrayConv(p, dest, src)
genOpenArrayConv(p, dest, src, flags)
elif containsGarbageCollectedRef(dest.t):
linefmt(p, cpsStmts, # XXX: is this correct for arrays?
"#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
@@ -594,7 +602,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
# skipping 'range' is correct here as we'll generate a proper range check
# later via 'chckRange'
let t = e.typ.skipTypes(abstractRange)
if optOverflowCheck notin p.options:
if optOverflowCheck notin p.options or (m in {mSucc, mPred} and t.kind in {tyUInt..tyUInt64}):
let res = "($1)($2 $3 $4)" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)]
putIntoDest(p, d, e, res)
else:
@@ -616,7 +624,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
if t.kind == tyInt64: prc64[m] else: prc[m])
putIntoDest(p, d, e, "($#)($#)" % [getTypeDesc(p.module, e.typ), res])
else:
let res = "($1)($2 $3 $4)" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)]
let res = "($1)(($2) $3 ($4))" % [getTypeDesc(p.module, e.typ), rdLoc(a), rope(opr[m]), rdLoc(b)]
putIntoDest(p, d, e, res)
proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
@@ -824,6 +832,8 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
#Message(e.info, warnUser, "HERE NEW &")
elif mapType(p.config, e[0].typ, mapTypeChooser(e[0]) == skParam) == ctArray or isCppRef(p, e.typ):
expr(p, e[0], d)
# bug #19497
d.lode = e
else:
var a: TLoc
initLocExpr(p, e[0], a)
@@ -1029,8 +1039,8 @@ proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) =
putIntoDest(p, d, n,
ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage)
proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
let ty = skipTypes(arr.t, abstractVarRange)
proc genBoundsCheck(p: BProc; arr, a, b: TLoc; arrTyp: PType) =
let ty = arrTyp
case ty.kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(arr.lode):
@@ -1496,11 +1506,12 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
initLocExpr(p, e[1], a)
if optSeqDestructors in p.config.globalOptions:
if d.k == locNone: getTemp(p, e.typ, d, needsInit=false)
linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayload($2, sizeof($3), NIM_ALIGNOF($3));$n",
linefmt(p, cpsStmts, "$1.len = 0; $1.p = ($4*) #newSeqPayloadUninit($2, sizeof($3), NIM_ALIGNOF($3));$n",
[d.rdLoc, a.rdLoc, getTypeDesc(p.module, seqtype.lastSon),
getSeqPayloadType(p.module, seqtype),
])
else:
if d.k == locNone: getTemp(p, e.typ, d, needsInit=false) # bug #22560
putIntoDest(p, d, e, ropecg(p.module,
"($1)#nimNewSeqOfCap($2, $3)", [
getTypeDesc(p.module, seqtype),
@@ -1550,6 +1561,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
var tmp: TLoc
var r: Rope
let needsZeroMem = p.config.selectedGC notin {gcArc, gcAtomicArc, gcOrc} or nfAllFieldsSet notin e.flags
if useTemp:
getTemp(p, t, tmp)
r = rdLoc(tmp)
@@ -1558,10 +1570,13 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
t = t.lastSon.skipTypes(abstractInstOwned)
r = "(*$1)" % [r]
gcUsage(p.config, e)
else:
elif needsZeroMem:
constructLoc(p, tmp)
else:
genObjectInit(p, cpsStmts, t, tmp, constructObj)
else:
resetLoc(p, d)
if needsZeroMem: resetLoc(p, d)
else: genObjectInit(p, cpsStmts, d.t, d, if isRef: constructRefObj else: constructObj)
r = rdLoc(d)
discard getTypeDesc(p.module, t)
let ty = getUniqueType(t)
@@ -1874,11 +1889,11 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
initLocExpr(p, a[2], b)
initLocExpr(p, a[3], c)
if optBoundsCheck in p.options:
genBoundsCheck(p, m, b, c)
genBoundsCheck(p, m, b, c, skipTypes(m.t, abstractVarRange))
if op == mHigh:
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)", [rdLoc(b), rdLoc(c)]))
putIntoDest(p, d, e, ropecg(p.module, "(($2)-($1))", [rdLoc(b), rdLoc(c)]))
else:
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)+1", [rdLoc(b), rdLoc(c)]))
putIntoDest(p, d, e, ropecg(p.module, "(($2)-($1)+1)", [rdLoc(b), rdLoc(c)]))
else:
if not reifiedOpenArray(a):
if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)")
@@ -2120,7 +2135,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mCard:
var a: TLoc
initLocExpr(p, e[1], a)
putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [addrLoc(p.config, a), size]))
putIntoDest(p, d, e, ropecg(p.module, "#cardSet($1, $2)", [rdCharLoc(a), size]))
of mLtSet, mLeSet:
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo, tyInt), i) # our counter
initLocExpr(p, e[1], a)
@@ -2347,7 +2362,7 @@ proc genWasMoved(p: BProc; n: PNode) =
proc genMove(p: BProc; n: PNode; d: var TLoc) =
var a: TLoc
initLocExpr(p, n[1].skipAddr, a)
initLocExpr(p, n[1].skipAddr, a, {lfEnforceDeref})
if n.len == 4:
# generated by liftdestructors:
var src: TLoc
@@ -2363,12 +2378,31 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) =
if op == nil:
resetLoc(p, a)
else:
let addrExp = makeAddr(n[1], p.module.idgen)
let wasMovedCall = newTreeI(nkCall, n.info, newSymNode(op), addrExp)
genCall(p, wasMovedCall, d)
var b: TLoc
initLocExpr(p, newSymNode(op), b)
case skipTypes(a.t, abstractVar+{tyStatic}).kind
of tyOpenArray, tyVarargs: # todo fixme generated `wasMoved` hooks for
# openarrays, but it probably shouldn't?
var s: string
if reifiedOpenArray(a.lode):
if a.t.kind in {tyVar, tyLent}:
s = "$1->Field0, $1->Field1" % [rdLoc(a)]
else:
s = "$1.Field0, $1.Field1" % [rdLoc(a)]
else:
s = "$1, $1Len_0" % [rdLoc(a)]
linefmt(p, cpsStmts, "$1($2);$n", [rdLoc(b), s])
else:
linefmt(p, cpsStmts, "$1($2);$n", [rdLoc(b), byRefLoc(p, a)])
else:
let flags = if not canMove(p, n[1], d): {needToCopy} else: {}
genAssignment(p, d, a, flags)
if n[1].kind == nkSym and isSinkParam(n[1].sym):
var tmp: TLoc
getTemp(p, n[1].typ.skipTypes({tySink}), tmp)
genAssignment(p, tmp, a, {needToCopySinkParam})
genAssignment(p, d, tmp, {})
resetLoc(p, tmp)
else:
genAssignment(p, d, a, {})
resetLoc(p, a)
proc genDestroy(p: BProc; n: PNode) =
@@ -2607,7 +2641,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mDeepCopy:
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and optEnableDeepCopy notin p.config.globalOptions:
localError(p.config, e.info,
"for --gc:arc|orc 'deepcopy' support has to be enabled with --deepcopy:on")
"for --mm:arc|atomicArc|orc 'deepcopy' support has to be enabled with --deepcopy:on")
var a, b: TLoc
let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1]
@@ -3084,16 +3118,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkObjConstr: genObjConstr(p, n, d)
of nkCast: genCast(p, n, d)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, d)
of nkHiddenAddr:
if n[0].kind == nkDerefExpr:
# addr ( deref ( x )) --> x
var x = n[0][0]
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
x.typ = n.typ
expr(p, x, d)
return
genAddr(p, n, d)
of nkAddr: genAddr(p, n, d)
of nkAddr, nkHiddenAddr: genAddr(p, n, d)
of nkBracketExpr: genBracketExpr(p, n, d)
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, d)
of nkDotExpr: genRecordField(p, n, d)
@@ -3278,11 +3303,16 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
isConst: bool, info: TLineInfo) =
case obj.kind
of nkRecList:
let isUnion = tfUnion in t.flags
for it in obj.sons:
getNullValueAux(p, t, it, constOrNil, result, count, isConst, info)
if isUnion:
# generate only 1 field for default value of union
return
of nkRecCase:
getNullValueAux(p, t, obj[0], constOrNil, result, count, isConst, info)
if count > 0: result.add ", "
var res = ""
if count > 0: res.add ", "
var branch = Zero
if constOrNil != nil:
## find kind value, default is zero if not specified
@@ -3296,18 +3326,21 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
break
let selectedBranch = caseObjDefaultBranch(obj, branch)
result.add "{"
res.add "{"
var countB = 0
let b = lastSon(obj[selectedBranch])
# designated initilization is the only way to init non first element of unions
# branches are allowed to have no members (b.len == 0), in this case they don't need initializer
if b.kind == nkRecList and not isEmptyCaseObjectBranch(b):
result.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {"
getNullValueAux(p, t, b, constOrNil, result, countB, isConst, info)
result.add "}"
res.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {"
getNullValueAux(p, t, b, constOrNil, res, countB, isConst, info)
res.add "}"
elif b.kind == nkSym:
result.add "." & mangleRecFieldName(p.module, b.sym) & " = "
getNullValueAux(p, t, b, constOrNil, result, countB, isConst, info)
res.add "." & mangleRecFieldName(p.module, b.sym) & " = "
getNullValueAux(p, t, b, constOrNil, res, countB, isConst, info)
else:
return
result.add res
result.add "}"
of nkSym:

View File

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

View File

@@ -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)
@@ -971,8 +971,11 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
hasDefault = true
exprBlock(p, branch.lastSon, d)
lineF(p, cpsStmts, "break;$n", [])
if (hasAssume in CC[p.config.cCompiler].props) and not hasDefault:
lineF(p, cpsStmts, "default: __assume(0);$n", [])
if not hasDefault:
if hasBuiltinUnreachable in CC[p.config.cCompiler].props:
lineF(p, cpsStmts, "default: __builtin_unreachable();$n", [])
elif hasAssume in CC[p.config.cCompiler].props:
lineF(p, cpsStmts, "default: __assume(0);$n", [])
lineF(p, cpsStmts, "}$n", [])
if lend != "": fixLabel(p, lend)

View File

@@ -54,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))
@@ -252,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
@@ -642,6 +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 =
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 genRecordFieldsAux(m: BModule; n: PNode,
rectype: PType,
check: var IntSet; result: var Rope; unionPrefix = "") =
@@ -706,7 +737,7 @@ proc genRecordFieldsAux(m: BModule; n: PNode,
else:
# don't use fieldType here because we need the
# tyGenericInst for C++ template support
if fieldType.isOrHasImportedCppType():
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])
@@ -729,7 +760,7 @@ proc getRecordFields(m: BModule; typ: PType, check: var IntSet): Rope =
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) =
@@ -737,6 +768,8 @@ proc fillObjectFields*(m: BModule; typ: PType) =
# 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
@@ -1404,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]
@@ -1563,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)
@@ -1909,8 +1942,11 @@ proc genTypeSection(m: BModule, n: PNode) =
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

@@ -13,6 +13,8 @@ import
ast, types, hashes, strutils, msgs, wordrecg,
platform, trees, options, cgendata
import std/[hashes, strutils, formatfloat]
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -121,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
@@ -132,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):
@@ -148,3 +153,64 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
result = not (pt.kind in {tyVar, tyArray, tyOpenArray, tyVarargs, tyRef, tyPtr, tyPointer} or
pt.kind == tySet and mapSetType(conf, pt) == ctArray)
proc encodeName*(name: string): string =
result = mangle(name)
result = $result.len & result
proc makeUnique(m: BModule; s: PSym, name: string = ""): string =
result = if name == "": s.name.s else: name
result.add "__"
result.add m.g.graph.ifaces[s.itemId.module].uniqueName
result.add "_u"
result.add $s.itemId.item
proc encodeSym*(m: BModule; s: PSym; makeUnique: bool = false): string =
#Module::Type
var name = s.name.s
if makeUnique:
name = makeUnique(m, s, name)
"N" & encodeName(s.skipGenericOwner.name.s) & encodeName(name) & "E"
proc elementType*(n: PType): PType {.inline.} = n.sons[^1]
proc encodeType*(m: BModule; t: PType): string =
result = ""
var kindName = ($t.kind)[2..^1]
kindName[0] = toLower($kindName[0])[0]
case t.kind
of tyObject, tyEnum, tyDistinct, tyUserTypeClass, tyGenericParam:
result = encodeSym(m, t.sym)
of tyGenericInst, tyUserTypeClassInst, tyGenericBody:
result = encodeName(t[0].sym.name.s)
result.add "I"
for i in 1..<t.len - 1:
result.add encodeType(m, t[i])
result.add "E"
of tySequence, tyOpenArray, tyArray, tyVarargs, tyTuple, tyProc, tySet, tyTypeDesc,
tyPtr, tyRef, tyVar, tyLent, tySink, tyStatic, tyUncheckedArray, tyOr, tyAnd, tyBuiltInTypeClass:
result =
case t.kind:
of tySequence: encodeName("seq")
else: encodeName(kindName)
result.add "I"
for i in 0..<t.len:
let s = t[i]
if s.isNil: continue
result.add encodeType(m, s)
result.add "E"
of tyRange:
var val = "range_"
if t.n[0].typ.kind in {tyFloat..tyFloat128}:
val.addFloat t.n[0].floatVal
val.add "_"
val.addFloat t.n[1].floatVal
else:
val.add $t.n[0].intVal & "_" & $t.n[1].intVal
result = encodeName(val)
of tyString..tyUInt64, tyPointer, tyBool, tyChar, tyVoid, tyAnything, tyNil, tyEmpty:
result = encodeName(kindName)
of tyAlias, tyInferred, tyOwned:
result = encodeType(m, t.elementType)
else:
assert false, "encodeType " & $t.kind

View File

@@ -30,6 +30,12 @@ import strutils except `%`, addf # collides with ropes.`%`
from ic / ic import ModuleBackendFlag
import dynlib
const
# we use some ASCII control characters to insert directives that will be converted to real code in a postprocessing pass
postprocessDirStart = '\1'
postprocessDirSep = '\31'
postprocessDirEnd = '\23'
when not declared(dynlib.libCandidates):
proc libCandidates(s: string, dest: var seq[string]) =
## given a library name pattern `s` write possible library names to `dest`.
@@ -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
@@ -296,7 +306,7 @@ 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) =
let line = t.info.safeLineNm
@@ -306,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);\n",
[line])
else:
linefmt(p, cpsStmts, "nimlf_($1, $2);\n",
[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.}
@@ -401,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)
@@ -986,11 +993,19 @@ proc closureSetup(p: BProc, prc: PSym) =
linefmt(p, cpsStmts, "$1 = ($2) ClE_0;$n",
[rdLoc(env.loc), getTypeDesc(p.module, env.typ)])
const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef,
nkMacroDef, nkMixinStmt, nkBindStmt, nkFormalParams} +
declarativeDefs
proc containsResult(n: PNode): bool =
result = false
case n.kind
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkFormalParams:
of succ(nkEmpty)..pred(nkSym), succ(nkSym)..nkNilLit, harmless:
discard
of nkReturnStmt:
for i in 0..<n.len:
if containsResult(n[i]): return true
result = n.len > 0 and n[0].kind == nkEmpty
of nkSym:
if n.sym.kind == skResult:
result = true
@@ -998,10 +1013,6 @@ proc containsResult(n: PNode): bool =
for i in 0..<n.len:
if containsResult(n[i]): return true
const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef,
nkMacroDef, nkMixinStmt, nkBindStmt, nkFormalParams} +
declarativeDefs
proc easyResultAsgn(n: PNode): PNode =
case n.kind
of nkStmtList, nkStmtListExpr:
@@ -1021,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(...)
@@ -1036,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
@@ -1048,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:
@@ -1064,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
@@ -1090,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:
@@ -1117,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])
@@ -1175,7 +1204,13 @@ proc genProcAux*(m: BModule, prc: PSym) =
# declare the result symbol:
assignLocalVar(p, resNode)
assert(res.loc.r != "")
initLocalVar(p, res, immediateAsgn=false)
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
allPathsAsgnResult(p, procBody) == InitSkippable:
# In an ideal world the codegen could rely on injectdestructors doing its job properly
# and then the analysis step would not be required.
discard "result init optimized out"
else:
initLocalVar(p, res, immediateAsgn=false)
returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)])
elif sfConstructor in prc.flags:
fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap)
@@ -1189,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:
@@ -1775,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:
@@ -1816,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])
@@ -1880,13 +1915,13 @@ proc genInitCode(m: BModule) =
if beforeRetNeeded in m.initProc.flags:
prc.add("\tBeforeRet_: ;\n")
if sfMainModule in m.module.flags and m.config.exc == excGoto:
if m.config.exc == excGoto:
if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil:
m.appcg(prc, "\t#nimTestErrorFlag();$n", [])
if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
prc.add(deinitFrame(m.initProc))
elif sfMainModule in m.module.flags and m.config.exc == excGoto:
elif m.config.exc == excGoto:
if getCompilerProc(m.g.graph, "nimTestErrorFlag") != nil:
m.appcg(prc, "\t#nimTestErrorFlag();$n", [])
@@ -1931,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
@@ -1959,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

View File

@@ -135,6 +135,7 @@ type
# unconditionally...
# nimtvDeps is VERY hard to cache because it's
# not a list of IDs nor can it be made to be one.
mangledPrcs*: HashSet[string]
TCGen = object of PPassContext # represents a C source file
s*: TCFileSections # sections of the C file
@@ -148,7 +149,7 @@ type
typeABICache*: HashSet[SigHash] # cache for ABI checks; reusing typeCache
# would be ideal but for some reason enums
# don't seem to get cached so it'd generate
# 1 ABI check per occurence in code
# 1 ABI check per occurrence in code
forwTypeCache*: TypeCache # cache for forward declarations of types
declaredThings*: IntSet # things we have declared in this .c file
declaredProtos*: IntSet # prototypes we have declared in this .c file
@@ -196,6 +197,8 @@ proc newProc*(prc: PSym, module: BModule): BProc =
result = BProc(
prc: prc,
module: module,
optionsStack: if module.initProc != nil: module.initProc.optionsStack
else: @[],
options: if prc != nil: prc.options
else: module.config.options,
blocks: @[initBlock()],

View File

@@ -95,7 +95,8 @@ proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
return No
if result == Yes:
# check for return type:
if not sameTypeOrNil(a.typ[0], b.typ[0]):
# ignore flags of return types; # bug #22673
if not sameTypeOrNil(a.typ[0], b.typ[0], {IgnoreFlags}):
if b.typ[0] != nil and b.typ[0].kind == tyUntyped:
# infer 'auto' from the base to make it consistent:
b.typ[0] = a.typ[0]

View File

@@ -163,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:

View File

@@ -55,6 +55,11 @@ proc loadConfigsAndProcessCmdLine*(self: NimProg, cache: IdentCache; conf: Confi
if conf.cmd == cmdNimscript:
incl(conf.globalOptions, optWasNimscript)
loadConfigs(DefaultConfig, cache, conf, graph.idgen) # load all config files
# restores `conf.notes` after loading config files
# because it has overwrites the notes when compiling the system module which
# is a foreign module compared to the project
if conf.cmd in cmdBackends:
conf.notes = conf.mainPackageNotes
if not self.suggestMode:
let scriptFile = conf.projectFull.changeFileExt("nims")

View File

@@ -205,7 +205,11 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
# unfortunately, hintUser and warningUser clash, otherwise implementation would simplify a bit
let x = findStr(noteMin, noteMax, id, errUnknown)
if x != errUnknown: notes = {TNoteKind(x)}
else: localError(conf, info, "unknown $#: $#" % [name, id])
else:
if isSomeHint:
message(conf, info, hintUnknownHint, id)
else:
localError(conf, info, "unknown $#: $#" % [name, id])
case id.normalize
of "all": # other note groups would be easy to support via additional cases
notes = if isSomeHint: {hintMin..hintMax} else: {warnMin..warnMax}

View File

@@ -314,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

@@ -143,7 +143,6 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasTemplateRedefinitionPragma")
defineSymbol("nimHasCstringCase")
defineSymbol("nimHasCallsitePragma")
defineSymbol("nimHasAmbiguousEnumHint")
defineSymbol("nimHasWarnCastSizes") # deadcode
defineSymbol("nimHasOutParams")
@@ -158,3 +157,9 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimAllowNonVarDestructor")
defineSymbol("nimHasQuirky")
defineSymbol("nimHasEnsureMove")
defineSymbol("nimHasNoReturnError")
defineSymbol("nimHasCastExtendedVm")
defineSymbol("nimHasGenericsOpenSym2")
defineSymbol("nimHasNolineTooLong")
defineSymbol("nimHasGenericsOpenSym3")

View File

@@ -821,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 = ""
@@ -839,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
@@ -853,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
@@ -1723,7 +1723,7 @@ proc genOutFile(d: PDoc, groupedToc = false): string =
"moduledesc", d.modDescFinal, "date", getDateStr(), "time", getClockStr(),
"content", content, "author", d.meta[metaAuthor],
"version", esc(d.target, d.meta[metaVersion]), "analytics", d.analytics,
"deprecationMsg", d.modDeprecationMsg]
"deprecationMsg", d.modDeprecationMsg, "nimVersion", $NimMajor & "." & $NimMinor & "." & $NimPatch]
else:
code = content
result = code
@@ -1907,7 +1907,7 @@ proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"")
"title", "Index",
"subtitle", "", "tableofcontents", "", "moduledesc", "",
"date", getDateStr(), "time", getClockStr(),
"content", content, "author", "", "version", "", "analytics", ""]
"content", content, "author", "", "version", "", "analytics", "", "nimVersion", $NimMajor & "." & $NimMinor & "." & $NimPatch]
# no analytics because context is not available
try:

View File

@@ -423,8 +423,8 @@ 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 sig: ParamList
var cif: TCif = default(TCif)
var sig: ParamList = default(ParamList)
# use the arguments' types for varargs support:
for i in 1..<call.len:
sig[i-1] = mapType(conf, call[i].typ)
@@ -463,8 +463,8 @@ proc callForeignFunction*(conf: ConfigRef, fn: PNode, fntyp: PType,
info: TLineInfo): PNode =
internalAssert conf, fn.kind == nkPtrLit
var cif: TCif
var sig: ParamList
var cif: TCif = default(TCif)
var sig: ParamList = default(ParamList)
for i in 0..len-1:
var aTyp = args[i+start].typ
if aTyp.isNil:

View File

@@ -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:

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
@@ -33,6 +33,7 @@ type
hasGnuAsm, # CC's asm uses the absurd GNU assembler syntax
hasDeclspec, # CC has __declspec(X)
hasAttribute, # CC has __attribute__((X))
hasBuiltinUnreachable # CC has __builtin_unreachable
TInfoCCProps* = set[TInfoCCProp]
TInfoCC* = tuple[
name: string, # the short name of the compiler
@@ -95,7 +96,7 @@ compiler gcc:
produceAsm: gnuAsmListing,
cppXsupport: "-std=gnu++17 -funsigned-char",
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
hasAttribute})
hasAttribute, hasBuiltinUnreachable})
# GNU C and C++ Compiler
compiler nintendoSwitchGCC:
@@ -122,7 +123,7 @@ compiler nintendoSwitchGCC:
produceAsm: gnuAsmListing,
cppXsupport: "-std=gnu++17 -funsigned-char",
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
hasAttribute})
hasAttribute, hasBuiltinUnreachable})
# LLVM Frontend for GCC/G++
compiler llvmGcc:
@@ -451,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)
@@ -992,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
@@ -1013,10 +1019,14 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) =
currentDir: getCurrentDir())
if optRun in conf.globalOptions or isDefined(conf, "nimBetterRun"):
bcache.cmdline = conf.commandLine
bcache.depfiles = collect(for it in conf.m.fileInfos:
for it in conf.m.fileInfos:
let path = it.fullPath.string
if isAbsolute(path): # TODO: else?
(path, $secureHashFile(path)))
if path in deps:
bcache.depfiles.add (path, deps[path])
else: # backup for configs etc.
bcache.depfiles.add (path, $secureHashFile(path))
bcache.nimexe = hashNimExe()
conf.jsonBuildFile = conf.jsonBuildInstructionsFile
conf.jsonBuildFile.string.writeFile(bcache.toJson.pretty)

View File

@@ -1047,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

@@ -10,9 +10,6 @@
# This include implements the high level optimization pass.
# included from sem.nim
when defined(nimPreviewSlimSystem):
import std/assertions
proc hlo(c: PContext, n: PNode): PNode
proc evalPattern(c: PContext, n, orig: PNode): PNode =

View File

@@ -421,7 +421,7 @@ proc addModuleRef(n: PNode; ir: var PackedTree; c: var PackedEncoder; m: var Pac
## add a remote symbol reference to the tree
let info = n.info.toPackedInfo(c, m)
ir.nodes.add PackedNode(kind: nkModuleRef, operand: 3.int32, # spans 3 nodes in total
typeId: storeTypeLater(n.typ, c, m), info: info)
typeId: storeTypeLater(n.typ, c, m), info: info, flags: n.flags)
ir.nodes.add PackedNode(kind: nkInt32Lit, info: info,
operand: toLitId(n.sym.itemId.module.FileIndex, c, m).int32)
ir.nodes.add PackedNode(kind: nkInt32Lit, info: info,
@@ -768,6 +768,8 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
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.nodes[n.int].operand))
if result.typ == nil:
result.typ = result.sym.typ
of directIntLit:
result.intVal = tree.nodes[n.int].operand
of externIntLit:
@@ -782,6 +784,8 @@ proc loadNodes*(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
assert n2.kind == nkInt32Lit
transitionNoneToSym(result)
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)

View File

@@ -141,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")
@@ -304,7 +304,15 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym =
var prefix = ""
if realModule.constraint != nil: prefix = realModule.constraint.strVal & "; "
message(c.config, n.info, warnDeprecated, prefix & realModule.name.s & " is deprecated")
suggestSym(c.graph, n.info, result, c.graph.usageSym, false)
proc suggestMod(n: PNode; s: PSym) =
if n.kind == nkImportAs:
suggestMod(n[0], realModule)
elif n.kind == nkInfix:
suggestMod(n[2], s)
else:
suggestSym(c.graph, n.info, s, c.graph.usageSym, false)
suggestMod(n, result)
importStmtResult.add newSymNode(result, n.info)
#newStrNode(toFullPath(c.config, f), n.info)
@@ -344,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

@@ -79,11 +79,11 @@ proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
proc nestedScope(parent: var Scope; body: PNode): Scope =
Scope(vars: @[], locals: @[], wasMoved: @[], final: @[], body: body, needsTry: false, parent: addr(parent))
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode
type
MoveOrCopyFlag = enum
IsDecl, IsExplicitSink
IsDecl, IsExplicitSink, IsReturn
proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; flags: set[MoveOrCopyFlag] = {}): PNode
@@ -161,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
@@ -185,7 +186,9 @@ proc isCursor(n: PNode): bool =
template isUnpackedTuple(n: PNode): bool =
## we move out all elements of unpacked tuples,
## hence unpacked tuples themselves don't need to be destroyed
(n.kind == nkSym and n.sym.kind == skTemp and n.sym.typ.kind == tyTuple)
## except it's already a cursor
(n.kind == nkSym and n.sym.kind == skTemp and
n.sym.typ.kind == tyTuple and sfCursor notin n.sym.flags)
proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string; inferredFromCopy = false) =
var m = "'" & opname & "' is not available for type <" & typeToString(t) & ">"
@@ -270,7 +273,7 @@ proc deepAliases(dest, ri: PNode): bool =
proc genSink(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
if (c.inLoopCond == 0 and (isUnpackedTuple(dest) or IsDecl in flags or
(isAnalysableFieldAccess(dest, c.owner) and isFirstWrite(dest, c)))) or
isNoInit(dest):
isNoInit(dest) or IsReturn in flags:
# optimize sink call into a bitwise memcopy
result = newTree(nkFastAsgn, dest, ri)
else:
@@ -293,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.
@@ -310,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))
@@ -405,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)
@@ -435,24 +442,25 @@ proc isCapturedVar(n: PNode): bool =
proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let tmp = c.getTemp(s, n.typ, n.info)
if hasDestructor(c, n.typ):
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
@@ -461,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)
@@ -472,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
@@ -489,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:
@@ -587,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:
@@ -745,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
@@ -760,7 +770,19 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
result.add copyNode(n[0])
s.needsTry = true
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode =
template isCustomDestructor(c: Con, t: PType): bool =
hasDestructor(c, t) and
getAttachedOp(c.graph, t, attachedDestructor) != nil and
sfOverridden in getAttachedOp(c.graph, t, attachedDestructor).flags
proc hasCustomDestructor(c: Con, t: PType): bool =
result = isCustomDestructor(c, t)
var obj = t
while obj.len > 0 and obj[0] != nil:
obj = skipTypes(obj[0], abstractPtrs)
result = result or isCustomDestructor(c, obj)
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode =
if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt,
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt, nkPragmaBlock}:
template process(child, s): untyped = p(child, c, s, mode)
@@ -773,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
@@ -801,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)
@@ -850,15 +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:
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
@@ -875,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:
@@ -896,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:
@@ -944,7 +964,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}:
cycleCheck(n, c)
assert n[1].kind notin {nkAsgn, nkFastAsgn, nkSinkAsgn}
let flags = if n.kind == nkSinkAsgn: {IsExplicitSink} else: {}
var flags = if n.kind == nkSinkAsgn: {IsExplicitSink} else: {}
if inReturn:
flags.incl(IsReturn)
result = moveOrCopy(p(n[0], c, s, mode), n[1], c, s, flags)
elif isDiscriminantField(n[0]):
result = c.genDiscriminantAsgn(s, n)
@@ -1028,7 +1050,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
of nkReturnStmt:
result = shallowCopy(n)
for i in 0..<n.len:
result[i] = p(n[i], c, s, mode)
result[i] = p(n[i], c, s, mode, inReturn=true)
s.needsTry = true
of nkCast:
result = shallowCopy(n)
@@ -1134,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):
@@ -1142,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:
@@ -1162,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:
@@ -1182,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

View File

@@ -50,6 +50,7 @@ type
graph: ModuleGraph
config: ConfigRef
sigConflicts: CountTable[SigHash]
initProc: PProc
BModule = ref TJSGen
TJSTypeKind = enum # necessary JS "types"
@@ -158,6 +159,8 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
options: TOptions): PProc =
result = PProc(
blocks: @[],
optionsStack: if module.initProc != nil: module.initProc.optionsStack
else: @[],
options: options,
module: module,
procDef: procDef,
@@ -893,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
@@ -1195,7 +1198,7 @@ proc needsNoCopy(p: PProc; y: PNode): bool =
return y.kind in nodeKindsNeedNoCopy or
((mapType(y.typ) != etyBaseIndex or (y.kind == nkSym and y.sym.kind == skParam)) and
(skipTypes(y.typ, abstractInst).kind in
{tyRef, tyPtr, tyLent, tyVar, tyCstring, tyProc, tyOwned} + IntegralTypes))
{tyRef, tyPtr, tyLent, tyVar, tyCstring, tyProc, tyOwned, tyOpenArray} + IntegralTypes))
proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
var a, b: TCompRes
@@ -1516,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:
@@ -1949,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:
@@ -3036,6 +3032,7 @@ proc processJSCodeGen*(b: PPassContext, n: PNode): PNode =
if m.module == nil: internalError(m.config, n.info, "myProcess")
let globals = PGlobals(m.graph.backend)
var p = newInitProc(globals, m)
m.initProc = p
p.unique = globals.unique
genModule(p, n)
p.g.code.add(p.locals)

View File

@@ -258,8 +258,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PN
let iter = n.sym
assert iter.isIterator
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
result = newNodeIT(nkStmtListExpr, n.info, iter.typ)
let hp = getHiddenParam(g, iter)
var env: PNode
if owner.isIterator:
@@ -293,23 +292,26 @@ proc freshVarForClosureIter*(g: ModuleGraph; s: PSym; idgen: IdGenerator; owner:
proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
let s = n.sym
let isEnv = s.name.id == getIdent(g.cache, ":env").id
if illegalCapture(s):
localError(g.config, n.info,
("'$1' is of type <$2> which cannot be captured as it would violate memory" &
" safety, declared here: $3; using '-d:nimNoLentIterators' helps in some cases." &
" Consider using a <ref $2> which can be captured.") %
[s.name.s, typeToString(s.typ), g.config$s.info])
elif not (owner.typ.callConv == ccClosure or owner.typ.callConv == ccNimCall and tfExplicitCallConv notin owner.typ.flags):
elif not (owner.typ.isClosure or owner.isNimcall and not owner.isExplicitCallConv or isEnv):
localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
[s.name.s, owner.name.s, $owner.typ.callConv])
incl(owner.typ.flags, tfCapturesEnv)
owner.typ.callConv = ccClosure
if not isEnv:
owner.typ.callConv = ccClosure
type
DetectionPass = object
processed, capturedVars: IntSet
ownerToType: Table[int, PType]
somethingToDo: bool
inTypeOf: bool
graph: ModuleGraph
idgen: IdGenerator
@@ -413,6 +415,9 @@ Consider:
"""
proc isTypeOf(n: PNode): bool =
n.kind == nkSym and n.sym.magic in {mTypeOf, mType}
proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
var cp = getEnvParam(fn)
let owner = if fn.kind == skIterator: fn else: fn.skipGenericOwner
@@ -444,12 +449,15 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
let body = transformBody(c.graph, c.idgen, s, useCache)
detectCapturedVars(body, s, c)
let ow = s.skipGenericOwner
let innerClosure = innerProc and s.typ.callConv == ccClosure and not s.isIterator
let interested = interestingVar(s)
if ow == owner:
if owner.isIterator:
c.somethingToDo = true
addClosureParam(c, owner, n.info)
if interestingIterVar(s):
if not c.capturedVars.containsOrIncl(s.id):
if not c.capturedVars.contains(s.id):
if not c.inTypeOf: c.capturedVars.incl(s.id)
let obj = getHiddenParam(c.graph, owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
#let obj = c.getEnvTypeForOwner(s.owner).skipTypes({tyOwned, tyRef, tyPtr})
@@ -458,7 +466,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
else:
discard addField(obj, s, c.graph.cache, c.idgen)
# direct or indirect dependency:
elif (innerProc and not s.isIterator and s.typ.callConv == ccClosure) or interestingVar(s):
elif innerClosure or interested:
discard """
proc outer() =
var x: int
@@ -475,10 +483,12 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
addClosureParam(c, owner, n.info)
#echo "capturing ", n.info
# variable 's' is actually captured:
if interestingVar(s) and not c.capturedVars.containsOrIncl(s.id):
let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef, tyPtr})
#getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
discard addField(obj, s, c.graph.cache, c.idgen)
if interestingVar(s):
if not c.capturedVars.contains(s.id):
if not c.inTypeOf: c.capturedVars.incl(s.id)
let obj = c.getEnvTypeForOwner(ow, n.info).skipTypes({tyOwned, tyRef, tyPtr})
#getHiddenParam(owner).typ.skipTypes({tyOwned, tyRef, tyPtr})
discard addField(obj, s, c.graph.cache, c.idgen)
# create required upFields:
var w = owner.skipGenericOwner
if isInnerProc(w) or owner.isIterator:
@@ -510,9 +520,14 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
detectCapturedVars(n[namePos], owner, c)
of nkReturnStmt:
detectCapturedVars(n[0], owner, c)
of nkIdentDefs:
detectCapturedVars(n[^1], owner, c)
else:
if n.isCallExpr and n[0].isTypeOf:
c.inTypeOf = true
for i in 0..<n.len:
detectCapturedVars(n[i], owner, c)
c.inTypeOf = false
type
LiftingPass = object
@@ -792,6 +807,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass;
of nkTypeOfExpr:
result = n
else:
if n.isCallExpr and n[0].isTypeOf:
return
if owner.isIterator:
if nfLL in n.flags:
# special case 'when nimVm' due to bug #3636:
@@ -971,12 +988,15 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym):
# gather vars in a tuple:
var v2 = newNodeI(nkLetSection, body.info)
var vpart = newNodeI(if body.len == 3: nkIdentDefs else: nkVarTuple, body.info)
for i in 0..<body.len-2:
if body[i].kind == nkSym:
body[i].sym.transitionToLet()
vpart.add body[i]
if body.len == 3 and body[0].kind == nkVarTuple:
vpart = body[0] # fixes for (i,j) in walk() # bug #15924
else:
for i in 0..<body.len-2:
if body[i].kind == nkSym:
body[i].sym.transitionToLet()
vpart.add body[i]
vpart.add newNodeI(nkEmpty, body.info) # no explicit type
vpart.add newNodeI(nkEmpty, body.info) # no explicit type
if not env.isNil:
call[0] = makeClosure(g, idgen, call[0].sym, env.newSymNode, body.info)
vpart.add call

View File

@@ -156,17 +156,18 @@ proc genWasMovedCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
result.add(newSymNode(op))
result.add genAddr(c, x)
proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) =
proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool, enforceWasMoved = false) =
case n.kind
of nkSym:
if c.filterDiscriminator != nil: return
let f = n.sym
let b = if c.kind == attachedTrace: y else: y.dotField(f)
if (sfCursor in f.flags and f.typ.skipTypes(abstractInst).kind in {tyRef, tyProc} and
c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcHooks}) or
if (sfCursor in f.flags and c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcHooks}) or
enforceDefaultOp:
defaultOp(c, f.typ, body, x.dotField(f), b)
else:
if enforceWasMoved:
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x.dotField(f))
fillBody(c, f.typ, body, x.dotField(f), b)
of nkNilLit: discard
of nkRecCase:
@@ -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)
@@ -542,6 +568,14 @@ proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) =
else:
body.sons.setLen counterIdx
proc checkSelfAssignment(c: var TLiftCtx; t: PType; body, x, y: PNode) =
var cond = callCodegenProc(c.g, "sameSeqPayload", c.info,
newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x),
newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y)
)
cond.typ = getSysType(c.g, c.info, tyBool)
body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info)))
proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
of attachedDup:
@@ -549,10 +583,13 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
forallElements(c, t, body, x, y)
of attachedAsgn, attachedDeepCopy:
# we generate:
# if x.p == y.p:
# return
# setLen(dest, y.len)
# var i = 0
# while i < y.len: dest[i] = y[i]; inc(i)
# This is usually more efficient than a destroy/create pair.
checkSelfAssignment(c, t, body, x, y)
body.add setLenSeqCall(c, t, x, y)
forallElements(c, t, body, x, y)
of attachedSink:
@@ -1059,7 +1096,7 @@ proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttache
incl result.flags, sfGeneratedOp
proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator): PSym =
info: TLineInfo; idgen: IdGenerator; isDiscriminant = false): PSym =
if kind == attachedDup:
return symDupPrototype(g, typ, owner, kind, info, idgen)
@@ -1068,8 +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 typ.kind in {tyRef, tyString, tySequence} and g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
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})):
dest.typ = typ
else:
dest.typ = makeVarType(typ.owner, typ, idgen)
@@ -1151,18 +1188,26 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
fillStrOp(a, typ, result.ast[bodyPos], d, src)
else:
fillBody(a, typ, result.ast[bodyPos], d, src)
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy, attachedDup} and not lacksMTypeField(typ):
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy, attachedDup} and not isObjLackingTypeField(typ):
# 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)
proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym,
info: TLineInfo; idgen: IdGenerator): PSym =
assert(typ.skipTypes({tyAlias, tyGenericInst}).kind == tyObject)
result = symPrototype(g, field.typ, typ.owner, attachedDestructor, info, idgen)
# discrimantor assignments needs pointers to destroy fields; alas, we cannot use non-var destructor here
result = symPrototype(g, field.typ, typ.owner, attachedDestructor, info, idgen, isDiscriminant = true)
var a = TLiftCtx(info: info, g: g, kind: attachedDestructor, asgnForType: typ, idgen: idgen,
fn: result)
a.asgnForType = typ
@@ -1214,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;

View File

@@ -91,6 +91,7 @@ type
warnStmtListLambda = "StmtListLambda",
warnBareExcept = "BareExcept",
warnImplicitDefaultValue = "ImplicitDefaultValue",
warnIgnoredSymbolInjection = "IgnoredSymbolInjection",
warnUser = "User",
# hints
hintSuccess = "Success", hintSuccessX = "SuccessX",
@@ -104,10 +105,10 @@ type
hintPattern = "Pattern", hintExecuting = "Exec", hintLinking = "Link", hintDependency = "Dependency",
hintSource = "Source", hintPerformance = "Performance", hintStackTrace = "StackTrace",
hintGCStats = "GCStats", hintGlobalVar = "GlobalVar", hintExpandMacro = "ExpandMacro",
hintAmbiguousEnum = "AmbiguousEnum",
hintUser = "User", hintUserRaw = "UserRaw", hintExtendedContext = "ExtendedContext",
hintMsgOrigin = "MsgOrigin", # since 1.3.5
hintDeclaredLoc = "DeclaredLoc", # since 1.5.1
hintUnknownHint = "UnknownHint"
const
MsgKindToStr*: array[TMsgKind, string] = [
@@ -185,7 +186,7 @@ const
warnAnyEnumConv: "$1",
warnHoleEnumConv: "$1",
warnCstringConv: "$1",
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; this will become a compile time error in the future",
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; Use a `cast` operation like `cast[cstring](x)`; this will become a compile time error in the future",
warnEffect: "$1",
warnCastSizes: "$1", # deadcode
warnAboveMaxSizeSet: "$1",
@@ -194,6 +195,7 @@ const
warnStmtListLambda: "statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead",
warnBareExcept: "$1",
warnImplicitDefaultValue: "$1",
warnIgnoredSymbolInjection: "$1",
warnUser: "$1",
hintSuccess: "operation successful: $#",
# keep in sync with `testament.isSuccess`
@@ -225,12 +227,12 @@ const
hintGCStats: "$1",
hintGlobalVar: "global variable declared here",
hintExpandMacro: "expanded macro: $1",
hintAmbiguousEnum: "$1",
hintUser: "$1",
hintUserRaw: "$1",
hintExtendedContext: "$1",
hintMsgOrigin: "$1",
hintDeclaredLoc: "$1",
hintUnknownHint: "unknown hint: $1"
]
const

View File

@@ -12,7 +12,7 @@
import std/strutils
from std/sugar import dup
import options, ast, msgs, idents, lineinfos, wordrecg, astmsgs, semdata, packages
import options, ast, msgs, idents, lineinfos, wordrecg, astmsgs, semdata, packages, modulegraphs
export packages
const
@@ -95,7 +95,7 @@ template styleCheckDef*(ctx: PContext; info: TLineInfo; sym: PSym; k: TSymKind)
if optStyleCheck in ctx.config.options and # ignore if styleChecks are off
{optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # check only if hint/error is enabled
hintName in ctx.config.notes and # ignore if name checks are not requested
ctx.config.belongsToProjectPackage(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
@@ -136,7 +136,7 @@ template styleCheckUse*(ctx: PContext; info: TLineInfo; sym: PSym) =
## Check symbol uses match their definition's style.
if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
hintName in ctx.config.notes and # ignore if name checks are not requested
ctx.config.belongsToProjectPackage(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
@@ -152,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

@@ -48,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:
@@ -61,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)
@@ -135,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
@@ -148,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:
@@ -220,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:
@@ -238,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:
@@ -254,8 +256,63 @@ proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSy
if s.kind in filter:
result.add s
proc errorSym*(c: PContext, n: PNode): PSym =
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 = default(TIdentIter)
var candidate = initIdentIter(ti, scope.symbols, s)
var scopeHasCandidate = false
while candidate != nil:
if candidate.kind in filter:
if scopeHasCandidate:
# 2 candidates in same scope, ambiguous
return true
else:
scopeHasCandidate = true
sym = candidate
candidate = nextIdentIter(ti, scope.symbols)
if scopeHasCandidate:
# scope had a candidate but wasn't ambiguous
return false
var importsHaveCandidate = false
var marked = initIntSet()
for im in c.imports.mitems:
for s in symbols(im, marked, s, c.graph):
if s.kind in filter:
if importsHaveCandidate:
# 2 candidates among imports, ambiguous
return true
else:
importsHaveCandidate = true
sym = s
if importsHaveCandidate:
# imports had a candidate but wasn't ambiguous
return false
proc errorSym*(c: PContext, 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]
@@ -263,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
@@ -295,7 +347,7 @@ 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]]
@@ -450,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
@@ -505,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:
@@ -531,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
@@ -539,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.
@@ -551,16 +607,16 @@ 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
return nil
if amb:
#contains(c.ambiguousSymbols, result.id):
result = errorUseQualifier(c, n.info, result, amb)
@@ -571,36 +627,45 @@ 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
if amb and checkAmbiguity in flags:
errorUseQualifier(c, n.info, candidates)
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:
result = nil
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})
@@ -615,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: " &
@@ -637,6 +702,10 @@ 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

View File

@@ -122,25 +122,6 @@ proc newTupleAccessRaw*(tup: PNode, i: int): PNode =
proc newTryFinally*(body, final: PNode): PNode =
result = newTree(nkHiddenTryStmt, body, newTree(nkFinally, final))
proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode =
let value = n.lastSon
result = newNodeI(nkStmtList, n.info)
var temp = newSym(skTemp, getIdent(g.cache, "_"), idgen, owner, value.info, owner.options)
var v = newNodeI(nkLetSection, value.info)
let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
vpart[0] = tempAsNode
vpart[1] = newNodeI(nkTupleClassTy, value.info)
vpart[2] = value
v.add vpart
result.add(v)
let lhs = n[0]
for i in 0..<lhs.len:
result.add newAsgnStmt(lhs[i], newTupleAccessRaw(tempAsNode, i))
proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode =
result = newNodeI(nkStmtList, n.info)
# note: cannot use 'skTemp' here cause we really need the copy for the VM :-(
@@ -237,6 +218,9 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym
field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item)
let t = skipIntLit(s.typ, idgen)
field.typ = t
if s.kind in {skLet, skVar, skField, skForVar}:
#field.bitsize = s.bitsize
field.alignment = s.alignment
assert t.kind != tyTyped
propagateToOwner(obj, t)
field.position = obj.n.len

View File

@@ -151,7 +151,7 @@ proc commandCompileToC(graph: ModuleGraph) =
extccomp.callCCompiler(conf)
# for now we do not support writing out a .json file with the build instructions when HCR is on
if not conf.hcrOn:
extccomp.writeJsonBuildInstructions(conf)
extccomp.writeJsonBuildInstructions(conf, graph.cachedFiles)
if optGenScript in graph.config.globalOptions:
writeDepsFile(graph)
if optGenCDeps in graph.config.globalOptions:
@@ -195,8 +195,8 @@ proc commandScan(cache: IdentCache, config: ConfigRef) =
var stream = llStreamOpen(f, fmRead)
if stream != nil:
var
L: Lexer
tok: Token
L: Lexer = default(Lexer)
tok: Token = default(Token)
initToken(tok)
openLexer(L, f, stream, cache, config)
while true:

View File

@@ -11,7 +11,7 @@
## represents a complete Nim project. Single modules can either be kept in RAM
## or stored in a rod-file.
import intsets, tables, hashes
import 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]
@@ -57,6 +57,7 @@ type
SymInfoPair* = object
sym*: PSym
info*: TLineInfo
isDecl*: bool
PipelinePass* = enum
NonePass
@@ -128,6 +129,8 @@ type
idgen*: IdGenerator
operators*: Operators
cachedFiles*: StringTableRef
TPassContext* = object of RootObj # the pass's context
idgen*: IdGenerator
PPassContext* = ref TPassContext
@@ -248,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
@@ -269,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
@@ -479,6 +482,7 @@ proc initModuleGraphFields(result: ModuleGraph) =
result.symBodyHashes = initTable[int, SigHash]()
result.operators = initOperators(result)
result.emittedTypeInfo = initTable[string, FileIndex]()
result.cachedFiles = newStringTable()
proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
result = ModuleGraph()

View File

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

View File

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

View File

@@ -125,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 =
@@ -429,7 +429,8 @@ To create a stacktrace, rerun compilation with './koch temp $1 <file>', see $2 f
proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string, ignoreMsg: bool) =
if msg in fatalMsgs:
if conf.cmd == cmdIdeTools: log(s)
quit(conf, msg)
if conf.cmd != cmdIdeTools or msg != errFatal:
quit(conf, msg)
if msg >= errMin and msg <= errMax or
(msg in warnMin..hintMax and msg in conf.warningAsErrors and not ignoreMsg):
inc(conf.errorCounter)
@@ -437,7 +438,11 @@ proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string,
if conf.errorCounter >= conf.errorMax:
# only really quit when we're not in the new 'nim check --def' mode:
if conf.ideCmd == ideNone:
quit(conf, msg)
when defined(nimsuggest):
#we need to inform the user that something went wrong when initializing NimSuggest
raiseRecoverableError(s)
else:
quit(conf, msg)
elif eh == doAbort and conf.cmd != cmdIdeTools:
quit(conf, msg)
elif eh == doRaise:
@@ -553,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)
@@ -643,13 +649,16 @@ template lintReport*(conf: ConfigRef; info: TLineInfo, beau, got: string, extraM
let msg = if optStyleError in conf.globalOptions: errGenerated else: hintName
liMessage(conf, info, msg, m, doNothing, instLoc())
proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
if i.fileIndex.int32 < 0:
proc quotedFilename*(conf: ConfigRef; fi: FileIndex): Rope =
if fi.int32 < 0:
result = makeCString "???"
elif optExcessiveStackTrace in conf.globalOptions:
result = conf.m.fileInfos[i.fileIndex.int32].quotedFullName
result = conf.m.fileInfos[fi.int32].quotedFullName
else:
result = conf.m.fileInfos[i.fileIndex.int32].quotedName
result = conf.m.fileInfos[fi.int32].quotedName
proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
quotedFilename(conf, i.fileIndex)
template listMsg(title, r) =
msgWriteln(conf, title, {msgNoUnitSep})

View File

@@ -9,6 +9,7 @@ define:nimPreviewSlimSystem
define:nimPreviewCstringConversion
define:nimPreviewProcConversion
define:nimPreviewRangeDefault
define:nimPreviewNonVarDestructor
threads:off
#import:"$projectpath/testability"

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

@@ -279,8 +279,8 @@ proc optimize*(n: PNode): PNode =
Now assume 'use' raises, then we shouldn't do the 'wasMoved(s)'
]#
var c: Con
var b: BasicBlock
var c: Con = Con()
var b: BasicBlock = default(BasicBlock)
analyse(c, b, n)
if c.somethingTodo:
result = shallowCopy(n)

View File

@@ -195,7 +195,7 @@ type
IdeCmd* = enum
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideChkFile, ideMod,
ideHighlight, ideOutline, ideKnown, ideMsg, ideProject, ideGlobalSymbols,
ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand
ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand, ideInlayHints
Feature* = enum ## experimental features; DO NOT RENAME THESE!
dotOperators,
@@ -220,7 +220,10 @@ type
unicodeOperators, # deadcode
flexibleOptionalParams,
strictDefs,
strictCaseObjects
strictCaseObjects,
openSym, # remove nfDisabledOpenSym when this is default
# alternative to above:
genericsOpenSym
LegacyFeature* = enum
allowSemcheckedAstModification,
@@ -280,9 +283,24 @@ type
version*: int
endLine*: uint16
endCol*: int
inlayHintInfo*: SuggestInlayHint
Suggestions* = seq[Suggest]
SuggestInlayHintKind* = enum
sihkType = "Type",
sihkParameter = "Parameter"
SuggestInlayHint* = ref object
kind*: SuggestInlayHintKind
line*: int # Starts at 1
column*: int # Starts at 0
label*: string
paddingLeft*: bool
paddingRight*: bool
allowInsert*: bool
tooltip*: string
ProfileInfo* = object
time*: float
count*: int
@@ -417,6 +435,8 @@ type
expandNodeResult*: string
expandPosition*: TLineInfo
clientProcessId*: int
proc parseNimVersion*(a: string): NimVer =
# could be moved somewhere reusable
@@ -1057,6 +1077,7 @@ proc `$`*(c: IdeCmd): string =
of ideRecompile: "recompile"
of ideChanged: "changed"
of ideType: "type"
of ideInlayHints: "inlayHints"
proc floatInt64Align*(conf: ConfigRef): int16 =
## Returns either 4 or 8 depending on reasons.

View File

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

View File

@@ -280,8 +280,15 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isAssignable(owner, n[0])
of nkCallKinds:
# builtin slice keeps lvalue-ness:
if getMagic(n) in {mArrGet, mSlice}:
let m = getMagic(n)
if m == mSlice:
# builtin slice keeps l-value-ness
# except for pointers because slice dereferences
if n[1].typ.kind == tyPtr:
result = arLValue
else:
result = isAssignable(owner, n[1])
elif m == mArrGet:
result = isAssignable(owner, n[1])
elif n.typ != nil:
case n.typ.kind

View File

@@ -1430,6 +1430,7 @@ proc parseTypeDesc(p: var Parser, fullExpr = false): PNode =
result = newNodeP(nkObjectTy, p)
getTok(p)
of tkConcept:
result = p.emptyNode
parMessage(p, "the 'concept' keyword is only valid in 'type' sections")
of tkVar: result = parseTypeDescKAux(p, nkVarTy, pmTypeDesc)
of tkOut: result = parseTypeDescKAux(p, nkOutTy, pmTypeDesc)
@@ -2285,7 +2286,7 @@ proc parseTypeDef(p: var Parser): PNode =
setEndInfo()
proc parseVarTuple(p: var Parser): PNode =
#| varTupleLhs = '(' optInd (identWithPragma / varTupleLhs) ^+ comma optPar ')'
#| varTupleLhs = '(' optInd (identWithPragma / varTupleLhs) ^+ comma optPar ')' (':' optInd typeDescExpr)?
#| varTuple = varTupleLhs '=' optInd expr
result = newNodeP(nkVarTuple, p)
getTok(p) # skip '('
@@ -2302,9 +2303,14 @@ proc parseVarTuple(p: var Parser): PNode =
if p.tok.tokType != tkComma: break
getTok(p)
skipComment(p, a)
result.add(p.emptyNode) # no type desc
optPar(p)
eat(p, tkParRi)
if p.tok.tokType == tkColon:
getTok(p)
optInd(p, result)
result.add(parseTypeDesc(p, fullExpr = true))
else:
result.add(p.emptyNode) # no type desc
setEndInfo()
proc parseVariable(p: var Parser): PNode =
@@ -2511,22 +2517,6 @@ proc parseStmt(p: var Parser): PNode =
if err and p.tok.tokType == tkEof: break
setEndInfo()
proc parseAll(p: var Parser): PNode =
## Parses the rest of the input stream held by the parser into a PNode.
result = newNodeP(nkStmtList, p)
while p.tok.tokType != tkEof:
p.hasProgress = false
var a = complexOrSimpleStmt(p)
if a.kind != nkEmpty and p.hasProgress:
result.add(a)
else:
parMessage(p, errExprExpected, p.tok)
# bugfix: consume a token here to prevent an endless loop:
getTok(p)
if p.tok.indent != 0:
parMessage(p, errInvalidIndentation)
setEndInfo()
proc checkFirstLineIndentation*(p: var Parser) =
if p.tok.indent != 0 and tsLeading in p.tok.spacing:
parMessage(p, errInvalidIndentation)
@@ -2561,6 +2551,16 @@ proc parseTopLevelStmt(p: var Parser): PNode =
break
setEndInfo()
proc parseAll*(p: var Parser): PNode =
## Parses the rest of the input stream held by the parser into a PNode.
result = newNodeP(nkStmtList, p)
while true:
let nextStmt = p.parseTopLevelStmt()
if nextStmt.kind == nkEmpty:
break
result &= nextStmt
setEndInfo()
proc parseString*(s: string; cache: IdentCache; config: ConfigRef;
filename: string = ""; line: int = 0;
errorHandler: ErrorHandler = nil): PNode =

View File

@@ -5,10 +5,12 @@ import sem, cgen, modulegraphs, ast, llstream, parser, msgs,
import pipelineutils
import ../dist/checksums/src/checksums/sha1
when not defined(leanCompiler):
import jsgen, docgen2
import std/[syncio, objectdollar, assertions, tables, strutils]
import std/[syncio, objectdollar, assertions, tables, strutils, strtabs]
import renderer
import ic/replayer
@@ -89,7 +91,7 @@ proc processPipelineModule*(graph: ModuleGraph; module: PSym; idgen: IdGenerator
stream: PLLStream): bool =
if graph.stopCompile(): return true
var
p: Parser
p: Parser = default(Parser)
s: PLLStream
fileIdx = module.fileIdx
@@ -225,7 +227,10 @@ proc compilePipelineModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymF
if result == nil:
var cachedModules: seq[FileIndex]
result = moduleFromRodFile(graph, fileIdx, cachedModules)
let filename = AbsoluteFile toFullPath(graph.config, fileIdx)
let path = toFullPath(graph.config, fileIdx)
let filename = AbsoluteFile path
if fileExists(filename): # it could be a stdinfile
graph.cachedFiles[path] = $secureHashFile(path)
if result == nil:
result = newModule(graph, fileIdx)
result.flags.incl flags

View File

@@ -330,7 +330,7 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
# {.dynlib: myGetProcAddr(...).}
result = c.semExpr(c, n[1])
if result.kind == nkSym and result.sym.kind == skConst:
result = result.sym.astdef # look it up
result = c.semConstExpr(c, result) # fold const
if result.typ == nil or result.typ.kind notin {tyPointer, tyString, tyProc}:
localError(c.config, n.info, errStringLiteralExpected)
result = newEmptyStrNode(c, n)
@@ -468,6 +468,18 @@ proc processOption(c: PContext, n: PNode, resOptions: var TOptions) =
# calling conventions (boring...):
localError(c.config, n.info, "option expected")
proc checkPushedPragma(c: PContext, n: PNode) =
let keyDeep = n.kind in nkPragmaCallKinds and n.len > 1
var key = if keyDeep: n[0] else: n
if key.kind in nkIdentKinds:
let ident = considerQuotedIdent(c, key)
var userPragma = strTableGet(c.userPragmas, ident)
if userPragma == nil:
let k = whichKeyword(ident)
# TODO: might as well make a list which is not accepted by `push`: emit, cast etc.
if k == wEmit:
localError(c.config, n.info, "an 'emit' pragma cannot be pushed")
proc processPush(c: PContext, n: PNode, start: int) =
if n[start-1].kind in nkPragmaCallKinds:
localError(c.config, n.info, "'push' cannot have arguments")
@@ -475,6 +487,7 @@ proc processPush(c: PContext, n: PNode, start: int) =
for i in start..<n.len:
if not tryProcessOption(c, n[i], c.config.options):
# simply store it somewhere:
checkPushedPragma(c, n[i])
if x.otherPragmas.isNil:
x.otherPragmas = newNodeI(nkPragma, n.info)
x.otherPragmas.add n[i]
@@ -849,6 +862,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
# number of pragmas increase/decrease with user pragma expansion
inc c.instCounter
defer: dec c.instCounter
if c.instCounter > 100:
globalError(c.config, it.info, "recursive dependency: " & userPragma.name.s)
@@ -858,7 +872,6 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
pragma(c, sym, userPragma.ast, validPragmas, isStatement)
n.sons[i..i] = userPragma.ast.sons # expand user pragma with its content
i.inc(userPragma.ast.len - 1) # inc by -1 is ok, user pragmas was empty
dec c.instCounter
else:
let k = whichKeyword(ident)
if k in validPragmas:
@@ -1112,13 +1125,20 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
of wFatal: fatal(c.config, it.info, expectStrLit(c, it))
of wDefine: processDefine(c, it, sym)
of wUndef: processUndef(c, it)
of wCompile: processCompile(c, it)
of wCompile:
let m = sym.getModule()
incl(m.flags, sfUsed)
processCompile(c, it)
of wLink: processLink(c, it)
of wPassl:
let m = sym.getModule()
incl(m.flags, sfUsed)
let s = expectStrLit(c, it)
extccomp.addLinkOption(c.config, s)
recordPragma(c, it, "passl", s)
of wPassc:
let m = sym.getModule()
incl(m.flags, sfUsed)
let s = expectStrLit(c, it)
extccomp.addCompileOption(c.config, s)
recordPragma(c, it, "passc", s)
@@ -1275,8 +1295,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
pragmaProposition(c, it)
of wEnsures:
pragmaEnsures(c, it)
of wEnforceNoRaises, wQuirky:
of wEnforceNoRaises:
sym.flags.incl sfNeverRaises
of wQuirky:
sym.flags.incl sfNeverRaises
if sym.kind in {skProc, skMethod, skConverter, skFunc, skIterator}:
sym.options.incl optQuirky
of wSystemRaisesDefect:
sym.flags.incl sfSystemRaisesDefect
of wVirtual:

View File

@@ -31,7 +31,7 @@ proc equalGenericParams(procA, procB: PNode): bool =
proc searchForProcAux(c: PContext, scope: PScope, fn: PSym): PSym =
const flags = {ExactGenericParams, ExactTypeDescValues,
ExactConstraints, IgnoreCC}
var it: TIdentIter
var it: TIdentIter = default(TIdentIter)
result = initIdentIter(it, scope.symbols, fn.name)
while result != nil:
if result.kind == fn.kind: #and sameType(result.typ, fn.typ, flags):
@@ -74,7 +74,7 @@ when false:
proc searchForBorrowProc*(c: PContext, startScope: PScope, fn: PSym): PSym =
# Searches for the fn in the symbol table. If the parameter lists are suitable
# for borrowing the sym in the symbol table is returned, else nil.
var it: TIdentIter
var it: TIdentIter = default(TIdentIter)
for scope in walkScopes(startScope):
result = initIdentIter(it, scope.symbols, fn.Name)
while result != nil:

View File

@@ -14,7 +14,7 @@
{.used.}
import
lexer, options, idents, strutils, ast, msgs, lineinfos
lexer, options, idents, strutils, ast, msgs, lineinfos, wordrecg
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions, formatfloat]
@@ -515,6 +515,7 @@ proc lsub(g: TSrcGen; n: PNode): int =
result = if n.len > 0: lcomma(g, n) + 2 else: len("{:}")
of nkClosedSymChoice, nkOpenSymChoice:
if n.len > 0: result += lsub(g, n[0])
of nkOpenSym: result = lsub(g, n[0])
of nkTupleTy: result = lcomma(g, n) + len("tuple[]")
of nkTupleClassTy: result = len("tuple")
of nkDotExpr: result = lsons(g, n) + 1
@@ -556,8 +557,16 @@ proc lsub(g: TSrcGen; n: PNode): int =
of nkIfExpr:
result = lsub(g, n[0][0]) + lsub(g, n[0][1]) + lsons(g, n, 1) +
len("if_:_")
of nkElifExpr: result = lsons(g, n) + len("_elif_:_")
of nkElseExpr: result = lsub(g, n[0]) + len("_else:_") # type descriptions
of nkElifExpr, nkElifBranch:
if isEmptyType(n[1].typ):
result = lsons(g, n) + len("elif_:_")
else:
result = lsons(g, n) + len("_elif_:_")
of nkElseExpr, nkElse:
if isEmptyType(n[0].typ):
result = lsub(g, n[0]) + len("else:_")
else:
result = lsub(g, n[0]) + len("_else:_") # type descriptions
of nkTypeOfExpr: result = (if n.len > 0: lsub(g, n[0]) else: 0)+len("typeof()")
of nkRefTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ref")
of nkPtrTy: result = (if n.len > 0: lsub(g, n[0])+1 else: 0) + len("ptr")
@@ -600,8 +609,6 @@ proc lsub(g: TSrcGen; n: PNode): int =
of nkCommentStmt: result = n.comment.len
of nkOfBranch: result = lcomma(g, n, 0, - 2) + lsub(g, lastSon(n)) + len("of_:_")
of nkImportAs: result = lsub(g, n[0]) + len("_as_") + lsub(g, n[1])
of nkElifBranch: result = lsons(g, n) + len("elif_:_")
of nkElse: result = lsub(g, n[0]) + len("else:_")
of nkFinally: result = lsub(g, n[0]) + len("finally:_")
of nkGenericParams: result = lcomma(g, n) + 2
of nkFormalParams:
@@ -848,7 +855,7 @@ proc gcase(g: var TSrcGen, n: PNode) =
gsub(g, n[^1], c)
proc genSymSuffix(result: var string, s: PSym) {.inline.} =
if sfGenSym in s.flags:
if sfGenSym in s.flags and s.name.id != ord(wUnderscore):
result.add '_'
result.addInt s.id
@@ -874,7 +881,7 @@ proc gproc(g: var TSrcGen, n: PNode) =
if renderNoPragmas notin g.flags:
gsub(g, n[pragmasPos])
if renderNoBody notin g.flags:
if n[bodyPos].kind != nkEmpty:
if n.len > bodyPos and n[bodyPos].kind != nkEmpty:
put(g, tkSpaces, Space)
putWithSpace(g, tkEquals, "=")
indentNL(g)
@@ -971,7 +978,9 @@ proc gident(g: var TSrcGen, n: PNode) =
s.addInt localId
if sfCursor in n.sym.flags:
s.add "_cursor"
elif n.kind == nkSym and (renderIds in g.flags or sfGenSym in n.sym.flags or n.sym.kind == skTemp):
elif n.kind == nkSym and (renderIds in g.flags or
(sfGenSym in n.sym.flags and n.sym.name.id != ord(wUnderscore)) or
n.sym.kind == skTemp):
s.add '_'
s.addInt n.sym.id
when defined(debugMagics):
@@ -1017,7 +1026,7 @@ proc bracketKind*(g: TSrcGen, n: PNode): BracketKind =
proc skipHiddenNodes(n: PNode): PNode =
result = n
while result != nil:
if result.kind in {nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv} and result.len > 1:
if result.kind in {nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv, nkOpenSym} and result.len > 1:
result = result[1]
elif result.kind in {nkCheckedFieldExpr, nkHiddenAddr, nkHiddenDeref, nkStringToCString, nkCStringToString} and
result.len > 0:
@@ -1277,6 +1286,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
put(g, tkParRi, if n.kind == nkOpenSymChoice: "|...)" else: ")")
else:
gsub(g, n, 0)
of nkOpenSym: gsub(g, n, 0)
of nkPar, nkClosure:
put(g, tkParLe, "(")
gcomma(g, n, c)
@@ -1306,10 +1316,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
put(g, tkCustomLit, n[0].strVal)
gsub(g, n, 1)
else:
gsub(g, n, 0)
for i in 0..<n.len-1:
gsub(g, n, i)
put(g, tkDot, ".")
assert n.len == 2, $n.len
accentedName(g, n[1])
if n.len > 1:
accentedName(g, n[^1])
of nkBind:
putWithSpace(g, tkBind, "bind")
gsub(g, n, 0)
@@ -1454,15 +1465,30 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
putWithSpace(g, tkColon, ":")
if n.len > 0: gsub(g, n[0], 1)
gsons(g, n, emptyContext, 1)
of nkElifExpr:
putWithSpace(g, tkElif, " elif")
gcond(g, n[0])
putWithSpace(g, tkColon, ":")
gsub(g, n, 1)
of nkElseExpr:
put(g, tkElse, " else")
putWithSpace(g, tkColon, ":")
gsub(g, n, 0)
of nkElifExpr, nkElifBranch:
if isEmptyType(n[1].typ):
optNL(g)
putWithSpace(g, tkElif, "elif")
gsub(g, n, 0)
putWithSpace(g, tkColon, ":")
gcoms(g)
gstmts(g, n[1], c)
else:
putWithSpace(g, tkElif, " elif")
gcond(g, n[0])
putWithSpace(g, tkColon, ":")
gsub(g, n, 1)
of nkElseExpr, nkElse:
if isEmptyType(n[0].typ):
optNL(g)
put(g, tkElse, "else")
putWithSpace(g, tkColon, ":")
gcoms(g)
gstmts(g, n[0], c)
else:
put(g, tkElse, " else")
putWithSpace(g, tkColon, ":")
gsub(g, n, 0)
of nkTypeOfExpr:
put(g, tkType, "typeof")
put(g, tkParLe, "(")
@@ -1524,17 +1550,16 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
gsub(g, n[0])
gsub(g, n[1])
gcoms(g)
indentNL(g)
gsub(g, n[2])
dedent(g)
else:
put(g, tkObject, "object")
of nkRecList:
indentNL(g)
for i in 0..<n.len:
optNL(g)
gsub(g, n[i], c)
gcoms(g)
dedent(g)
putNL(g)
of nkOfInherit:
putWithSpace(g, tkOf, "of")
gsub(g, n, 0)
@@ -1725,19 +1750,6 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext, fromStmtList = false) =
of nkMixinStmt:
putWithSpace(g, tkMixin, "mixin")
gcomma(g, n, c)
of nkElifBranch:
optNL(g)
putWithSpace(g, tkElif, "elif")
gsub(g, n, 0)
putWithSpace(g, tkColon, ":")
gcoms(g)
gstmts(g, n[1], c)
of nkElse:
optNL(g)
put(g, tkElse, "else")
putWithSpace(g, tkColon, ":")
gcoms(g)
gstmts(g, n[0], c)
of nkFinally, nkDefer:
optNL(g)
if n.kind == nkFinally:

View File

@@ -319,6 +319,14 @@ proc intersects(s1, s2: IntSet): bool =
if s2.contains(a):
return true
proc hasPushOrPopPragma(n: DepN): bool =
# Checks if the tree node has some pragmas that do not
# play well with reordering, like the push/pop pragma
# no crossing for push/pop barrier
let a = n.pnode
result = a.kind == nkPragma and a[0].kind == nkIdent and
(a[0].ident.s == "push" or a[0].ident.s == "pop")
proc buildGraph(n: PNode, deps: seq[(IntSet, IntSet)]): DepG =
# Build a dependency graph
result = newSeqOfCap[DepN](deps.len)
@@ -360,6 +368,13 @@ proc buildGraph(n: PNode, deps: seq[(IntSet, IntSet)]): DepG =
for dep in deps[i][0]:
if dep in declares:
ni.expls.add "one declares \"" & idNames[dep] & "\" and the other defines it"
elif hasPushOrPopPragma(nj):
# Every node that comes after a push/pop pragma must
# depend on it; vice versa
if j < i:
ni.kids.add nj
else:
nj.kids.add ni
else:
for d in declares:
if uses.contains(d):
@@ -393,23 +408,14 @@ proc strongConnect(v: var DepN, idx: var int, s: var seq[DepN],
proc getStrongComponents(g: var DepG): seq[seq[DepN]] =
## Tarjan's algorithm. Performs a topological sort
## and detects strongly connected components.
var s: seq[DepN]
result = @[]
var s: seq[DepN] = @[]
var idx = 0
for v in g.mitems:
if v.idx < 0:
strongConnect(v, idx, s, result)
proc hasForbiddenPragma(n: PNode): bool =
# Checks if the tree node has some pragmas that do not
# play well with reordering, like the push/pop pragma
for a in n:
if a.kind == nkPragma and a[0].kind == nkIdent and
a[0].ident.s == "push":
return true
proc reorder*(graph: ModuleGraph, n: PNode, module: PSym): PNode =
if n.hasForbiddenPragma:
return n
var includedFiles = initIntSet()
let mpath = toFullPath(graph.config, module.fileIdx)
let n = expandIncludes(graph, module, n, mpath,

View File

@@ -26,7 +26,10 @@ when not defined(leanCompiler):
import spawn
when defined(nimPreviewSlimSystem):
import std/formatfloat
import std/[
formatfloat,
assertions,
]
# implementation
@@ -85,6 +88,11 @@ proc fitNodePostMatch(c: PContext, formal: PType, arg: PNode): PNode =
changeType(c, x, formal, check=true)
result = arg
result = skipHiddenSubConv(result, c.graph, c.idgen)
# mark inserted converter as used:
var a = result
if a.kind == nkHiddenDeref: a = a[0]
if a.kind == nkHiddenCallConv and a[0].kind == nkSym:
markUsed(c, a.info, a[0].sym)
proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
@@ -205,13 +213,19 @@ proc commonType*(c: PContext; x, y: PType): PType =
result = newType(k, nextTypeId(c.idgen), r.owner)
result.addSonSkipIntLit(r, c.idgen)
proc endsInNoReturn(n: PNode): bool =
# check if expr ends in raise exception or call of noreturn proc
var it = n
while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
it = it.lastSon
result = it.kind in nkLastBlockStmts or
it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt64, tyBool}
proc shouldCheckCaseCovered(caseTyp: PType): bool =
result = false
case caseTyp.kind
of shouldChckCovered:
result = true
of tyRange:
if skipTypes(caseTyp[0], abstractInst).kind in shouldChckCovered:
result = true
else:
discard
proc endsInNoReturn(n: PNode): bool
proc commonType*(c: PContext; x: PType, y: PNode): PType =
# ignore exception raising branches in case/if expressions
@@ -243,6 +257,8 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
result.owner = getCurrOwner(c)
else:
result = newSym(kind, considerQuotedIdent(c, n), c.idgen, getCurrOwner(c), n.info)
if find(result.name.s, '`') >= 0:
result.flags.incl sfWasGenSym
#if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule:
# incl(result.flags, sfGlobal)
when defined(nimsuggest):
@@ -252,7 +268,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym
# identifier with visibility
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym
allowed: TSymFlags, fromTopLevel = false): PSym
proc typeAllowedCheck(c: PContext; info: TLineInfo; typ: PType; kind: TSymKind;
flags: TTypeAllowedFlags = {}) =
@@ -351,6 +367,11 @@ proc tryConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
c.config.m.errorOutputs = {}
c.config.errorMax = high(int) # `setErrorMaxHighMaybe` not appropriate here
when defined(nimsuggest):
# Remove the error hook so nimsuggest doesn't report errors there
let tempHook = c.graph.config.structuredErrorHook
c.graph.config.structuredErrorHook = nil
try:
result = evalConstExpr(c.module, c.idgen, c.graph, e)
if result == nil or result.kind == nkEmpty:
@@ -361,6 +382,10 @@ proc tryConstExpr(c: PContext, n: PNode; expectedType: PType = nil): PNode =
except ERecoverableError:
result = nil
when defined(nimsuggest):
# Restore the error hook
c.graph.config.structuredErrorHook = tempHook
c.config.errorCounter = oldErrorCount
c.config.errorMax = oldErrorMax
c.config.m.errorOutputs = oldErrorOutputs
@@ -462,7 +487,13 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
# we now know the supplied arguments
var paramTypes = newIdTable()
for param, value in genericParamsInMacroCall(s, call):
idTablePut(paramTypes, param.typ, value.typ)
var givenType = value.typ
# the sym nodes used for the supplied generic arguments for
# templates and macros leave type nil so regular sem can handle it
# in this case, get the type directly from the sym
if givenType == nil and value.kind == nkSym and value.sym.typ != nil:
givenType = value.sym.typ
idTablePut(paramTypes, param.typ, givenType)
retType = generateTypeInstance(c, paramTypes,
macroResult.info, retType)
@@ -470,7 +501,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
if retType.kind == tyVoid:
result = semStmt(c, result, flags)
else:
result = semExpr(c, result, flags, expectedType)
result = semExpr(c, result, flags)
result = fitNode(c, retType, result, result.info)
#globalError(s.info, errInvalidParamKindX, typeToString(s.typ[0]))
dec(c.config.evalTemplateCounter)

View File

@@ -68,7 +68,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
# `matches` may find new symbols, so keep track of count
var symCount = c.currentScope.symbols.counter
var o: TOverloadIter
var o: TOverloadIter = default(TOverloadIter)
# https://github.com/nim-lang/Nim/issues/21272
# prevent mutation during iteration by storing them in a seq
# luckily `initCandidateSymbols` does just that
@@ -236,44 +236,89 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
candidates.add("\n")
let nArg = if err.firstMismatch.arg < n.len: n[err.firstMismatch.arg] else: nil
let nameParam = if err.firstMismatch.formal != nil: err.firstMismatch.formal.name.s else: ""
if n.len > 1 and verboseTypeMismatch in c.config.legacyFeatures:
candidates.add(" first type mismatch at position: " & $err.firstMismatch.arg)
# candidates.add "\n reason: " & $err.firstMismatch.kind # for debugging
case err.firstMismatch.kind
of kUnknownNamedParam:
if nArg == nil:
candidates.add("\n unknown named parameter")
else:
candidates.add("\n unknown named parameter: " & $nArg[0])
of kAlreadyGiven: candidates.add("\n named param already provided: " & $nArg[0])
of kPositionalAlreadyGiven: candidates.add("\n positional param was already given as named param")
of kExtraArg: candidates.add("\n extra argument given")
of kMissingParam: candidates.add("\n missing parameter: " & nameParam)
of kTypeMismatch, kVarNeeded:
doAssert nArg != nil
let wanted = err.firstMismatch.formal.typ
doAssert err.firstMismatch.formal != nil
candidates.add("\n required type for " & nameParam & ": ")
candidates.addTypeDeclVerboseMaybe(c.config, wanted)
candidates.add "\n but expression '"
if err.firstMismatch.kind == kVarNeeded:
if n.len > 1:
if verboseTypeMismatch notin c.config.legacyFeatures:
case err.firstMismatch.kind
of kUnknownNamedParam:
if nArg == nil:
candidates.add(" unknown named parameter")
else:
candidates.add(" unknown named parameter: " & $nArg[0])
candidates.add "\n"
of kAlreadyGiven:
candidates.add(" named param already provided: " & $nArg[0])
candidates.add "\n"
of kPositionalAlreadyGiven:
candidates.add(" positional param was already given as named param")
candidates.add "\n"
of kExtraArg:
candidates.add(" extra argument given")
candidates.add "\n"
of kMissingParam:
candidates.add(" missing parameter: " & nameParam)
candidates.add "\n"
of kVarNeeded:
doAssert nArg != nil
doAssert err.firstMismatch.formal != nil
candidates.add " expression '"
candidates.add renderNotLValue(nArg)
candidates.add "' is immutable, not 'var'"
else:
candidates.add renderTree(nArg)
candidates.add "' is of type: "
let got = nArg.typ
candidates.addTypeDeclVerboseMaybe(c.config, got)
candidates.add "\n"
of kTypeMismatch:
doAssert nArg != nil
let wanted = err.firstMismatch.formal.typ
doAssert err.firstMismatch.formal != nil
doAssert wanted != nil
if got != nil:
if got.kind == tyProc and wanted.kind == tyProc:
# These are proc mismatches so,
# add the extra explict detail of the mismatch
candidates.addPragmaAndCallConvMismatch(wanted, got, c.config)
let got = nArg.typ
if got != nil and got.kind == tyProc and wanted.kind == tyProc:
# These are proc mismatches so,
# add the extra explict detail of the mismatch
candidates.add " expression '"
candidates.add renderTree(nArg)
candidates.add "' is of type: "
candidates.addTypeDeclVerboseMaybe(c.config, got)
candidates.addPragmaAndCallConvMismatch(wanted, got, c.config)
effectProblem(wanted, got, candidates, c)
candidates.add "\n"
of kUnknown: discard "do not break 'nim check'"
else:
candidates.add(" first type mismatch at position: " & $err.firstMismatch.arg)
# candidates.add "\n reason: " & $err.firstMismatch.kind # for debugging
case err.firstMismatch.kind
of kUnknownNamedParam:
if nArg == nil:
candidates.add("\n unknown named parameter")
else:
candidates.add("\n unknown named parameter: " & $nArg[0])
of kAlreadyGiven: candidates.add("\n named param already provided: " & $nArg[0])
of kPositionalAlreadyGiven: candidates.add("\n positional param was already given as named param")
of kExtraArg: candidates.add("\n extra argument given")
of kMissingParam: candidates.add("\n missing parameter: " & nameParam)
of kTypeMismatch, kVarNeeded:
doAssert nArg != nil
let wanted = err.firstMismatch.formal.typ
doAssert err.firstMismatch.formal != nil
candidates.add("\n required type for " & nameParam & ": ")
candidates.addTypeDeclVerboseMaybe(c.config, wanted)
candidates.add "\n but expression '"
if err.firstMismatch.kind == kVarNeeded:
candidates.add renderNotLValue(nArg)
candidates.add "' is immutable, not 'var'"
else:
candidates.add renderTree(nArg)
candidates.add "' is of type: "
let got = nArg.typ
candidates.addTypeDeclVerboseMaybe(c.config, got)
doAssert wanted != nil
if got != nil:
if got.kind == tyProc and wanted.kind == tyProc:
# These are proc mismatches so,
# add the extra explict detail of the mismatch
candidates.addPragmaAndCallConvMismatch(wanted, got, c.config)
effectProblem(wanted, got, candidates, c)
of kUnknown: discard "do not break 'nim check'"
candidates.add "\n"
of kUnknown: discard "do not break 'nim check'"
candidates.add "\n"
if err.firstMismatch.arg == 1 and nArg.kind == nkTupleConstr and
n.kind == nkCommand:
maybeWrongSpace = true
@@ -354,7 +399,7 @@ proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
proc bracketNotFoundError(c: PContext; n: PNode) =
var errors: CandidateErrors = @[]
var o: TOverloadIter
var o: TOverloadIter = default(TOverloadIter)
let headSymbol = n[0]
var symx = initOverloadIter(o, c, headSymbol)
while symx != nil:
@@ -376,7 +421,7 @@ proc getMsgDiagnostic(c: PContext, flags: TExprFlags, n, f: PNode): string =
# also avoid slowdowns in evaluating `compiles(expr)`.
discard
else:
var o: TOverloadIter
var o: TOverloadIter = default(TOverloadIter)
var sym = initOverloadIter(o, c, f)
while sym != nil:
result &= "\n found $1" % [getSymRepr(c.config, sym)]
@@ -420,7 +465,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
filter, result, alt, errors, efExplain in flags,
errorsEnabled, flags)
var dummyErrors: CandidateErrors
var dummyErrors: CandidateErrors = @[]
template pickSpecialOp(headSymbol) =
pickBestCandidate(c, headSymbol, n, orig, initialBinding,
filter, result, alt, dummyErrors, efExplain in flags,
@@ -511,6 +556,15 @@ proc instGenericConvertersSons*(c: PContext, n: PNode, x: TCandidate) =
for i in 1..<n.len:
instGenericConvertersArg(c, n[i], x)
proc markConvertersUsed*(c: PContext, n: PNode) =
assert n.kind in nkCallKinds
for i in 1..<n.len:
var a = n[i]
if a == nil: continue
if a.kind == nkHiddenDeref: a = a[0]
if a.kind == nkHiddenCallConv and a[0].kind == nkSym:
markUsed(c, a.info, a[0].sym)
proc indexTypesMatch(c: PContext, f, a: PType, arg: PNode): PNode =
var m = newCandidate(c, f)
result = paramTypesMatch(m, f, a, arg, nil)
@@ -595,14 +649,21 @@ proc semResolvedCall(c: PContext, x: TCandidate,
else:
x.call.add c.graph.emptyNode
of skType:
x.call.add newSymNode(s, n.info)
var tn = newSymNode(s, n.info)
# this node will be used in template substitution,
# pretend this is an untyped node and let regular sem handle the type
# to prevent problems where a generic parameter is treated as a value
tn.typ = nil
x.call.add tn
else:
internalAssert c.config, false
result = x.call
instGenericConvertersSons(c, result, x)
markConvertersUsed(c, result)
result[0] = newSymNode(finalCallee, getCallLineInfo(result[0]))
result.typ = finalCallee.typ[0]
if finalCallee.magic notin {mArrGet, mArrPut}:
result.typ = finalCallee.typ[0]
updateDefaultParams(result)
proc canDeref(n: PNode): bool {.inline.} =
@@ -665,14 +726,18 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
onUse(info, s)
result = newSymNode(newInst, info)
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
assert n.kind == nkBracketExpr
proc setGenericParams(c: PContext, n: PNode) =
## sems generic params in subscript expression
for i in 1..<n.len:
let e = semExprWithType(c, n[i])
if e.typ == nil:
n[i].typ = errorType(c)
else:
n[i].typ = e.typ.skipTypes({tyTypeDesc})
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
assert n.kind == nkBracketExpr
setGenericParams(c, n)
var s = s
var a = n[0]
if a.kind == nkSym:
@@ -707,17 +772,25 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
else:
result = explicitGenericInstError(c, n)
proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): tuple[s: PSym, state: TBorrowState] =
# Searches for the fn in the symbol table. If the parameter lists are suitable
# for borrowing the sym in the symbol table is returned, else nil.
# New approach: generate fn(x, y, z) where x, y, z have the proper types
# and use the overloading resolution mechanism:
const desiredTypes = abstractVar + {tyCompositeTypeClass} - {tyTypeDesc, tyDistinct}
template getType(isDistinct: bool; t: PType):untyped =
if isDistinct: t.baseOfDistinct(c.graph, c.idgen) else: t
result = default(tuple[s: PSym, state: TBorrowState])
var call = newNodeI(nkCall, fn.info)
var hasDistinct = false
var isDistinct: bool
var x: PType
var t: PType
call.add(newIdentNode(fn.name, fn.info))
for i in 1..<fn.typ.n.len:
let param = fn.typ.n[i]
const desiredTypes = abstractVar + {tyCompositeTypeClass} - {tyTypeDesc, tyDistinct}
#[.
# We only want the type not any modifiers such as `ptr`, `var`, `ref` ...
# tyCompositeTypeClass is here for
@@ -726,22 +799,31 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
proc `$`(f: Foo): string {.borrow.}
# We want to skip the `Foo` to get `int`
]#
let t = skipTypes(param.typ, desiredTypes)
if t.kind == tyDistinct or param.typ.kind == tyDistinct: hasDistinct = true
var x: PType
t = skipTypes(param.typ, desiredTypes)
isDistinct = t.kind == tyDistinct or param.typ.kind == tyDistinct
if t.kind == tyGenericInvocation and t[0].lastSon.kind == tyDistinct:
result.state = bsGeneric
return
if isDistinct: hasDistinct = true
if param.typ.kind == tyVar:
x = newTypeS(param.typ.kind, c)
x.addSonSkipIntLit(t.baseOfDistinct(c.graph, c.idgen), c.idgen)
x.addSonSkipIntLit(getType(isDistinct, t), c.idgen)
else:
x = t.baseOfDistinct(c.graph, c.idgen)
call.add(newNodeIT(nkEmpty, fn.info, x))
x = getType(isDistinct, t)
var s = copySym(param.sym, c.idgen)
s.typ = x
s.info = param.info
call.add(newSymNode(s))
if hasDistinct:
let filter = if fn.kind in {skProc, skFunc}: {skProc, skFunc} else: {fn.kind}
var resolved = semOverloadedCall(c, call, call, filter, {})
if resolved != nil:
result = resolved[0].sym
if not compareTypes(result.typ[0], fn.typ[0], dcEqIgnoreDistinct):
result = nil
elif result.magic in {mArrPut, mArrGet}:
result.s = resolved[0].sym
result.state = bsMatch
if not compareTypes(result.s.typ[0], fn.typ[0], dcEqIgnoreDistinct, {IgnoreFlags}):
result.state = bsReturnNotMatch
elif result.s.magic in {mArrPut, mArrGet}:
# cannot borrow these magics for now
result = nil
result.state = bsNotSupported
else:
result.state = bsNoDistinct

View File

@@ -76,6 +76,7 @@ type
efNoDiagnostics,
efTypeAllowed # typeAllowed will be called after
efWantNoDefaults
efAllowSymChoice # symchoice node should not be resolved
TExprFlags* = set[TExprFlag]
@@ -168,7 +169,10 @@ type
sideEffects*: Table[int, seq[(TLineInfo, PSym)]] # symbol.id index
inUncheckedAssignSection*: int
importModuleLookup*: Table[int, seq[int]] # (module.ident.id, [module.id])
skipTypes*: seq[PNode] # used to skip types between passes in type section. So far only used for inheritance and sets.
skipTypes*: seq[PNode] # used to skip types between passes in type section. So far only used for inheritance, sets and generic bodies.
inTypeofContext*: int
TBorrowState* = enum
bsNone, bsReturnNotMatch, bsNoDistinct, bsGeneric, bsNotSupported, bsMatch
template config*(c: PContext): ConfigRef = c.graph.config

View File

@@ -52,19 +52,8 @@ template rejectEmptyNode(n: PNode) =
proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
rejectEmptyNode(n)
# same as 'semExprWithType' but doesn't check for proc vars
result = semExpr(c, n, flags + {efOperand})
result = semExpr(c, n, flags + {efOperand, efAllowSymChoice})
if result.typ != nil:
# XXX tyGenericInst here?
if result.typ.kind == tyProc and hasUnresolvedParams(result, {efOperand}):
#and tfUnresolved in result.typ.flags:
let owner = result.typ.owner
let err =
# consistent error message with evaltempl/semMacroExpr
if owner != nil and owner.kind in {skTemplate, skMacro}:
errMissingGenericParamsForTemplate % n.renderTree
else:
errProcHasNoConcreteType % n.renderTree
localError(c.config, n.info, err)
if result.typ.kind in {tyVar, tyLent}: result = newDeref(result)
elif {efWantStmt, efAllowStmt} * flags != {}:
result.typ = newTypeS(tyVoid, c)
@@ -90,39 +79,10 @@ proc semExprCheck(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType
# do not produce another redundant error message:
result = errorNode(c, n)
proc ambiguousSymChoice(c: PContext, orig, n: PNode): PNode =
let first = n[0].sym
if first.kind == skEnumField:
# choose the first resolved enum field, i.e. the latest in scope
# to mirror behavior before overloadable enums
if hintAmbiguousEnum in c.config.notes:
var err = "ambiguous enum field '" & first.name.s &
"' assumed to be of type " & typeToString(first.typ) &
" -- use one of the following:\n"
for child in n:
let candidate = child.sym
err.add " " & candidate.owner.name.s & "." & candidate.name.s & "\n"
message(c.config, orig.info, hintAmbiguousEnum, err)
result = n[0]
else:
var err = "ambiguous identifier '" & first.name.s &
"' -- use one of the following:\n"
for child in n:
let candidate = child.sym
err.add " " & candidate.owner.name.s & "." & candidate.name.s
err.add ": " & typeToString(candidate.typ) & "\n"
localError(c.config, orig.info, err)
n.typ = errorType(c)
result = n
proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
result = semExprCheck(c, n, flags-{efTypeAllowed}, expectedType)
if result.typ == nil and efInTypeof in flags:
result.typ = c.voidType
elif (result.typ == nil or result.typ.kind == tyNone) and
efTypeAllowed in flags and
result.kind == nkClosedSymChoice and result.len > 0:
result = ambiguousSymChoice(c, n, result)
elif result.typ == nil or result.typ == c.enforceVoidContext:
localError(c.config, n.info, errExprXHasNoType %
renderTree(result, {renderNoComments}))
@@ -155,6 +115,112 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
result = symChoice(c, n, s, scClosed)
proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode
proc isSymChoice(n: PNode): bool {.inline.} =
result = n.kind in nkSymChoices
proc resolveSymChoice(c: PContext, n: var PNode, flags: TExprFlags = {}, expectedType: PType = nil) =
## Attempts to resolve a symchoice `n`, `n` remains a symchoice if
## it cannot be resolved (this is the case even when `n.len == 1`).
if expectedType != nil:
# resolve from type inference, see paramTypesMatch
n = fitNode(c, expectedType, n, n.info)
if isSymChoice(n) and efAllowSymChoice notin flags:
# some contexts might want sym choices preserved for later disambiguation
# in general though they are ambiguous
let first = n[0].sym
var foundSym: PSym = nil
if first.kind == skEnumField and
not isAmbiguous(c, first.name, {skEnumField}, foundSym) and
foundSym == first:
# choose the first resolved enum field, i.e. the latest in scope
# to mirror behavior before overloadable enums
n = n[0]
proc semOpenSym(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType,
warnDisabled = false): PNode =
## sem the child of an `nkOpenSym` node, that is, captured symbols that can be
## replaced by newly injected symbols in generics. `s` must be the captured
## symbol if the original node is an `nkSym` node; and `nil` if it is an
## `nkOpenSymChoice`, in which case only non-overloadable injected symbols
## will be considered.
let isSym = n.kind == nkSym
let ident = n.getPIdent
assert ident != nil
let id = newIdentNode(ident, n.info)
c.isAmbiguous = false
let s2 = qualifiedLookUp(c, id, {})
# for `nkSym`, the first found symbol being different and unambiguous is
# enough to replace the original
# for `nkOpenSymChoice`, the first found symbol must be non-overloadable,
# since otherwise we have to use regular `nkOpenSymChoice` functionality
# but of the overloadable sym kinds, semExpr does not handle skModule, skMacro, skTemplate
# as overloaded in the case where `nkIdent` finds them first
if s2 != nil and not c.isAmbiguous and
((isSym and s2 != n.sym) or
(not isSym and s2.kind notin OverloadableSyms-{skModule, skMacro, skTemplate})):
# only consider symbols defined under current proc:
var o = s2.owner
while o != nil:
if o == c.p.owner:
if not warnDisabled:
result = semExpr(c, id, flags, expectedType)
return
else:
var msg =
"a new symbol '" & ident.s & "' has been injected during " &
# msgContext should show what is being instantiated:
"template or generic instantiation, however "
if isSym:
msg.add(
getSymRepr(c.config, n.sym) & " captured at " &
"the proc declaration will be used instead; " &
"either enable --experimental:openSym to use the injected symbol, " &
"or `bind` this captured symbol explicitly")
else:
msg.add(
"overloads of " & ident.s & " will be used instead; " &
"either enable --experimental:openSym to use the injected symbol, " &
"or `bind` this symbol explicitly")
message(c.config, n.info, warnIgnoredSymbolInjection, msg)
break
o = o.owner
# nothing found
n.flags.excl nfDisabledOpenSym
if not warnDisabled and isSym:
result = semExpr(c, n, flags, expectedType)
else:
result = nil
if not isSym:
# set symchoice node type back to None
n.typ = newTypeS(tyNone, c)
proc semSymChoice(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
if n.kind == nkOpenSymChoice:
result = semOpenSym(c, n, flags, expectedType,
warnDisabled = nfDisabledOpenSym in n.flags and
genericsOpenSym notin c.features)
if result != nil:
return
result = n
resolveSymChoice(c, result, flags, expectedType)
if isSymChoice(result) and result.len == 1:
# resolveSymChoice can leave 1 sym
result = result[0]
if isSymChoice(result) and efAllowSymChoice notin flags:
var err = "ambiguous identifier: '" & result[0].sym.name.s &
"' -- use one of the following:\n"
for child in n:
let candidate = child.sym
err.add " " & candidate.owner.name.s & "." & candidate.name.s
err.add ": " & typeToString(candidate.typ) & "\n"
localError(c.config, n.info, err)
n.typ = errorType(c)
result = n
if result.kind == nkSym:
result = semSym(c, result, result.sym, flags)
proc inlineConst(c: PContext, n: PNode, s: PSym): PNode {.inline.} =
result = copyTree(s.astdef)
if result.isNil:
@@ -223,7 +289,8 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus =
discard "convOk"
elif targetTyp.isOrdinalType:
if src.kind in nkCharLit..nkUInt64Lit and
src.getInt notin firstOrd(c.config, targetTyp)..lastOrd(c.config, targetTyp):
src.getInt notin firstOrd(c.config, targetTyp)..lastOrd(c.config, targetTyp) and
targetTyp.kind notin {tyUInt..tyUInt64}:
result = convNotInRange
elif src.kind in nkFloatLit..nkFloat64Lit and
(classify(src.floatVal) in {fcNan, fcNegInf, fcInf} or
@@ -238,6 +305,9 @@ proc checkConvertible(c: PContext, targetTyp: PType, src: PNode): TConvStatus =
result = convNotInRange
else:
# we use d, s here to speed up that operation a bit:
if d.kind == tyFromExpr:
result = convNotLegal
return
case cmpTypes(c, d, s)
of isNone, isGeneric:
if not compareTypes(targetTyp.skipTypes(abstractVar), srcTyp.skipTypes({tyOwned}), dcEqIgnoreDistinct):
@@ -291,9 +361,6 @@ proc isCastable(c: PContext; dst, src: PType, info: TLineInfo): bool =
if result and src.kind == tyNil:
return dst.size <= conf.target.ptrSize
proc isSymChoice(n: PNode): bool {.inline.} =
result = n.kind in nkSymChoices
proc maybeLiftType(t: var PType, c: PContext, info: TLineInfo) =
# XXX: liftParamType started to perform addDecl
# we could do that instead in semTypeNode by snooping for added
@@ -308,7 +375,7 @@ proc isOwnedSym(c: PContext; n: PNode): bool =
let s = qualifiedLookUp(c, n, {})
result = s != nil and sfSystemModule in s.owner.flags and s.name.s == "owned"
proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode =
proc semConv(c: PContext, n: PNode; flags: TExprFlags = {}, expectedType: PType = nil): PNode =
if n.len != 2:
localError(c.config, n.info, "a type conversion takes exactly one argument")
return n
@@ -355,10 +422,10 @@ proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode =
if n[1].kind == nkExprEqExpr and
targetType.skipTypes(abstractPtrs).kind == tyObject:
localError(c.config, n.info, "object construction uses ':', not '='")
var op = semExprWithType(c, n[1])
if op.kind == nkClosedSymChoice and op.len > 0 and
op[0].sym.kind == skEnumField: # resolves overloadedable enums
op = ambiguousSymChoice(c, n, op)
var op = semExprWithType(c, n[1], flags * {efDetermineType} + {efAllowSymChoice})
if isSymChoice(op) and op[0].sym.kind notin routineKinds:
# T(foo) disambiguation syntax only allowed for routines
op = semSymChoice(c, op)
if targetType.kind != tyGenericParam and targetType.isMetaType:
let final = inferWithMetatype(c, targetType, op, true)
result.add final
@@ -370,7 +437,9 @@ proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode =
# here or needs to be overwritten too then.
result.add op
if targetType.kind == tyGenericParam:
if targetType.kind == tyGenericParam or
(op.typ != nil and op.typ.kind == tyFromExpr and c.inGenericContext > 0):
# expression is compiled early in a generic body
result.typ = makeTypeFromExpr(c, copyTree(result))
return result
@@ -384,7 +453,8 @@ proc semConv(c: PContext, n: PNode; expectedType: PType = nil): PNode =
elif op.kind in {nkPar, nkTupleConstr} and targetType.kind == tyTuple:
op = fitNode(c, targetType, op, result.info)
of convNotNeedeed:
message(c.config, n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
if efNoSem2Check notin flags:
message(c.config, n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
of convNotLegal:
result = fitNode(c, result.typ, result[1], result.info)
if result == nil:
@@ -514,8 +584,9 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.typ = n.typ
proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
if n.len != 3:
if n.len != 3 or n[2].kind == nkEmpty:
localError(c.config, n.info, "'is' operator takes 2 arguments")
return errorNode(c, n)
let boolType = getSysType(c.graph, n.info, tyBool)
result = n
@@ -549,15 +620,14 @@ proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode =
n[1] = makeTypeSymNode(c, lhsType, n[1].info)
lhsType = n[1].typ
else:
if lhsType.base.kind == tyNone or
(c.inGenericContext > 0 and lhsType.base.containsGenericType):
if c.inGenericContext > 0 and lhsType.base.containsGenericType:
# BUGFIX: don't evaluate this too early: ``T is void``
return
result = isOpImpl(c, n, flags)
proc semOpAux(c: PContext, n: PNode) =
const flags = {efDetermineType}
const flags = {efDetermineType, efAllowSymChoice}
for i in 1..<n.len:
var a = n[i]
if a.kind == nkExprEqExpr and a.len == 2:
@@ -615,7 +685,7 @@ proc changeType(c: PContext; n: PNode, newType: PType, check: bool) =
a.add m
changeType(m, tup[i], check)
of nkCharLit..nkUInt64Lit:
if check and n.kind != nkUInt64Lit and not sameType(n.typ, newType):
if check and n.kind != nkUInt64Lit and not sameTypeOrNil(n.typ, newType):
let value = n.intVal
if value < firstOrd(c.config, newType) or value > lastOrd(c.config, newType):
localError(c.config, n.info, "cannot convert " & $value &
@@ -899,9 +969,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
n.typ.flags.incl tfUnresolved
# optimization pass: not necessary for correctness of the semantic pass
if callee.kind == skConst or
if (callee.kind == skConst or
{sfNoSideEffect, sfCompileTime} * callee.flags != {} and
{sfForward, sfImportc} * callee.flags == {} and n.typ != nil:
{sfForward, sfImportc} * callee.flags == {}) and n.typ != nil:
if callee.kind != skConst and
sfCompileTime notin callee.flags and
@@ -909,7 +979,8 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
if callee.magic notin ctfeWhitelist: return
if callee.kind notin {skProc, skFunc, skConverter, skConst} or callee.isGenericRoutine:
if callee.kind notin {skProc, skFunc, skConverter, skConst} or
callee.isGenericRoutineStrict:
return
if n.typ != nil and typeAllowed(n.typ, skConst, c) != nil: return
@@ -996,9 +1067,33 @@ proc bracketedMacro(n: PNode): PSym =
if result.kind notin {skMacro, skTemplate}:
result = nil
proc setGenericParams(c: PContext, n: PNode) =
for i in 1..<n.len:
n[i].typ = semTypeNode(c, n[i], nil)
proc finishOperand(c: PContext, a: PNode): PNode =
if a.typ.isNil:
result = c.semOperand(c, a, {efDetermineType})
else:
result = a
# XXX tyGenericInst here?
if result.typ.kind == tyProc and hasUnresolvedParams(result, {efOperand}):
#and tfUnresolved in result.typ.flags:
let owner = result.typ.owner
let err =
# consistent error message with evaltempl/semMacroExpr
if owner != nil and owner.kind in {skTemplate, skMacro}:
errMissingGenericParamsForTemplate % a.renderTree
else:
errProcHasNoConcreteType % a.renderTree
localError(c.config, a.info, err)
considerGenSyms(c, result)
proc semFinishOperands(c: PContext; n: PNode; isBracketExpr = false) =
# this needs to be called to ensure that after overloading resolution every
# argument has been sem'checked
# skip the first argument for operands of `[]` since it may be an unresolved
# generic proc, which is handled in semMagic
let start = 1 + ord(isBracketExpr)
for i in start..<n.len:
n[i] = finishOperand(c, n[i])
proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
if efNoSemCheck notin flags and n.typ != nil and n.typ.kind == tyError:
@@ -1020,7 +1115,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedTy
of skMacro: result = semMacroExpr(c, result, orig, callee, flags, expectedType)
of skTemplate: result = semTemplateExpr(c, result, callee, flags, expectedType)
else:
semFinishOperands(c, result)
semFinishOperands(c, result, isBracketExpr = callee.magic in {mArrGet, mArrPut})
activate(c, result)
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
@@ -1031,7 +1126,8 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedTy
not (result.typ.kind == tySequence and result.typ[0].kind == tyEmpty):
liftTypeBoundOps(c, result.typ, n.info)
#result = patchResolvedTypeBoundOp(c, result)
if c.matchedConcept == nil:
if c.matchedConcept == nil and (c.inTypeofContext == 0 or callee.magic != mNone):
# don't fold calls in concepts and typeof
result = evalAtCompileTime(c, result)
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
@@ -1051,7 +1147,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
else:
n[0] = n0
else:
n[0] = semExpr(c, n[0], {efInCall})
n[0] = semExpr(c, n[0], {efInCall, efAllowSymChoice})
let t = n[0].typ
if t != nil and t.kind in {tyVar, tyLent}:
n[0] = newDeref(n[0])
@@ -1069,7 +1165,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
t = skipTypes(n[0].typ, abstractInst+{tyOwned}-{tyTypeDesc, tyDistinct})
if t != nil and t.kind == tyTypeDesc:
if n.len == 1: return semObjConstr(c, n, flags, expectedType)
return semConv(c, n)
return semConv(c, n, flags)
let nOrig = n.copyTree
semOpAux(c, n)
@@ -1106,10 +1202,10 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
msg.addDeclaredLocMaybe(c.config, typ)
localError(c.config, n.info, msg)
return errorNode(c, n)
result = nil
else:
result = m.call
instGenericConvertersSons(c, result, m)
markConvertersUsed(c, result)
else:
result = overloadedCallOpr(c, n) # this uses efNoUndeclared
@@ -1249,7 +1345,9 @@ proc readTypeParameter(c: PContext, typ: PType,
# This seems semantically correct and then we'll be able
# to return the section symbol directly here
let foundType = makeTypeDesc(c, def[2].typ)
return newSymNode(copySym(def[0].sym, c.idgen).linkTo(foundType), info)
let s = copySym(def[0].sym, c.idgen)
s.typ = foundType
return newSymNode(s, info)
of nkConstSection:
for def in statement:
@@ -1274,7 +1372,9 @@ proc readTypeParameter(c: PContext, typ: PType,
return c.graph.emptyNode
else:
let foundTyp = makeTypeDesc(c, rawTyp)
return newSymNode(copySym(tParam.sym, c.idgen).linkTo(foundTyp), info)
let s = copySym(tParam.sym, c.idgen)
s.typ = foundTyp
return newSymNode(s, info)
return nil
@@ -1364,6 +1464,8 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
if n.kind != nkDotExpr: # dotExpr is already checked by builtinFieldAccess
markUsed(c, n.info, s)
onUse(n.info, s)
if s.typ == nil:
return localErrorNode(c, n, "symbol '$1' has no type" % [s.name.s])
if s.typ.kind == tyStatic and s.typ.base.kind != tyNone and s.typ.n != nil:
return s.typ.n
result = newSymNode(s, n.info)
@@ -1457,7 +1559,8 @@ proc builtinFieldAccess(c: PContext; n: PNode; flags: var TExprFlags): PNode =
onUse(n[1].info, s)
return
n[0] = semExprWithType(c, n[0], flags+{efDetermineType, efWantIterable})
# extra flags since LHS may become a call operand:
n[0] = semExprWithType(c, n[0], flags+{efDetermineType, efWantIterable, efAllowSymChoice})
#restoreOldStyleType(n[0])
var i = considerQuotedIdent(c, n[1], n)
var ty = n[0].typ
@@ -1611,7 +1714,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
return
checkMinSonsLen(n, 2, c.config)
# signal that generic parameters may be applied after
n[0] = semExprWithType(c, n[0], {efNoEvaluateGeneric})
n[0] = semExprWithType(c, n[0], {efNoEvaluateGeneric, efAllowSymChoice})
var arr = skipTypes(n[0].typ, {tyGenericInst, tyUserTypeClassInst, tyOwned,
tyVar, tyLent, tyPtr, tyRef, tyAlias, tySink})
if arr.kind == tyStatic:
@@ -1670,7 +1773,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = nil
else:
let s = if n[0].kind == nkSym: n[0].sym
elif n[0].kind in nkSymChoices: n[0][0].sym
elif n[0].kind in nkSymChoices + {nkOpenSym}: n[0][0].sym
else: nil
if s != nil:
case s.kind
@@ -1710,7 +1813,7 @@ proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
# this is ugly. XXX Semantic checking should use the ``nfSem`` flag for
# nodes?
let aOrig = nOrig[0]
result = newTreeI(nkCall, n.info, setterId, a[0], semExprWithType(c, n[1]))
result = newTreeI(nkCall, n.info, setterId, a[0], n[1])
result.flags.incl nfDotSetter
let orig = newTreeI(nkCall, n.info, setterId, aOrig[0], nOrig[1])
result = semOverloadedCallAnalyseEffects(c, result, orig, {})
@@ -1751,6 +1854,8 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode =
else:
localError(c.config, n.info, errExprHasNoAddress)
result = newNodeIT(nkHiddenAddr, n.info, if n.typ.kind in {tyVar, tyLent}: n.typ else: makePtrType(c, n.typ))
if n.typ.kind in {tyVar, tyLent}:
n.typ = n.typ.elementType
result.add(n)
proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
@@ -1817,6 +1922,39 @@ proc goodLineInfo(arg: PNode): TLineInfo =
else:
arg.info
proc makeTupleAssignments(c: PContext; n: PNode): PNode =
## expand tuple unpacking assignment into series of assignments
##
## mirrored with semstmts.makeVarTupleSection
let lhs = n[0]
let value = semExprWithType(c, n[1], {efTypeAllowed})
if value.typ.kind != tyTuple:
localError(c.config, n[1].info, errTupleUnpackingTupleExpected %
[typeToString(value.typ, preferDesc)])
elif lhs.len != value.typ.len:
localError(c.config, n.info, errTupleUnpackingDifferentLengths %
[$lhs.len, typeToString(value.typ, preferDesc), $value.typ.len])
result = newNodeI(nkStmtList, n.info)
let temp = newSym(skTemp, getIdent(c.cache, "tmpTupleAsgn"), c.idgen, getCurrOwner(c), n.info)
temp.typ = value.typ
temp.flags.incl(sfGenSym)
var v = newNodeI(nkLetSection, value.info)
let tempNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
var vpart = newNodeI(nkIdentDefs, v.info, 3)
vpart[0] = tempNode
vpart[1] = c.graph.emptyNode
vpart[2] = value
v.add vpart
result.add(v)
for i in 0..<lhs.len:
if lhs[i].kind == nkIdent and lhs[i].ident.id == ord(wUnderscore):
# skip _ assignments if we are using a temp as they are already evaluated
discard
else:
result.add newAsgnStmt(lhs[i], newTupleAccessRaw(tempNode, i))
proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
checkSonsLen(n, 2, c.config)
var a = n[0]
@@ -1845,7 +1983,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
result.add(n[1])
if mode == noOverloadedSubscript:
bracketNotFoundError(c, result)
return n
return errorNode(c, n)
else:
result = semExprNoType(c, result)
return result
@@ -1859,7 +1997,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
# unfortunately we need to rewrite ``(x, y) = foo()`` already here so
# that overloading of the assignment operator still works. Usually we
# prefer to do these rewritings in transf.nim:
return semStmt(c, lowerTupleUnpackingForAsgn(c.graph, n, c.idgen, c.p.owner), {})
return semStmt(c, makeTupleAssignments(c, n), {})
else:
a = semExprWithType(c, a, {efLValue})
else:
@@ -2009,12 +2147,10 @@ proc semYield(c: PContext, n: PNode): PNode =
if c.p.owner == nil or c.p.owner.kind != skIterator:
localError(c.config, n.info, errYieldNotAllowedHere)
elif n[0].kind != nkEmpty:
n[0] = semExprWithType(c, n[0]) # check for type compatibility:
var iterType = c.p.owner.typ
let restype = iterType[0]
n[0] = semExprWithType(c, n[0], {}, restype) # check for type compatibility:
if restype != nil:
if restype.kind != tyUntyped:
n[0] = fitNode(c, restype, n[0], n.info)
if n[0].typ == nil: internalError(c.config, n.info, "semYield")
if resultTypeIsInferrable(restype):
@@ -2022,6 +2158,8 @@ proc semYield(c: PContext, n: PNode): PNode =
iterType[0] = inferred
if c.p.resultSym != nil:
c.p.resultSym.typ = inferred
else:
n[0] = fitNode(c, restype, n[0], n.info)
semYieldVarResult(c, n, restype)
else:
@@ -2073,6 +2211,8 @@ proc lookUpForDeclared(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
result = n.sym
of nkOpenSymChoice, nkClosedSymChoice:
result = n[0].sym
of nkOpenSym:
result = lookUpForDeclared(c, n[0], onlyCurrentScope)
else:
localError(c.config, n.info, "identifier expected, but got: " & renderTree(n))
result = nil
@@ -2108,6 +2248,7 @@ proc expectString(c: PContext, n: PNode): string =
if n.kind in nkStrKinds:
return n.strVal
else:
result = ""
localError(c.config, n.info, errStringLiteralExpected)
proc newAnonSym(c: PContext; kind: TSymKind, info: TLineInfo): PSym =
@@ -2132,7 +2273,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
let headSymbol = macroCall[0]
var cands = 0
var cand: PSym = nil
var o: TOverloadIter
var o: TOverloadIter = default(TOverloadIter)
var symx = initOverloadIter(o, c, headSymbol)
while symx != nil:
if symx.kind in {skTemplate, skMacro} and symx.typ.len == macroCall.len:
@@ -2244,7 +2385,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
for i in 1..<ids.len:
let exp = semExprWithType(c, quotes[i+1], {})
let typ = exp.typ
if tfTriggersCompileTime notin typ.flags and exp.kind == nkSym and exp.sym.kind notin routineKinds + {skType}:
if tfTriggersCompileTime notin typ.flags and typ.kind != tyStatic and exp.kind == nkSym and exp.sym.kind notin routineKinds + {skType}:
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[i], newNodeIT(nkType, n.info, typ), c.graph.emptyNode)
else:
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[i], getSysSym(c.graph, n.info, "typed").newSymNode, c.graph.emptyNode)
@@ -2383,9 +2524,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: P
of mAddr:
markUsed(c, n.info, s)
checkSonsLen(n, 2, c.config)
result[0] = newSymNode(s, n[0].info)
result[1] = semAddrArg(c, n[1])
result.typ = makePtrType(c, result[1].typ)
result = semAddr(c, n[1])
of mTypeOf:
markUsed(c, n.info, s)
result = semTypeOf(c, n)
@@ -2512,9 +2651,10 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
# If semCheck is set to false, ``when`` will return the verbatim AST of
# the correct branch. Otherwise the AST will be passed through semStmt.
result = nil
let flags = if semCheck: {efWantStmt} else: {}
template setResult(e: untyped) =
if semCheck: result = semExpr(c, e) # do not open a new scope!
if semCheck: result = semExpr(c, e, flags) # do not open a new scope!
else: result = e
# Check if the node is "when nimvm"
@@ -2526,7 +2666,9 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
var typ = commonTypeBegin
if n.len in 1..2 and n[0].kind == nkElifBranch and (
n.len == 1 or n[1].kind == nkElse):
let exprNode = n[0][0]
var exprNode = n[0][0]
if exprNode.kind == nkOpenSym:
exprNode = exprNode[0]
if exprNode.kind == nkIdent:
whenNimvm = lookUp(c, exprNode).magic == mNimvm
elif exprNode.kind == nkSym:
@@ -2540,7 +2682,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
checkSonsLen(it, 2, c.config)
if whenNimvm:
if semCheck:
it[1] = semExpr(c, it[1])
it[1] = semExpr(c, it[1], flags)
typ = commonType(c, typ, it[1].typ)
result = n # when nimvm is not elimited until codegen
else:
@@ -2556,8 +2698,10 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
checkSonsLen(it, 1, c.config)
if result == nil or whenNimvm:
if semCheck:
it[0] = semExpr(c, it[0])
it[0] = semExpr(c, it[0], flags)
typ = commonType(c, typ, it[0].typ)
if typ != nil and typ.kind != tyUntyped:
it[0] = fitNode(c, typ, it[0], it[0].info)
if result == nil:
result = it[0]
else: illFormedAst(n, c.config)
@@ -2702,6 +2846,12 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType
# can check if field name matches expected type here
let expectedElemType = if expected != nil: expected[i] else: nil
n[i][1] = semExprWithType(c, n[i][1], {}, expectedElemType)
if expectedElemType != nil and
(expectedElemType.kind != tyNil and not hasEmpty(expectedElemType)):
# hasEmpty/nil check is to not break existing code like
# `const foo = [(1, {}), (2, {false})]`,
# `const foo = if true: (0, nil) else: (1, new(int))`
n[i][1] = fitNode(c, expectedElemType, n[i][1], n[i][1].info)
if n[i][1].typ.kind == tyTypeDesc:
localError(c.config, n[i][1].info, "typedesc not allowed as tuple field.")
@@ -2728,6 +2878,12 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags; expectedT
for i in 0..<n.len:
let expectedElemType = if expected != nil: expected[i] else: nil
n[i] = semExprWithType(c, n[i], {}, expectedElemType)
if expectedElemType != nil and
(expectedElemType.kind != tyNil and not hasEmpty(expectedElemType)):
# hasEmpty/nil check is to not break existing code like
# `const foo = [(1, {}), (2, {false})]`,
# `const foo = if true: (0, nil) else: (1, new(int))`
n[i] = fitNode(c, expectedElemType, n[i], n[i].info)
addSonSkipIntLit(typ, n[i].typ, c.idgen)
result.typ = typ
@@ -2783,7 +2939,7 @@ proc semExport(c: PContext, n: PNode): PNode =
result = newNodeI(nkExportStmt, n.info)
for i in 0..<n.len:
let a = n[i]
var o: TOverloadIter
var o: TOverloadIter = default(TOverloadIter)
var s = initOverloadIter(o, c, a)
if s == nil:
localError(c.config, a.info, errGenerated, "cannot export: " & renderTree(a))
@@ -2863,6 +3019,18 @@ proc asBracketExpr(c: PContext; n: PNode): PNode =
return result
return nil
proc isOpenArraySym(x: PNode): bool =
var x = x
while true:
case x.kind
of {nkAddr, nkHiddenAddr}:
x = x[0]
of {nkHiddenStdConv, nkHiddenDeref}:
x = x[1]
else:
break
result = x.kind == nkSym
proc hoistParamsUsedInDefault(c: PContext, call, letSection, defExpr: var PNode) =
# This takes care of complicated signatures such as:
# proc foo(a: int, b = a)
@@ -2883,7 +3051,10 @@ proc hoistParamsUsedInDefault(c: PContext, call, letSection, defExpr: var PNode)
if defExpr.kind == nkSym and defExpr.sym.kind == skParam and defExpr.sym.owner == call[0].sym:
let paramPos = defExpr.sym.position + 1
if call[paramPos].kind != nkSym:
if call[paramPos].skipAddr.kind != nkSym and not (
skipTypes(call[paramPos].typ, abstractVar).kind in {tyOpenArray, tyVarargs} and
isOpenArraySym(call[paramPos])
):
let hoistedVarSym = newSym(skLet, getIdent(c.graph.cache, genPrefix), c.idgen,
c.p.owner, letSection.info, c.p.owner.options)
hoistedVarSym.typ = call[paramPos].typ
@@ -2909,8 +3080,8 @@ proc getNilType(c: PContext): PType =
result.align = c.config.target.ptrSize.int16
c.nilTypeCache = result
proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym): PNode =
var o: TOverloadIter
proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym; flags: TExprFlags): PNode =
var o: TOverloadIter = default(TOverloadIter)
var i = 0
var a = initOverloadIter(o, c, n)
while a != nil:
@@ -2922,7 +3093,7 @@ proc enumFieldSymChoice(c: PContext, n: PNode, s: PSym): PNode =
if i <= 1:
if sfGenSym notin s.flags:
result = newSymNode(s, info)
markUsed(c, info, s)
markUsed(c, info, s, efInCall notin flags)
onUse(info, s)
else:
result = n
@@ -2943,6 +3114,48 @@ proc semPragmaStmt(c: PContext; n: PNode) =
else:
pragma(c, c.p.owner, n, stmtPragmas, true)
proc resolveIdentToSym(c: PContext, n: PNode, resultNode: var PNode,
flags: TExprFlags, expectedType: PType): PSym =
# result is nil on error or if a node that can't produce a sym is resolved
let ident = considerQuotedIdent(c, n)
var filter = {low(TSymKind)..high(TSymKind)}
if efNoEvaluateGeneric in flags:
# `a[...]` where `a` is a module or package is not possible
filter.excl {skModule, skPackage}
let candidates = lookUpCandidates(c, ident, filter)
if candidates.len == 0:
result = errorUndeclaredIdentifierHint(c, ident, n.info)
elif candidates.len == 1 or {efNoEvaluateGeneric, efInCall} * flags != {}:
# unambiguous, or we don't care about ambiguity
result = candidates[0]
else:
# ambiguous symbols have 1 last chance as a symchoice,
# but type symbols cannot participate in symchoices
var choice = newNodeIT(nkClosedSymChoice, n.info, newTypeS(tyNone, c))
for c in candidates:
if c.kind notin {skType, skModule, skPackage}:
choice.add newSymNode(c, n.info)
if choice.len == 0:
# we know candidates.len > 1, we just couldn't put any in a symchoice
errorUseQualifier(c, n.info, candidates)
return nil
resolveSymChoice(c, choice, flags, expectedType)
# choice.len == 1 can be true here but as long as it's a symchoice
# it's still not resolved
if isSymChoice(choice):
result = nil
if efAllowSymChoice in flags:
resultNode = choice
else:
errorUseQualifier(c, n.info, candidates)
else:
if choice.kind == nkSym:
result = choice.sym
else:
# resolution could have generated nkHiddenStdConv etc
resultNode = semExpr(c, choice, flags, expectedType)
result = nil
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
when defined(nimCompilerStacktraceHints):
setFrameMsg c.config$n.info & " " & $n.kind
@@ -2980,25 +3193,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
if nfSem in n.flags: return
case n.kind
of nkIdent, nkAccQuoted:
var s: PSym
if expectedType != nil and (
let expected = expectedType.skipTypes(abstractRange-{tyDistinct});
expected.kind == tyEnum):
let nameId = considerQuotedIdent(c, n).id
for f in expected.n:
if f.kind == nkSym and f.sym.name.id == nameId:
s = f.sym
break
let s = resolveIdentToSym(c, n, result, flags, expectedType)
if s == nil:
let checks = if efNoEvaluateGeneric in flags:
{checkUndeclared, checkPureEnumFields}
elif efInCall in flags:
{checkUndeclared, checkModule, checkPureEnumFields}
else:
{checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields}
s = qualifiedLookUp(c, n, checks)
if s == nil:
return
# resolveIdentToSym either errored or gave a result node
return
if c.matchedConcept == nil: semCaptureSym(s, c.p.owner)
case s.kind
of skProc, skFunc, skMethod, skConverter, skIterator:
@@ -3012,23 +3210,35 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
if optOwnedRefs in c.config.globalOptions:
result.typ = makeVarType(c, result.typ, tyOwned)
of skEnumField:
result = enumFieldSymChoice(c, n, s)
result = enumFieldSymChoice(c, n, s, flags)
else:
result = semSym(c, n, s, flags)
if expectedType != nil and isSymChoice(result):
result = fitNode(c, expectedType, result, n.info)
if result.kind == nkSym:
result = semSym(c, result, result.sym, flags)
if isSymChoice(result):
result = semSymChoice(c, result, flags, expectedType)
of nkClosedSymChoice, nkOpenSymChoice:
result = semSymChoice(c, n, flags, expectedType)
of nkSym:
let s = n.sym
if nfDisabledOpenSym in n.flags:
let override = genericsOpenSym in c.features
let res = semOpenSym(c, n, flags, expectedType,
warnDisabled = not override)
if res != nil:
assert override
return res
# because of the changed symbol binding, this does not mean that we
# don't have to check the symbol for semantics here again!
result = semSym(c, n, n.sym, flags)
result = semSym(c, n, s, flags)
of nkOpenSym:
assert n.len == 1
let inner = n[0]
result = semOpenSym(c, inner, flags, expectedType)
of nkEmpty, nkNone, nkCommentStmt, nkType:
discard
of nkNilLit:
if result.typ == nil:
result.typ = getNilType(c)
if expectedType != nil:
if expectedType != nil and expectedType.kind notin {tyUntyped, tyTyped}:
var m = newCandidate(c, result.typ)
if typeRel(m, expectedType, result.typ) >= isSubtype:
result.typ = expectedType
@@ -3040,7 +3250,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
expected.kind in {tyInt..tyInt64,
tyUInt..tyUInt64,
tyFloat..tyFloat128}):
result.typ = expected
if expected.kind in {tyFloat..tyFloat128}:
n.transitionIntToFloatKind(nkFloatLit)
changeType(c, result, expectedType, check=true)
@@ -3112,7 +3321,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
# XXX think about this more (``set`` procs)
let ambig = c.isAmbiguous
if not (n[0].kind in {nkClosedSymChoice, nkOpenSymChoice, nkIdent} and ambig) and n.len == 2:
result = semConv(c, n, expectedType)
result = semConv(c, n, flags, expectedType)
elif ambig and n.len == 1:
errorUseQualifier(c, n.info, s)
elif n.len == 1:
@@ -3198,8 +3407,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
of nkAddr:
result = n
checkSonsLen(n, 1, c.config)
result[0] = semAddrArg(c, n[0])
result.typ = makePtrType(c, result[0].typ)
result = semAddr(c, n[0])
of nkHiddenAddr, nkHiddenDeref:
checkSonsLen(n, 1, c.config)
n[0] = semExpr(c, n[0], flags, expectedType)
@@ -3219,10 +3427,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
considerGenSyms(c, n)
of nkTableConstr:
result = semTableConstr(c, n, expectedType)
of nkClosedSymChoice, nkOpenSymChoice:
# handling of sym choices is context dependent
# the node is left intact for now
discard
of nkStaticExpr: result = semStaticExpr(c, n[0], expectedType)
of nkAsgn, nkFastAsgn: result = semAsgn(c, n)
of nkBlockStmt, nkBlockExpr: result = semBlock(c, n, flags, expectedType)

View File

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

View File

@@ -230,7 +230,13 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n, g)
of mDivF64:
result = newFloatNodeT(getFloat(a) / getFloat(b), n, g)
of mIsNil: result = newIntNodeT(toInt128(ord(a.kind == nkNilLit)), n, idgen, g)
of mIsNil:
let val = a.kind == nkNilLit or
# nil closures have the value (nil, nil)
(a.typ != nil and skipTypes(a.typ, abstractRange).kind == tyProc and
a.kind == nkTupleConstr and a.len == 2 and
a[0].kind == nkNilLit and a[1].kind == nkNilLit)
result = newIntNodeT(toInt128(ord(val)), n, idgen, g)
of mLtI, mLtB, mLtEnum, mLtCh:
result = newIntNodeT(toInt128(ord(getOrdValue(a) < getOrdValue(b))), n, idgen, g)
of mLeI, mLeB, mLeEnum, mLeCh:
@@ -403,14 +409,17 @@ proc foldConv(n, a: PNode; idgen: IdGenerator; g: ModuleGraph; check = false): P
result = newIntNodeT(toInt128(getFloat(a)), n, idgen, g)
of tyChar, tyUInt..tyUInt64, tyInt..tyInt64:
var val = a.getOrdValue
if check: rangeCheck(n, val, g)
result = newIntNodeT(val, n, idgen, g)
if dstTyp.kind in {tyUInt..tyUInt64}:
result = newIntNodeT(maskBytes(val, int getSize(g.config, dstTyp)), n, idgen, g)
result.transitionIntKind(nkUIntLit)
else:
if check: rangeCheck(n, val, g)
result = newIntNodeT(val, n, idgen, g)
else:
result = a
result.typ = n.typ
if check and result.kind in {nkCharLit..nkUInt64Lit}:
if check and result.kind in {nkCharLit..nkUInt64Lit} and
dstTyp.kind notin {tyUInt..tyUInt64}:
rangeCheck(n, getInt(result), g)
of tyFloat..tyFloat64:
case srcTyp.kind
@@ -679,10 +688,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
except DivByZeroDefect:
localError(g.config, n.info, "division by zero")
of nkAddr:
var a = getConstExpr(m, n[0], idgen, g)
if a != nil:
result = n
n[0] = a
result = nil # don't fold paths containing nkAddr
of nkBracket, nkCurly:
result = copyNode(n)
for son in n.items:
@@ -728,6 +734,8 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
if leValueConv(n[1], a) and leValueConv(a, n[2]):
result = a # a <= x and x <= b
result.typ = n.typ
elif n.typ.kind in {tyUInt..tyUInt64}:
discard "don't check uints"
else:
localError(g.config, n.info,
"conversion from $1 to $2 is invalid" %
@@ -749,7 +757,8 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
of nkCast:
var a = getConstExpr(m, n[1], idgen, g)
if a == nil: return
if n.typ != nil and n.typ.kind in NilableTypes:
if n.typ != nil and n.typ.kind in NilableTypes and
not (n.typ.kind == tyProc and a.typ.kind == tyProc):
# we allow compile-time 'cast' for pointer types:
result = a
result.typ = n.typ

View File

@@ -56,6 +56,9 @@ template isMixedIn(sym): bool =
s.magic == mNone and
s.kind in OverloadableSyms)
template canOpenSym(s): bool =
{withinMixin, withinConcept} * flags == {withinMixin} and s.id notin ctx.toBind
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
ctx: var GenericCtx; flags: TSemGenericFlags,
fromDotExpr=false): PNode =
@@ -68,6 +71,15 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result.transitionSonsKind(nkClosedSymChoice)
else:
result = symChoice(c, n, s, scOpen)
if canOpenSym(s):
if openSym in c.features:
if result.kind == nkSym:
result = newOpenSym(result)
else:
result.typ = nil
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
case s.kind
of skUnknown:
# Introduced in this pass! Leave it as an identifier.
@@ -95,6 +107,12 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
result = n
else:
result = newSymNodeTypeDesc(s, c.idgen, n.info)
if canOpenSym(result.sym):
if openSym in c.features:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
onUse(n.info, s)
of skParam:
result = n
@@ -103,11 +121,23 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
if (s.typ != nil) and
(s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
result = newSymNodeTypeDesc(s, c.idgen, n.info)
if canOpenSym(result.sym):
if openSym in c.features:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
else:
result = n
onUse(n.info, s)
else:
result = newSymNode(s, n.info)
if canOpenSym(result.sym):
if openSym in c.features:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
onUse(n.info, s)
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
@@ -147,6 +177,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
var s = qualifiedLookUp(c, n, luf)
if s != nil:
isMacro = s.kind in {skTemplate, skMacro}
result = semGenericStmtSymbol(c, n, s, ctx, flags)
else:
n[0] = semGenericStmt(c, n[0], flags, ctx)
@@ -167,6 +198,17 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
elif s.isMixedIn:
result = newDot(result, symChoice(c, n, s, scForceOpen))
else:
if s.kind == skType and candidates.len > 1:
var ambig = false
let s2 = searchInScopes(c, ident, ambig)
if ambig:
# this is a type conversion like a.T where T is ambiguous with
# other types or routines
# in regular code, this never considers a type conversion and
# skips to routine overloading
# so symchoices are used which behave similarly with type symbols
result = newDot(result, symChoice(c, n, s, scForceOpen))
return
let syms = semGenericStmtSymbol(c, n, s, ctx, flags, fromDotExpr=true)
result = newDot(result, syms)
@@ -176,6 +218,18 @@ proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
styleCheckDef(c, n.info, s, kind)
onDef(n.info, s)
proc addTempDeclToIdents(c: PContext; n: PNode; kind: TSymKind; inCall: bool) =
case n.kind
of nkIdent:
if inCall:
addTempDecl(c, n, kind)
of nkCallKinds:
for s in n:
addTempDeclToIdents(c, s, kind, true)
else:
for s in n:
addTempDeclToIdents(c, s, kind, inCall)
proc semGenericStmt(c: PContext, n: PNode,
flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
result = n
@@ -197,7 +251,7 @@ proc semGenericStmt(c: PContext, n: PNode,
#var s = qualifiedLookUp(c, n, luf)
#if s != nil: result = semGenericStmtSymbol(c, n, s)
# XXX for example: ``result.add`` -- ``add`` needs to be looked up here...
var dummy: bool
var dummy: bool = false
result = fuzzyLookup(c, n, flags, ctx, dummy)
of nkSym:
let a = n.sym
@@ -348,7 +402,9 @@ proc semGenericStmt(c: PContext, n: PNode,
var a = n[i]
checkMinSonsLen(a, 1, c.config)
for j in 0..<a.len-1:
a[j] = semGenericStmt(c, a[j], flags, ctx)
a[j] = semGenericStmt(c, a[j], flags+{withinMixin}, ctx)
addTempDeclToIdents(c, a[j], skVar, false)
a[^1] = semGenericStmtScope(c, a[^1], flags, ctx)
closeScope(c)
of nkForStmt, nkParForStmt:
@@ -445,8 +501,47 @@ proc semGenericStmt(c: PContext, n: PNode,
of nkIdent: a = n[i]
else: illFormedAst(n, c.config)
addDecl(c, newSymS(skUnknown, getIdentNode(c, a), c))
of nkObjectTy, nkTupleTy, nkTupleClassTy:
discard
of nkTupleTy:
for i in 0..<n.len:
var a = n[i]
case a.kind:
of nkCommentStmt, nkNilLit, nkSym, nkEmpty: continue
of nkIdentDefs:
checkMinSonsLen(a, 3, c.config)
a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx)
a[^1] = semGenericStmt(c, a[^1], flags, ctx)
for j in 0..<a.len-2:
addTempDecl(c, getIdentNode(c, a[j]), skField)
else:
illFormedAst(a, c.config)
of nkObjectTy:
if n.len > 0:
openScope(c)
for i in 0..<n.len:
result[i] = semGenericStmt(c, n[i], flags, ctx)
closeScope(c)
of nkRecList:
for i in 0..<n.len:
var a = n[i]
case a.kind:
of nkCommentStmt, nkNilLit, nkSym, nkEmpty: continue
of nkIdentDefs:
checkMinSonsLen(a, 3, c.config)
a[^2] = semGenericStmt(c, a[^2], flags+{withinTypeDesc}, ctx)
a[^1] = semGenericStmt(c, a[^1], flags, ctx)
for j in 0..<a.len-2:
addTempDecl(c, getIdentNode(c, a[j]), skField)
of nkRecCase, nkRecWhen:
n[i] = semGenericStmt(c, a, flags, ctx)
else:
illFormedAst(a, c.config)
of nkRecCase:
checkSonsLen(n[0], 3, c.config)
n[0][^2] = semGenericStmt(c, n[0][^2], flags+{withinTypeDesc}, ctx)
n[0][^1] = semGenericStmt(c, n[0][^1], flags, ctx)
addTempDecl(c, getIdentNode(c, n[0][0]), skField)
for i in 1..<n.len:
n[i] = semGenericStmt(c, n[i], flags, ctx)
of nkFormalParams:
checkMinSonsLen(n, 1, c.config)
for i in 1..<n.len:
@@ -482,7 +577,8 @@ proc semGenericStmt(c: PContext, n: PNode,
else:
body = getBody(c.graph, s)
else: body = n[bodyPos]
n[bodyPos] = semGenericStmtScope(c, body, flags, ctx)
let bodyFlags = if n.kind == nkTemplateDef: flags + {withinMixin} else: flags
n[bodyPos] = semGenericStmtScope(c, body, bodyFlags, ctx)
closeScope(c)
of nkPragma, nkPragmaExpr: discard
of nkExprColonExpr, nkExprEqExpr:

View File

@@ -60,6 +60,15 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym
elif t.kind in {tyGenericParam, tyConcept}:
localError(c.config, a.info, errCannotInstantiateX % q.name.s)
t = errorType(c)
elif isUnresolvedStatic(t) and (q.typ.kind == tyStatic or
(q.typ.kind == tyGenericParam and
q.typ.sons.len > 0 and
q.typ.sons[0].kind == tyStatic)) and
c.inGenericContext == 0 and c.matchedConcept == nil:
# generic/concept type bodies will try to instantiate static values but
# won't actually use them
localError(c.config, a.info, errCannotInstantiateX % q.name.s)
t = errorType(c)
elif t.kind == tyGenericInvocation:
#t = instGenericContainer(c, a, t)
t = generateTypeInstance(c, pt, a, t)
@@ -272,11 +281,13 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
# call head symbol, because this leads to infinite recursion.
if oldParam.ast != nil:
var def = oldParam.ast.copyTree
if def.kind == nkCall:
if def.kind in nkCallKinds:
for i in 1..<def.len:
def[i] = replaceTypeVarsN(cl, def[i])
def[i] = replaceTypeVarsN(cl, def[i], 1)
def = semExprWithType(c, def)
# allow symchoice since node will be fit later
# although expectedType should cover it
def = semExprWithType(c, def, {efAllowSymChoice}, typeToFit)
if def.referencesAnotherParam(getCurrOwner(c)):
def.flags.incl nfDefaultRefsParam
@@ -330,7 +341,12 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
# generates an instantiated proc
if c.instCounter > 50:
globalError(c.config, info, "generic instantiation too nested")
inc(c.instCounter)
inc c.instCounter
let currentTypeofContext = c.inTypeofContext
c.inTypeofContext = 0
defer:
dec c.instCounter
c.inTypeofContext = currentTypeofContext
# careful! we copy the whole AST including the possibly nil body!
var n = copyTree(fn.ast)
# NOTE: for access of private fields within generics from a different module
@@ -364,15 +380,19 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
# see ttypeor.nim test.
var i = 0
newSeq(entry.concreteTypes, fn.typ.len+gp.len-1)
# let param instantiation know we are in a concept for unresolved statics:
c.matchedConcept = oldMatchedConcept
for s in instantiateGenericParamList(c, gp, pt):
addDecl(c, s)
entry.concreteTypes[i] = s.typ
inc i
c.matchedConcept = nil
pushProcCon(c, result)
instantiateProcType(c, pt, result, info)
for j in 1..<result.typ.len:
entry.concreteTypes[i] = result.typ[j]
inc i
#echo "INSTAN ", fn.name.s, " ", typeToString(result.typ), " ", entry.concreteTypes.len
if tfTriggersCompileTime in result.typ.flags:
incl(result.flags, sfCompileTime)
n[genericParamsPos] = c.graph.emptyNode
@@ -395,7 +415,9 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
if result.magic notin {mSlice, mTypeOf}:
# 'toOpenArray' is special and it is allowed to return 'openArray':
paramsTypeCheck(c, result.typ)
#echo "INSTAN ", fn.name.s, " ", typeToString(result.typ), " <-- NEW PROC!", " ", entry.concreteTypes.len
else:
#echo "INSTAN ", fn.name.s, " ", typeToString(result.typ), " <-- CACHED! ", typeToString(oldPrc.typ), " ", entry.concreteTypes.len
result = oldPrc
popProcCon(c)
popInfoContext(c.config)
@@ -404,7 +426,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
popOwner(c)
c.currentScope = oldScope
discard c.friendModules.pop()
dec(c.instCounter)
c.matchedConcept = oldMatchedConcept
if result.kind == skMethod: finishMethod(c, result)

View File

@@ -51,6 +51,7 @@ proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
of nkObjConstr:
let x = t.skipTypes(abstractPtrs)
n.typ = t
n[0].typ = t
for i in 1..<n.len:
var j = i-1
let field = x.ithField(j)

View File

@@ -30,13 +30,15 @@ proc addDefaultFieldForNew(c: PContext, n: PNode): PNode =
if asgnExpr.sons.len > 1:
result = newTree(nkAsgn, result[1], asgnExpr)
proc semAddrArg(c: PContext; n: PNode): PNode =
proc semAddr(c: PContext; n: PNode): PNode =
result = newNodeI(nkAddr, n.info)
let x = semExprWithType(c, n)
if x.kind == nkSym:
x.sym.flags.incl(sfAddrTaken)
if isAssignable(c, x) notin {arLValue, arLocalLValue, arAddressableConst, arLentValue}:
localError(c.config, n.info, errExprHasNoAddress)
result = x
result.add x
result.typ = makePtrType(c, x.typ)
proc semTypeOf(c: PContext; n: PNode): PNode =
var m = BiggestInt 1 # typeOfIter
@@ -47,6 +49,8 @@ proc semTypeOf(c: PContext; n: PNode): PNode =
else:
m = mode.intVal
result = newNodeI(nkTypeOfExpr, n.info)
inc c.inTypeofContext
defer: dec c.inTypeofContext # compiles can raise an exception
let typExpr = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
result.add typExpr
result.typ = makeTypeDesc(c, typExpr.typ)
@@ -66,7 +70,7 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
x[0] = newIdentNode(getIdent(c.cache, "[]"), n.info)
bracketNotFoundError(c, x)
#localError(c.config, n.info, "could not resolve: " & $n)
result = n
result = errorNode(c, n)
proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode =
# rewrite `[]=`(a, i, x) back to ``a[i] = x``.
@@ -519,7 +523,9 @@ proc semNewFinalize(c: PContext; n: PNode): PNode =
selfPtr.add transFormedSym.ast[bodyPos][1]
selfPtr.typ = selfSymbolType
transFormedSym.ast[bodyPos][1] = c.semExpr(c, selfPtr)
bindTypeHook(c, transFormedSym, n, attachedDestructor)
# TODO: suppress var destructor warnings; if newFinalizer is not
# TODO: deprecated, try to implement plain T destructor
bindTypeHook(c, transFormedSym, n, attachedDestructor, suppressVarDestructorWarning = true)
result = addDefaultFieldForNew(c, n)
proc semPrivateAccess(c: PContext, n: PNode): PNode =
@@ -547,9 +553,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
case n[0].sym.magic
of mAddr:
checkSonsLen(n, 2, c.config)
result = n
result[1] = semAddrArg(c, n[1])
result.typ = makePtrType(c, result[1].typ)
result = semAddr(c, n[1])
of mTypeOf:
result = semTypeOf(c, n)
of mSizeOf:
@@ -668,7 +672,8 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
result.typ = expectedType # type inference for empty sequence # bug #21377
of mEnsureMove:
result = n
if isAssignable(c, n[1]) notin {arLValue, arLocalLValue}:
localError(c.config, n.info, "'" & $n[1] & "'" & " is not a mutable location; it cannot be moved")
if n[1].kind in {nkStmtListExpr, nkBlockExpr,
nkIfExpr, nkCaseStmt, nkTryStmt}:
localError(c.config, n.info, "Nested expressions cannot be moved: '" & $n[1] & "'")
else:
result = n

View File

@@ -91,7 +91,9 @@ proc semConstrField(c: PContext, flags: TExprFlags,
assignment[0] = newSymNode(field)
assignment[1] = initValue
assignment.flags.incl nfSem
return initValue
result = initValue
else:
result = nil
proc branchVals(c: PContext, caseNode: PNode, caseIdx: int,
isStmtBranch: bool): IntSet =
@@ -184,6 +186,23 @@ proc collectOrAddMissingCaseFields(c: PContext, branchNode: PNode,
asgnExpr.typ = recTyp
defaults.add newTree(nkExprColonExpr, newSymNode(sym), asgnExpr)
proc collectBranchFields(c: PContext, n: PNode, discriminatorVal: PNode,
constrCtx: var ObjConstrContext, flags: TExprFlags) =
# All bets are off. If any of the branches has a mandatory
# fields we must produce an error:
for i in 1..<n.len:
let branchNode = n[i]
if branchNode != nil:
let oldCheckDefault = constrCtx.checkDefault
constrCtx.checkDefault = true
let (_, defaults) = semConstructFields(c, branchNode[^1], constrCtx, flags)
constrCtx.checkDefault = oldCheckDefault
if len(defaults) > 0:
localError(c.config, discriminatorVal.info, "branch initialization " &
"with a runtime discriminator is not supported " &
"for a branch whose fields have default values.")
discard collectMissingCaseFields(c, n[i], constrCtx, @[])
proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
flags: TExprFlags): tuple[status: InitStatus, defaults: seq[PNode]] =
case n.kind
@@ -322,13 +341,27 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
discriminator.sym,
constrCtx.initExpr)
if discriminatorVal == nil:
# None of the branches were explicitly selected by the user and no
# value was given to the discrimator. We can assume that it will be
# initialized to zero and this will select a particular branch as
# a result:
let defaultValue = newIntLit(c.graph, constrCtx.initExpr.info, 0)
let matchedBranch = n.pickCaseBranch defaultValue
discard collectMissingCaseFields(c, matchedBranch, constrCtx, @[])
if discriminator.sym.ast != nil:
# branch is selected by the default field value of discriminator
let discriminatorDefaultVal = discriminator.sym.ast
result.status = initUnknown
result.defaults.add newTree(nkExprColonExpr, n[0], discriminatorDefaultVal)
if discriminatorDefaultVal.kind == nkIntLit:
let matchedBranch = n.pickCaseBranch discriminatorDefaultVal
if matchedBranch != nil:
let (_, defaults) = semConstructFields(c, matchedBranch[^1], constrCtx, flags)
result.defaults.add defaults
collectOrAddMissingCaseFields(c, matchedBranch, constrCtx, result.defaults)
else:
collectBranchFields(c, n, discriminatorDefaultVal, constrCtx, flags)
else:
# None of the branches were explicitly selected by the user and no
# value was given to the discrimator. We can assume that it will be
# initialized to zero and this will select a particular branch as
# a result:
let defaultValue = newIntLit(c.graph, constrCtx.initExpr.info, 0)
let matchedBranch = n.pickCaseBranch defaultValue
discard collectMissingCaseFields(c, matchedBranch, constrCtx, @[])
else:
result.status = initPartial
if discriminatorVal.kind == nkIntLit:
@@ -340,20 +373,8 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
result.defaults.add defaults
collectOrAddMissingCaseFields(c, matchedBranch, constrCtx, result.defaults)
else:
# All bets are off. If any of the branches has a mandatory
# fields we must produce an error:
for i in 1..<n.len:
let branchNode = n[i]
if branchNode != nil:
let oldCheckDefault = constrCtx.checkDefault
constrCtx.checkDefault = true
let (_, defaults) = semConstructFields(c, branchNode[^1], constrCtx, flags)
constrCtx.checkDefault = oldCheckDefault
if len(defaults) > 0:
localError(c.config, discriminatorVal.info, "branch initialization " &
"with a runtime discriminator is not supported " &
"for a branch whose fields have default values.")
discard collectMissingCaseFields(c, n[i], constrCtx, @[])
collectBranchFields(c, n, discriminatorVal, constrCtx, flags)
of nkSym:
let field = n.sym
let e = semConstrField(c, flags, field, constrCtx.initExpr)
@@ -451,7 +472,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
result.typ.flags.incl tfHasOwned
if t.kind != tyObject:
return localErrorNode(c, result, if t.kind != tyGenericBody:
"object constructor needs an object type".dup(addDeclaredLoc(c.config, t))
"object constructor needs an object type".dup(addTypeNodeDeclaredLoc(c.config, t))
else: "cannot instantiate: '" &
typeToString(t, preferDesc) &
"'; the object's generic parameters cannot be inferred and must be explicitly given"

View File

@@ -11,7 +11,7 @@ import
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
wordrecg, strutils, options, guards, lineinfos, semfold, semdata,
modulegraphs, varpartitions, typeallowed, nilcheck, errorhandling, tables,
semstrictfuncs
semstrictfuncs, lowerings
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -89,10 +89,11 @@ const
errXCannotBeAssignedTo = "'$1' cannot be assigned to"
errLetNeedsInit = "'let' symbol requires an initialization"
proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) =
if typ == nil or sfGeneratedOp in tracked.owner.flags:
proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo; explicit = false) =
if typ == nil or (sfGeneratedOp in tracked.owner.flags and not explicit):
# don't create type bound ops for anything in a function with a `nodestroy` pragma
# bug #21987
# unless this is an explicit call, bug #24626
return
when false:
let realType = typ.skipTypes(abstractInst)
@@ -177,6 +178,7 @@ proc varDecl(a: PEffects; n: PNode) {.inline.} =
proc skipHiddenDeref(n: PNode): PNode {.inline.} =
result = if n.kind == nkHiddenDeref: n[0] else: n
proc initVar(a: PEffects, n: PNode; volatileCheck: bool) =
let n = skipHiddenDeref(n)
if n.kind != nkSym: return
@@ -356,12 +358,15 @@ proc useVar(a: PEffects, n: PNode) =
type
TIntersection = seq[tuple[id, count: int]] # a simple count table
proc addToIntersection(inter: var TIntersection, s: int) =
proc addToIntersection(inter: var TIntersection, s: int, zeroInit: bool) =
for j in 0..<inter.len:
if s == inter[j].id:
inc inter[j].count
return
inter.add((id: s, count: 1))
if zeroInit:
inter.add((id: s, count: 0))
else:
inter.add((id: s, count: 1))
proc throws(tracked, n, orig: PNode) =
if n.typ == nil or n.typ.kind != tyError:
@@ -465,7 +470,7 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
track(tracked, n[0])
dec tracked.inTryStmt
for i in oldState..<tracked.init.len:
addToIntersection(inter, tracked.init[i])
addToIntersection(inter, tracked.init[i], false)
var branches = 1
var hasFinally = false
@@ -500,7 +505,7 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
tracked.init.add b[j][2].sym.id
track(tracked, b[^1])
for i in oldState..<tracked.init.len:
addToIntersection(inter, tracked.init[i])
addToIntersection(inter, tracked.init[i], false)
else:
setLen(tracked.init, oldState)
track(tracked, b[^1])
@@ -578,7 +583,7 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
if paramType != nil and tfNotNil in paramType.flags and n.typ != nil:
let ntyp = n.typ.skipTypesOrNil({tyVar, tyLent, tySink})
if ntyp != nil and tfNotNil notin ntyp.flags:
if isAddrNode(n):
if n.kind in {nkAddr, nkHiddenAddr}:
# addr(x[]) can't be proven, but addr(x) can:
if not containsNode(n, {nkDerefExpr, nkHiddenDeref}): return
elif (n.kind == nkSym and n.sym.kind in routineKinds) or
@@ -696,9 +701,11 @@ proc trackCase(tracked: PEffects, n: PNode) =
addCaseBranchFacts(tracked.guards, n, i)
for i in 0..<branch.len:
track(tracked, branch[i])
if not breaksBlock(branch.lastSon): inc toCover
let hasBreaksBlock = breaksBlock(branch.lastSon)
if not hasBreaksBlock:
inc toCover
for i in oldState..<tracked.init.len:
addToIntersection(inter, tracked.init[i])
addToIntersection(inter, tracked.init[i], hasBreaksBlock)
setLen(tracked.init, oldState)
if not stringCase or lastSon(n).kind == nkElse:
@@ -718,9 +725,11 @@ proc trackIf(tracked: PEffects, n: PNode) =
var inter: TIntersection = @[]
var toCover = 0
track(tracked, n[0][1])
if not breaksBlock(n[0][1]): inc toCover
let hasBreaksBlock = breaksBlock(n[0][1])
if not hasBreaksBlock:
inc toCover
for i in oldState..<tracked.init.len:
addToIntersection(inter, tracked.init[i])
addToIntersection(inter, tracked.init[i], hasBreaksBlock)
for i in 1..<n.len:
let branch = n[i]
@@ -732,9 +741,12 @@ proc trackIf(tracked: PEffects, n: PNode) =
setLen(tracked.init, oldState)
for i in 0..<branch.len:
track(tracked, branch[i])
if not breaksBlock(branch.lastSon): inc toCover
let hasBreaksBlock = breaksBlock(branch.lastSon)
if not hasBreaksBlock:
inc toCover
for i in oldState..<tracked.init.len:
addToIntersection(inter, tracked.init[i])
addToIntersection(inter, tracked.init[i], hasBreaksBlock)
setLen(tracked.init, oldState)
if lastSon(n).len == 1:
for id, count in items(inter):
@@ -878,7 +890,7 @@ proc trackCall(tracked: PEffects; n: PNode) =
mergeRaises(tracked, effectList[exceptionEffects], n)
mergeTags(tracked, effectList[tagEffects], n)
gcsafeAndSideeffectCheck()
if a.kind != nkSym or a.sym.magic notin {mNBindSym, mFinished, mExpandToAst, mQuoteAst}:
if a.kind != nkSym or a.sym.magic notin {mNBindSym, mFinished, mExpandToAst, mQuoteAst, mType}:
for i in 1..<n.len:
trackOperandForIndirectCall(tracked, n[i], op, i, a)
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
@@ -915,10 +927,17 @@ proc trackCall(tracked: PEffects; n: PNode) =
# rebind type bounds operations after createTypeBoundOps call
let t = n[1].typ.skipTypes({tyAlias, tyVar})
if a.sym != getAttachedOp(tracked.graph, t, TTypeAttachedOp(opKind)):
createTypeBoundOps(tracked, t, n.info)
createTypeBoundOps(tracked, t, n.info, explicit = true)
let op = getAttachedOp(tracked.graph, t, TTypeAttachedOp(opKind))
if op != nil:
n[0].sym = op
if TTypeAttachedOp(opKind) == attachedDestructor and
op.typ.len == 2 and op.typ.firstParamType.kind != tyVar:
if n[1].kind == nkSym and n[1].sym.kind == skParam and
n[1].typ.kind == tyVar:
n[1] = genDeref(n[1])
else:
n[1] = skipAddr(n[1])
if op != nil and op.kind == tyProc:
for i in 1..<min(n.safeLen, op.len):
@@ -1047,7 +1066,7 @@ proc track(tracked: PEffects, n: PNode) =
if n.sym.typ != nil and tfHasAsgn in n.sym.typ.flags:
tracked.owner.flags.incl sfInjectDestructors
# bug #15038: ensure consistency
if not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ): n.typ = n.sym.typ
if n.typ == nil or (not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ)): n.typ = n.sym.typ
of nkHiddenAddr, nkAddr:
if n[0].kind == nkSym and isLocalSym(tracked, n[0].sym):
useVarNoInitCheck(tracked, n[0], n[0].sym)
@@ -1134,7 +1153,12 @@ proc track(tracked: PEffects, n: PNode) =
let last = lastSon(child)
track(tracked, last)
of nkCaseStmt: trackCase(tracked, n)
of nkWhen, nkIfStmt, nkIfExpr: trackIf(tracked, n)
of nkWhen: # This should be a "when nimvm" node.
let oldState = tracked.init.len
track(tracked, n[0][1])
tracked.init.setLen(oldState)
track(tracked, n[1][0])
of nkIfStmt, nkIfExpr: trackIf(tracked, n)
of nkBlockStmt, nkBlockExpr: trackBlock(tracked, n[1])
of nkWhileStmt:
# 'while true' loop?
@@ -1319,6 +1343,7 @@ proc track(tracked: PEffects, n: PNode) =
proc subtypeRelation(g: ModuleGraph; spec, real: PNode): bool =
if spec.typ.kind == tyOr:
result = false
for t in spec.typ.sons:
if safeInheritanceDiff(g.excType(real), t) <= 0:
return true

View File

@@ -129,17 +129,141 @@ proc semExprBranchScope(c: PContext, n: PNode; expectedType: PType = nil): PNode
closeScope(c)
const
skipForDiscardable = {nkIfStmt, nkIfExpr, nkCaseStmt, nkOfBranch,
nkElse, nkStmtListExpr, nkTryStmt, nkFinally, nkExceptBranch,
skipForDiscardable = {nkStmtList, nkStmtListExpr,
nkOfBranch, nkElse, nkFinally, nkExceptBranch,
nkElifBranch, nkElifExpr, nkElseExpr, nkBlockStmt, nkBlockExpr,
nkHiddenStdConv, nkHiddenDeref}
nkHiddenStdConv, nkHiddenSubConv, nkHiddenDeref}
proc implicitlyDiscardable(n: PNode): bool =
var n = n
while n.kind in skipForDiscardable: n = n.lastSon
result = n.kind in nkLastBlockStmts or
(isCallExpr(n) and n[0].kind == nkSym and
sfDiscardable in n[0].sym.flags)
# same traversal as endsInNoReturn
template checkBranch(branch) =
if not implicitlyDiscardable(branch):
return false
var it = n
# skip these beforehand, no special handling needed
while it.kind in skipForDiscardable and it.len > 0:
it = it.lastSon
case it.kind
of nkIfExpr, nkIfStmt:
for branch in it:
checkBranch:
if branch.len == 2:
branch[1]
elif branch.len == 1:
branch[0]
else:
raiseAssert "Malformed `if` statement during implicitlyDiscardable"
# all branches are discardable
result = true
of nkCaseStmt:
for i in 1 ..< it.len:
let branch = it[i]
checkBranch:
case branch.kind
of nkOfBranch:
branch[^1]
of nkElifBranch:
branch[1]
of nkElse:
branch[0]
else:
raiseAssert "Malformed `case` statement in endsInNoReturn"
# all branches are discardable
result = true
of nkTryStmt:
checkBranch(it[0])
for i in 1 ..< it.len:
let branch = it[i]
if branch.kind != nkFinally:
checkBranch(branch[^1])
# all branches are discardable
result = true
of nkCallKinds:
result = it[0].kind == nkSym and {sfDiscardable, sfNoReturn} * it[0].sym.flags != {}
of nkLastBlockStmts:
result = true
else:
result = false
proc endsInNoReturn(n: PNode, returningNode: var PNode; discardableCheck = false): bool =
## check if expr ends the block like raising or call of noreturn procs do
result = false # assume it does return
template checkBranch(branch) =
if not endsInNoReturn(branch, returningNode, discardableCheck):
# proved a branch returns
return false
var it = n
# skip these beforehand, no special handling needed
let skips = if discardableCheck: skipForDiscardable else: skipForDiscardable-{nkBlockExpr, nkBlockStmt}
while it.kind in skips and it.len > 0:
it = it.lastSon
case it.kind
of nkIfExpr, nkIfStmt:
var hasElse = false
for branch in it:
checkBranch:
if branch.len == 2:
branch[1]
elif branch.len == 1:
hasElse = true
branch[0]
else:
raiseAssert "Malformed `if` statement during endsInNoReturn"
# none of the branches returned
result = hasElse # Only truly a no-return when it's exhaustive
of nkCaseStmt:
let caseTyp = skipTypes(it[0].typ, abstractVar-{tyTypeDesc})
# semCase should already have checked for exhaustiveness in this case
# effectively the same as having an else
var hasElse = caseTyp.shouldCheckCaseCovered()
# actual noreturn checks
for i in 1 ..< it.len:
let branch = it[i]
checkBranch:
case branch.kind
of nkOfBranch:
branch[^1]
of nkElifBranch:
branch[1]
of nkElse:
hasElse = true
branch[0]
else:
raiseAssert "Malformed `case` statement in endsInNoReturn"
# Can only guarantee a noreturn if there is an else or it's exhaustive
result = hasElse
of nkTryStmt:
checkBranch(it[0])
var lastIndex = it.len - 1
if it[lastIndex].kind == nkFinally:
# if finally is noreturn, then the entire statement is noreturn
if endsInNoReturn(it[lastIndex][^1], returningNode, discardableCheck):
return true
dec lastIndex
for i in 1 .. lastIndex:
let branch = it[i]
checkBranch(branch[^1])
# none of the branches returned
result = true
of nkLastBlockStmts:
result = true
of nkCallKinds:
result = it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
if not result:
returningNode = it
else:
result = false
returningNode = it
proc endsInNoReturn(n: PNode): bool =
var dummy: PNode = nil
result = endsInNoReturn(n, dummy)
proc fixNilType(c: PContext; n: PNode) =
if isAtom(n):
@@ -162,10 +286,11 @@ proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
localError(c.config, result.info, "expression has no type: " &
renderTree(result, {renderNoComments}))
else:
# Ignore noreturn procs since they don't have a type
var n = result
while n.kind in skipForDiscardable:
if n.kind == nkTryStmt: n = n[0]
else: n = n.lastSon
if result.endsInNoReturn(n, discardableCheck = true):
return
var s = "expression '" & $n & "' is of type '" &
result.typ.typeToString & "' and has to be used (or discarded)"
if result.info.line != n.info.line or
@@ -331,6 +456,8 @@ proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
result.typ = typ
if not floatRangeCheck(result.floatVal, typ):
localError(c.config, n.info, errFloatToString % [$result.floatVal, typeToString(typ)])
elif r1.kind == nkSym and typ.skipTypes(abstractRange).kind == tyCstring:
discard "keep nkHiddenStdConv for cstring conversions"
else:
changeType(c, r1, typ, check=true)
result = r1
@@ -350,7 +477,7 @@ proc identWithin(n: PNode, s: PIdent): bool =
proc semIdentDef(c: PContext, n: PNode, kind: TSymKind, reportToNimsuggest = true): PSym =
if isTopLevel(c):
result = semIdentWithPragma(c, kind, n, {sfExported})
result = semIdentWithPragma(c, kind, n, {sfExported}, fromTopLevel = true)
incl(result.flags, sfGlobal)
#if kind in {skVar, skLet}:
# echo "global variable here ", n.info, " ", result.name.s
@@ -590,14 +717,22 @@ proc globalVarInitCheck(c: PContext, n: PNode) =
if n.isLocalVarSym or n.kind in nkCallKinds and usesLocalVar(n):
localError(c.config, n.info, errCannotAssignToGlobal)
const
errTupleUnpackingTupleExpected = "tuple expected for tuple unpacking, but got '$1'"
errTupleUnpackingDifferentLengths = "tuple with $1 elements expected, but got '$2' with $3 elements"
proc makeVarTupleSection(c: PContext, n, a, def: PNode, typ: PType, symkind: TSymKind, origResult: var PNode): PNode =
## expand tuple unpacking assignments into new var/let/const section
##
## mirrored with semexprs.makeTupleAssignments
if typ.kind != tyTuple:
localError(c.config, a.info, errXExpected, "tuple")
localError(c.config, a.info, errTupleUnpackingTupleExpected %
[typeToString(typ, preferDesc)])
elif a.len-2 != typ.len:
localError(c.config, a.info, errWrongNumberOfVariables)
localError(c.config, a.info, errTupleUnpackingDifferentLengths %
[$(a.len-2), typeToString(typ, preferDesc), $typ.len])
var
tmpTuple: PSym
tempNode: PNode = nil
lastDef: PNode
let defkind = if symkind == skConst: nkConstDef else: nkIdentDefs
# temporary not needed if not const and RHS is tuple literal
@@ -605,17 +740,18 @@ proc makeVarTupleSection(c: PContext, n, a, def: PNode, typ: PType, symkind: TSy
let useTemp = def.kind notin {nkPar, nkTupleConstr} or symkind == skConst
if useTemp:
# use same symkind for compatibility with original section
tmpTuple = newSym(symkind, getIdent(c.cache, "tmpTuple"), c.idgen, getCurrOwner(c), n.info)
tmpTuple.typ = typ
tmpTuple.flags.incl(sfGenSym)
let temp = newSym(symkind, getIdent(c.cache, "tmpTuple"), c.idgen, getCurrOwner(c), n.info)
temp.typ = typ
temp.flags.incl(sfGenSym)
lastDef = newNodeI(defkind, a.info)
newSons(lastDef, 3)
lastDef[0] = newSymNode(tmpTuple)
lastDef[0] = newSymNode(temp)
# NOTE: at the moment this is always ast.emptyNode, see parser.nim
lastDef[1] = a[^2]
lastDef[2] = def
tmpTuple.ast = lastDef
temp.ast = lastDef
addToVarSection(c, origResult, n, lastDef)
tempNode = newSymNode(temp)
result = newNodeI(n.kind, a.info)
for j in 0..<a.len-2:
let name = a[j]
@@ -634,7 +770,7 @@ proc makeVarTupleSection(c: PContext, n, a, def: PNode, typ: PType, symkind: TSy
lastDef[0] = name
lastDef[^2] = c.graph.emptyNode
if useTemp:
lastDef[^1] = newTreeIT(nkBracketExpr, name.info, typ[j], newSymNode(tmpTuple), newIntNode(nkIntLit, j))
lastDef[^1] = newTupleAccessRaw(tempNode, j)
else:
var val = def[j]
if val.kind == nkExprColonExpr: val = val[1]
@@ -644,6 +780,24 @@ proc makeVarTupleSection(c: PContext, n, a, def: PNode, typ: PType, symkind: TSy
proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var b: PNode
result = copyNode(n)
# transform var x, y = 12 into var x = 12; var y = 12
# bug #18104; transformation should be finished before templates expansion
# TODO: move warnings for tuple here
var transformed = copyNode(n)
for i in 0..<n.len:
var a = n[i]
if a.kind == nkIdentDefs and a.len > 3 and a[^1].kind != nkEmpty:
for j in 0..<a.len-2:
var b = newNodeI(nkIdentDefs, a.info)
b.add a[j]
b.add a[^2]
b.add copyTree(a[^1])
transformed.add b
else:
transformed.add a
let n = transformed
for i in 0..<n.len:
var a = n[i]
if c.config.cmd == cmdIdeTools: suggestStmt(c, a)
@@ -656,9 +810,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
addToVarSection(c, result, b)
continue
var hasUserSpecifiedType = false
var typ: PType = nil
if a[^2].kind != nkEmpty:
typ = semTypeNode(c, a[^2], nil)
hasUserSpecifiedType = true
var typFlags: TTypeAllowedFlags
@@ -730,6 +886,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
addToVarSection(c, result, n, a)
continue
var v = semIdentDef(c, a[j], symkind, false)
when defined(nimsuggest):
v.hasUserSpecifiedType = hasUserSpecifiedType
styleCheckDef(c, v)
onDef(a[j].info, v)
if sfGenSym notin v.flags:
@@ -803,9 +961,11 @@ proc semConst(c: PContext, n: PNode): PNode =
addToVarSection(c, result, b)
continue
var hasUserSpecifiedType = false
var typ: PType = nil
if a[^2].kind != nkEmpty:
typ = semTypeNode(c, a[^2], nil)
hasUserSpecifiedType = true
var typFlags: TTypeAllowedFlags
@@ -846,14 +1006,20 @@ proc semConst(c: PContext, n: PNode): PNode =
else:
for j in 0..<a.len-2:
var v = semIdentDef(c, a[j], skConst)
when defined(nimsuggest):
v.hasUserSpecifiedType = hasUserSpecifiedType
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
elif v.owner == nil: v.owner = getCurrOwner(c)
styleCheckDef(c, v)
onDef(a[j].info, v)
setVarType(c, v, typ)
when false:
v.ast = def # no need to copy
var fillSymbol = true
if v.typ != nil:
# symbol already has type and probably value
# don't mutate
fillSymbol = false
else:
setVarType(c, v, typ)
b = newNodeI(nkConstDef, a.info)
if importantComments(c.config): b.comment = a.comment
# postfix not generated here (to generate, get rid of it in transf)
@@ -866,8 +1032,9 @@ proc semConst(c: PContext, n: PNode): PNode =
b.add newSymNode(v)
b.add a[1]
b.add copyTree(def)
v.ast = b
addToVarSection(c, result, n, b)
if fillSymbol:
v.ast = b
addToVarSection(c, result, n, b)
dec c.inStaticContext
include semfields
@@ -894,7 +1061,10 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
if iterAfterVarLent.kind != tyTuple or n.len == 3:
if n.len == 3:
if n[0].kind == nkVarTuple:
if n[0].len-1 != iterAfterVarLent.len:
if iterAfterVarLent.kind != tyTuple:
return localErrorNode(c, n, n[0].info, errTupleUnpackingTupleExpected %
[typeToString(n[1].typ, preferDesc)])
elif n[0].len-1 != iterAfterVarLent.len:
return localErrorNode(c, n, n[0].info, errWrongNumberOfVariables)
for i in 0..<n[0].len-1:
@@ -1007,7 +1177,7 @@ proc handleStmtMacro(c: PContext; n, selector: PNode; magicType: string;
if maType == nil: return
let headSymbol = selector[0]
var o: TOverloadIter
var o: TOverloadIter = default(TOverloadIter)
var match: PSym = nil
var symx = initOverloadIter(o, c, headSymbol)
while symx != nil:
@@ -1041,7 +1211,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode; flags: TExprFlags): PNode =
toResolve.add newIdentNode(getIdent(c.cache, "case"), n.info)
toResolve.add n[0]
var errors: CandidateErrors
var errors: CandidateErrors = @[]
var r = resolveOverloads(c, toResolve, toResolve, {skTemplate, skMacro}, {efNoDiagnostics},
errors, false)
if r.state == csMatch:
@@ -1113,20 +1283,14 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags; expectedType: PType = nil
openScope(c)
pushCaseContext(c, n)
n[0] = semExprWithType(c, n[0])
var chckCovered = false
var covered: Int128 = toInt128(0)
var typ = commonTypeBegin
var expectedType = expectedType
var hasElse = false
let caseTyp = skipTypes(n[0].typ, abstractVar-{tyTypeDesc})
const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt64, tyBool}
var chckCovered = caseTyp.shouldCheckCaseCovered()
case caseTyp.kind
of shouldChckCovered:
chckCovered = true
of tyRange:
if skipTypes(caseTyp[0], abstractInst).kind in shouldChckCovered:
chckCovered = true
of tyFloat..tyFloat128, tyString, tyCstring, tyError:
of tyFloat..tyFloat128, tyString, tyCstring, tyError, shouldChckCovered, tyRange:
discard
else:
popCaseContext(c)
@@ -1461,9 +1625,12 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
# final pass
if a[2].kind in nkCallKinds:
incl a[2].flags, nfSem # bug #10548
if sfExportc in s.flags and s.typ.kind == tyAlias:
localError(c.config, name.info, "{.exportc.} not allowed for type aliases")
if sfExportc in s.flags:
if s.typ.kind == tyAlias:
localError(c.config, name.info, "{.exportc.} not allowed for type aliases")
elif s.typ.kind == tyGenericBody:
localError(c.config, name.info, "{.exportc.} not allowed for generic types")
if tfBorrowDot in s.typ.flags:
let body = s.typ.skipTypes({tyGenericBody})
if body.kind != tyDistinct:
@@ -1509,21 +1676,27 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
for sk in c.skipTypes:
discard semTypeNode(c, sk, nil)
c.skipTypes = @[]
proc checkForMetaFields(c: PContext; n: PNode) =
proc checkMeta(c: PContext; n: PNode; t: PType) =
if t != nil and t.isMetaType and tfGenericTypeParam notin t.flags:
proc checkForMetaFields(c: PContext; n: PNode; hasError: var bool) =
proc checkMeta(c: PContext; n: PNode; t: PType; hasError: var bool; parent: PType) =
if t != nil and (t.isMetaType or t.kind == tyNone) and tfGenericTypeParam notin t.flags:
if t.kind == tyBuiltInTypeClass and t.len == 1 and t[0].kind == tyProc:
localError(c.config, n.info, ("'$1' is not a concrete type; " &
"for a callback without parameters use 'proc()'") % t.typeToString)
elif t.kind == tyNone and parent != nil:
# TODO: openarray has the `tfGenericTypeParam` flag & generics
# TODO: handle special cases (sink etc.) and views
localError(c.config, n.info, errTIsNotAConcreteType % parent.typeToString)
else:
localError(c.config, n.info, errTIsNotAConcreteType % t.typeToString)
hasError = true
if n.isNil: return
case n.kind
of nkRecList, nkRecCase:
for s in n: checkForMetaFields(c, s)
for s in n: checkForMetaFields(c, s, hasError)
of nkOfBranch, nkElse:
checkForMetaFields(c, n.lastSon)
checkForMetaFields(c, n.lastSon, hasError)
of nkSym:
let t = n.sym.typ
case t.kind
@@ -1531,9 +1704,9 @@ proc checkForMetaFields(c: PContext; n: PNode) =
tyProc, tyGenericInvocation, tyGenericInst, tyAlias, tySink, tyOwned:
let start = ord(t.kind in {tyGenericInvocation, tyGenericInst})
for i in start..<t.len:
checkMeta(c, n, t[i])
checkMeta(c, n, t[i], hasError, t)
else:
checkMeta(c, n, t)
checkMeta(c, n, t, hasError, nil)
else:
internalAssert c.config, false
@@ -1546,6 +1719,17 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
# check the style here after the pragmas have been processed:
styleCheckDef(c, s)
# compute the type's size and check for illegal recursions:
if a[0].kind == nkPragmaExpr:
let pragmas = a[0][1]
for i in 0 ..< pragmas.len:
if pragmas[i].kind == nkExprColonExpr and
pragmas[i][0].kind == nkIdent and
whichKeyword(pragmas[i][0].ident) == wSize:
if s.typ.kind != tyEnum and sfImportc notin s.flags:
# EventType* {.size: sizeof(uint32).} = enum
# AtomicFlag* {.importc: "atomic_flag", header: "<stdatomic.h>", size: 1.} = object
localError(c.config, pragmas[i].info, "size pragma only allowed for enum types and imported types")
if a[1].kind == nkEmpty:
var x = a[2]
if x.kind in nkCallKinds and nfSem in x.flags:
@@ -1568,9 +1752,11 @@ proc typeSectionFinalPass(c: PContext, n: PNode) =
assert s.typ != nil
assignType(s.typ, t)
s.typ.itemId = t.itemId # same id
checkConstructedType(c.config, s.info, s.typ)
var hasError = false
if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil:
checkForMetaFields(c, s.typ.n)
checkForMetaFields(c, s.typ.n, hasError)
if not hasError:
checkConstructedType(c.config, s.info, s.typ)
# fix bug #5170, bug #17162, bug #15526: ensure locally scoped types get a unique name:
if s.typ.kind in {tyEnum, tyRef, tyObject} and not isTopLevel(c):
@@ -1648,18 +1834,27 @@ proc addParams(c: PContext, n: PNode, kind: TSymKind) =
proc semBorrow(c: PContext, n: PNode, s: PSym) =
# search for the correct alias:
var b = searchForBorrowProc(c, c.currentScope.parent, s)
if b != nil:
# store the alias:
n[bodyPos] = newSymNode(b)
# Carry over the original symbol magic, this is necessary in order to ensure
# the semantic pass is correct
s.magic = b.magic
if b.typ != nil and b.typ.len > 0:
s.typ.n[0] = b.typ.n[0]
s.typ.flags = b.typ.flags
else:
localError(c.config, n.info, errNoSymbolToBorrowFromFound)
var (b, state) = searchForBorrowProc(c, c.currentScope.parent, s)
case state
of bsMatch:
# store the alias:
n[bodyPos] = newSymNode(b)
# Carry over the original symbol magic, this is necessary in order to ensure
# the semantic pass is correct
s.magic = b.magic
if b.typ != nil and b.typ.len > 0:
s.typ.n[0] = b.typ.n[0]
s.typ.flags = b.typ.flags
of bsNoDistinct:
localError(c.config, n.info, "borrow proc without distinct type parameter is meaningless")
of bsReturnNotMatch:
localError(c.config, n.info, "borrow from proc return type mismatch: '$1'" % typeToString(b.typ[0]))
of bsGeneric:
localError(c.config, n.info, "borrow with generic parameter is not supported")
of bsNotSupported:
localError(c.config, n.info, "borrow from '$1' is not supported" % $b.name.s)
else:
localError(c.config, n.info, errNoSymbolToBorrowFromFound)
proc swapResult(n: PNode, sRes: PSym, dNode: PNode) =
## Swap nodes that are (skResult) symbols to d(estination)Node.
@@ -1767,7 +1962,6 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
n[genericParamsPos] = c.graph.emptyNode
# for LL we need to avoid wrong aliasing
let params = copyTree n.typ.n
n[paramsPos] = params
s.typ = n.typ
for i in 1..<params.len:
if params[i].typ.kind in {tyTypeDesc, tyGenericParam,
@@ -1876,7 +2070,7 @@ proc bindDupHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
incl(s.flags, sfUsed)
incl(s.flags, sfOverridden)
proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp; suppressVarDestructorWarning = false) =
let t = s.typ
var noError = false
let cond = case op
@@ -1884,6 +2078,11 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
t.len == 2 and t[0] == nil and t[1].kind == tyVar
of attachedTrace:
t.len == 3 and t[0] == nil and t[1].kind == tyVar and t[2].kind == tyPointer
of attachedDestructor:
if c.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
t.len == 2 and t[0] == nil
else:
t.len == 2 and t[0] == nil and t[1].kind == tyVar
else:
t.len >= 2 and t[0] == nil
@@ -1895,7 +2094,8 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
elif obj.kind == tyGenericInvocation: obj = obj[0]
else: break
if obj.kind in {tyObject, tyDistinct, tySequence, tyString}:
if op == attachedDestructor and t[1].kind == tyVar:
if (not suppressVarDestructorWarning) and op == attachedDestructor and t[1].kind == tyVar and
c.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
message(c.config, n.info, warnDeprecated, "A custom '=destroy' hook which takes a 'var T' parameter is deprecated; it should take a 'T' parameter")
obj = canonType(c, obj)
let ao = getAttachedOp(c.graph, obj, op)
@@ -1915,8 +2115,12 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
localError(c.config, n.info, errGenerated,
"signature for '=trace' must be proc[T: object](x: var T; env: pointer)")
of attachedDestructor:
localError(c.config, n.info, errGenerated,
"signature for '=destroy' must be proc[T: object](x: var T) or proc[T: object](x: T)")
if c.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
localError(c.config, n.info, errGenerated,
"signature for '=destroy' must be proc[T: object](x: var T) or proc[T: object](x: T)")
else:
localError(c.config, n.info, errGenerated,
"signature for '=destroy' must be proc[T: object](x: var T)")
else:
localError(c.config, n.info, errGenerated,
"signature for '" & s.name.s & "' must be proc[T: object](x: var T)")
@@ -2078,6 +2282,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
of nkEmpty:
s = newSym(kind, c.cache.idAnon, c.idgen, c.getCurrOwner, n.info)
s.flags.incl sfUsed
s.flags.incl sfGenSym
n[namePos] = newSymNode(s)
of nkSym:
s = n[namePos].sym
@@ -2613,9 +2818,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType =
var m = n[i]
while m.kind in {nkStmtListExpr, nkStmtList} and m.len > 0: # from templates
m = m.lastSon
if m.kind in nkLastBlockStmts or
m.kind in nkCallKinds and m[0].kind == nkSym and
sfNoReturn in m[0].sym.flags:
if endsInNoReturn(m):
for j in i + 1..<n.len:
case n[j].kind
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkState: discard

View File

@@ -51,7 +51,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
isField = false): PNode =
var
a: PSym
o: TOverloadIter
o: TOverloadIter = default(TOverloadIter)
var i = 0
a = initOverloadIter(o, c, n)
while a != nil:
@@ -66,7 +66,12 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
# for instance 'nextTry' is both in tables.nim and astalgo.nim ...
if not isField or sfGenSym notin s.flags:
result = newSymNode(s, info)
markUsed(c, info, s)
if isField:
# possibly not final field sym
incl(s.flags, sfUsed)
markOwnerModuleAsUsed(c, s)
else:
markUsed(c, info, s)
onUse(info, s)
else:
result = n
@@ -135,24 +140,32 @@ type
noGenSym: int
inTemplateHeader: int
proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
proc isTemplParam(c: TemplCtx, s: PSym): bool {.inline.} =
result = s.kind == skParam and
s.owner == c.owner and sfTemplateParam in s.flags
proc getIdentReplaceParams(c: var TemplCtx, n: var PNode): tuple[node: PNode, hasParam: bool] =
case n.kind
of nkPostfix: result = getIdentNode(c, n[1])
of nkPragmaExpr: result = getIdentNode(c, n[0])
of nkPostfix: result = getIdentReplaceParams(c, n[1])
of nkPragmaExpr: result = getIdentReplaceParams(c, n[0])
of nkIdent:
result = n
result = (n, false)
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if s.owner == c.owner and s.kind == skParam:
result = newSymNode(s, n.info)
of nkAccQuoted, nkSym: result = n
if s != nil and isTemplParam(c, s):
n = newSymNode(s, n.info)
result = (n, true)
of nkSym:
result = (n, isTemplParam(c, n.sym))
of nkAccQuoted:
result = (n, false)
for i in 0..<n.safeLen:
let (ident, hasParam) = getIdentReplaceParams(c, n[i])
if hasParam:
result.node[i] = ident
result.hasParam = true
else:
illFormedAst(n, c.c.config)
result = n
proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} =
result = n.kind == nkSym and n.sym.kind == skParam and
n.sym.owner == c.owner and sfTemplateParam in n.sym.flags
result = (n, false)
proc semTemplBody(c: var TemplCtx, n: PNode): PNode
@@ -167,19 +180,6 @@ proc semTemplBodyScope(c: var TemplCtx, n: PNode): PNode =
result = semTemplBody(c, n)
closeScope(c)
proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
result = n
if n.kind == nkIdent:
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if s.owner == c.owner and s.kind == skParam:
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
onUse(n.info, s)
else:
for i in 0..<n.safeLen:
result[i] = onlyReplaceParams(c, n[i])
proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
result = newSym(kind, considerQuotedIdent(c.c, n), c.c.idgen, c.owner, n.info)
incl(result.flags, sfGenSym)
@@ -191,24 +191,10 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
k == skField:
# even if injected, don't produce a sym choice here:
#n = semTemplBody(c, n)
var x = n
while true:
case x.kind
of nkPostfix: x = x[1]
of nkPragmaExpr: x = x[0]
of nkIdent: break
of nkAccQuoted:
# consider: type `T TemplParam` {.inject.}
# it suffices to return to treat it like 'inject':
n = onlyReplaceParams(c, n)
return
else:
illFormedAst(x, c.c.config)
let ident = getIdentNode(c, x)
if not isTemplParam(c, ident):
if k != skField: c.toInject.incl(x.ident.id)
else:
replaceIdentBySym(c.c, n, ident)
let (ident, hasParam) = getIdentReplaceParams(c, n)
if not hasParam:
if k != skField:
c.toInject.incl(considerQuotedIdent(c.c, ident).id)
else:
if (n.kind == nkPragmaExpr and n.len >= 2 and n[1].kind == nkPragma):
let pragmaNode = n[1]
@@ -218,15 +204,15 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
var found = false
if ni.kind == nkIdent:
for a in templatePragmas:
if ni.ident == getIdent(c.c.cache, $a):
if ni.ident.id == ord(a):
found = true
break
if not found:
openScope(c)
pragmaNode[i] = semTemplBody(c, pragmaNode[i])
closeScope(c)
let ident = getIdentNode(c, n)
if not isTemplParam(c, ident):
let (ident, hasParam) = getIdentReplaceParams(c, n)
if not hasParam:
if n.kind != nkSym and not (n.kind == nkIdent and n.ident.id == ord(wUnderscore)):
let local = newGenSym(k, ident, c)
addPrelimDecl(c.c, local)
@@ -235,77 +221,95 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
replaceIdentBySym(c.c, n, newSymNode(local, n.info))
if k == skParam and c.inTemplateHeader > 0:
local.flags.incl sfTemplateParam
else:
replaceIdentBySym(c.c, n, ident)
proc semTemplSymbol(c: PContext, n: PNode, s: PSym; isField: bool): PNode =
proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField: bool): PNode =
incl(s.flags, sfUsed)
# bug #12885; ideally sem'checking is performed again afterwards marking
# the symbol as used properly, but the nfSem mechanism currently prevents
# that from happening, so we mark the module as used here already:
markOwnerModuleAsUsed(c, s)
markOwnerModuleAsUsed(c.c, s)
# we do not call onUse here, as the identifier is not really
# resolved here. We will fixup the used identifiers later.
case s.kind
of skUnknown:
# Introduced in this pass! Leave it as an identifier.
result = n
of OverloadableSyms-{skTemplate,skMacro}:
result = symChoice(c, n, s, scOpen, isField)
of skTemplate, skMacro:
result = symChoice(c, n, s, scOpen, isField)
if result.kind == nkSym:
# template/macro symbols might need to be semchecked again
# prepareOperand etc don't do this without setting the type to nil
result.typ = nil
of OverloadableSyms:
result = symChoice(c.c, n, s, scOpen, isField)
if not isField and result.kind in {nkSym, nkOpenSymChoice}:
if openSym in c.c.features:
if result.kind == nkSym:
result = newOpenSym(result)
else:
result.typ = nil
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
of skGenericParam:
if isField and sfGenSym in s.flags: result = n
else: result = newSymNodeTypeDesc(s, c.idgen, n.info)
else:
result = newSymNodeTypeDesc(s, c.c.idgen, n.info)
if not isField and s.owner != c.owner:
if openSym in c.c.features:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
of skParam:
result = n
of skType:
if isField and sfGenSym in s.flags: result = n
else: result = newSymNodeTypeDesc(s, c.idgen, n.info)
else: result = newSymNodeTypeDesc(s, c.c.idgen, n.info)
else:
if isField and sfGenSym in s.flags: result = n
else: result = newSymNode(s, n.info)
else:
result = newSymNode(s, n.info)
if not isField:
if openSym in c.c.features:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
result.typ = nil
# Issue #12832
when defined(nimsuggest):
suggestSym(c.graph, n.info, s, c.graph.usageSym, false)
suggestSym(c.c.graph, n.info, s, c.c.graph.usageSym, false)
# field access (dot expr) will be handled by builtinFieldAccess
if not isField:
styleCheckUse(c, n.info, s)
styleCheckUse(c.c, n.info, s)
proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
proc semRoutineInTemplName(c: var TemplCtx, n: PNode, explicitInject: bool): PNode =
result = n
if n.kind == nkIdent:
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags):
if s.owner == c.owner and (s.kind == skParam or
(sfGenSym in s.flags and not explicitInject)):
incl(s.flags, sfUsed)
result = newSymNode(s, n.info)
onUse(n.info, s)
else:
for i in 0..<n.safeLen:
result[i] = semRoutineInTemplName(c, n[i])
result[i] = semRoutineInTemplName(c, n[i], explicitInject)
proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
result = n
checkSonsLen(n, bodyPos + 1, c.c.config)
# routines default to 'inject':
if n.kind notin nkLambdaKinds and symBinding(n[pragmasPos]) == spGenSym:
let ident = getIdentNode(c, n[namePos])
if not isTemplParam(c, ident):
var s = newGenSym(k, ident, c)
s.ast = n
addPrelimDecl(c.c, s)
styleCheckDef(c.c, n.info, s)
onDef(n.info, s)
n[namePos] = newSymNode(s, n[namePos].info)
if n.kind notin nkLambdaKinds:
# routines default to 'inject':
let binding = symBinding(n[pragmasPos])
if binding == spGenSym:
let (ident, hasParam) = getIdentReplaceParams(c, n[namePos])
if not hasParam:
var s = newGenSym(k, ident, c)
s.ast = n
addPrelimDecl(c.c, s)
styleCheckDef(c.c, n.info, s)
onDef(n.info, s)
n[namePos] = newSymNode(s, n[namePos].info)
else:
n[namePos] = ident
else:
n[namePos] = ident
else:
n[namePos] = semRoutineInTemplName(c, n[namePos])
n[namePos] = semRoutineInTemplName(c, n[namePos], binding == spInject)
# open scope for parameters
openScope(c)
for i in patternPos..paramsPos-1:
@@ -381,7 +385,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
else:
if s.kind in {skType, skVar, skLet, skConst}:
discard qualifiedLookUp(c.c, n, {checkAmbiguity, checkModule})
result = semTemplSymbol(c.c, n, s, c.noGenSym > 0)
result = semTemplSymbol(c, n, s, c.noGenSym > 0)
of nkBind:
result = semTemplBody(c, n[0])
of nkBindStmt:
@@ -526,14 +530,21 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
if x.kind == nkExprColonExpr:
x[1] = semTemplBody(c, x[1])
of nkBracketExpr:
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "[]"), n.info)
for i in 0..<n.len: result.add(n[i])
if n.typ == nil:
# if a[b] is nested inside a typed expression, don't convert it
# back to `[]`(a, b), prepareOperand will not typecheck it again
# and so `[]` will not be resolved
# checking if a[b] is typed should be enough to cover this case
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "[]"), n.info)
for i in 0..<n.len: result.add(n[i])
result = semTemplBodySons(c, result)
of nkCurlyExpr:
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "{}"), n.info)
for i in 0..<n.len: result.add(n[i])
if n.typ == nil:
# see nkBracketExpr case for explanation
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "{}"), n.info)
for i in 0..<n.len: result.add(n[i])
result = semTemplBodySons(c, result)
of nkAsgn, nkFastAsgn, nkSinkAsgn:
checkSonsLen(n, 2, c.c.config)
@@ -543,17 +554,21 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
let k = a.kind
case k
of nkBracketExpr:
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "[]="), n.info)
for i in 0..<a.len: result.add(a[i])
result.add(b)
if a.typ == nil:
# see nkBracketExpr case above for explanation
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "[]="), n.info)
for i in 0..<a.len: result.add(a[i])
result.add(b)
let a0 = semTemplBody(c, a[0])
result = semTemplBodySons(c, result)
of nkCurlyExpr:
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "{}="), n.info)
for i in 0..<a.len: result.add(a[i])
result.add(b)
if a.typ == nil:
# see nkBracketExpr case above for explanation
result = newNodeI(nkCall, n.info)
result.add newIdentNode(getIdent(c.c.cache, "{}="), n.info)
for i in 0..<a.len: result.add(a[i])
result.add(b)
result = semTemplBodySons(c, result)
else:
result = semTemplBodySons(c, n)
@@ -566,6 +581,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
# so we use the generic code for nkDotExpr too
let s = qualifiedLookUp(c.c, n, {})
if s != nil:
# mirror the nkIdent case
# do not symchoice a quoted template parameter (bug #2390):
if s.owner == c.owner and s.kind == skParam and
n.kind == nkAccQuoted and n.len == 1:
@@ -577,7 +593,9 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
elif contains(c.toMixin, s.name.id):
return symChoice(c.c, n, s, scForceOpen, c.noGenSym > 0)
else:
return symChoice(c.c, n, s, scOpen, c.noGenSym > 0)
if s.kind in {skType, skVar, skLet, skConst}:
discard qualifiedLookUp(c.c, n, {checkAmbiguity, checkModule})
return semTemplSymbol(c, n, s, c.noGenSym > 0)
if n.kind == nkDotExpr:
result = n
result[0] = semTemplBody(c, n[0])
@@ -673,6 +691,9 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
# a template's parameters are not gensym'ed even if that was originally the
# case as we determine whether it's a template parameter in the template
# body by the absence of the sfGenSym flag:
let retType = s.typ[0]
if retType != nil and retType.kind != tyUntyped:
allUntyped = false
for i in 1..<s.typ.n.len:
let param = s.typ.n[i].sym
if param.name.id != ord(wUnderscore):

View File

@@ -141,6 +141,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
result.n.add symNode
styleCheckDef(c, e)
onDef(e.info, e)
suggestSym(c.graph, e.info, e, c.graph.usageSym)
if sfGenSym notin e.flags:
if not isPure:
addInterfaceOverloadableSymAt(c, c.currentScope, e)
@@ -227,7 +228,24 @@ proc isRecursiveType(t: PType, cycleDetector: var IntSet): bool =
else:
return false
proc annotateClosureConv(n: PNode) =
case n.kind
of {nkNone..nkNilLit}:
discard
of nkTupleConstr:
if n.typ.kind == tyProc and n.typ.callConv == ccClosure and
n[0].typ.kind == tyProc and n[0].typ.callConv != ccClosure:
# restores `transf.generateThunk`
n[0] = newTreeIT(nkHiddenSubConv, n[0].info, n.typ,
newNodeI(nkEmpty, n[0].info), n[0])
n.transitionSonsKind(nkClosure)
n.flags.incl nfTransf
else:
for i in 0..<n.len:
annotateClosureConv(n[i])
proc fitDefaultNode(c: PContext, n: PNode): PType =
inc c.inStaticContext
let expectedType = if n[^2].kind != nkEmpty: semTypeNode(c, n[^2], nil) else: nil
n[^1] = semConstExpr(c, n[^1], expectedType = expectedType)
let oldType = n[^1].typ
@@ -235,9 +253,20 @@ proc fitDefaultNode(c: PContext, n: PNode): PType =
if n[^2].kind != nkEmpty:
if expectedType != nil and oldType != expectedType:
n[^1] = fitNodeConsiderViewType(c, expectedType, n[^1], n[^1].info)
changeType(c, n[^1], expectedType, true) # infer types for default fields value
# bug #22926; be cautious that it uses `semConstExpr` to
# evaulate the default fields; it's only natural to use
# `changeType` to infer types for constant values
# that's also the reason why we don't use `semExpr` to check
# the type since two overlapping error messages might be produced
annotateClosureConv(n)
result = n[^1].typ
else:
result = n[^1].typ
# xxx any troubles related to defaults fields, consult `semConst` for a potential answer
if n[^1].kind != nkNilLit:
typeAllowedCheck(c, n.info, result, skConst, {taProcContextIsNotMacro, taIsDefaultField})
dec c.inStaticContext
proc isRecursiveType*(t: PType): bool =
# handle simple recusive types before typeFinalPass
@@ -335,6 +364,14 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
localError(c.config, n.info, errXExpectsOneTypeParam % "range")
result = newOrPrevType(tyError, prev, c)
proc semArrayIndexConst(c: PContext, e: PNode, info: TLineInfo): PType =
let x = semConstExpr(c, e)
if x.kind in {nkIntLit..nkUInt64Lit}:
result = makeRangeType(c, 0, x.intVal-1, info,
x.typ.skipTypes({tyTypeDesc}))
else:
result = x.typ.skipTypes({tyTypeDesc})
proc semArrayIndex(c: PContext, n: PNode): PType =
if isRange(n):
result = semRangeAux(c, n, nil)
@@ -351,14 +388,18 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
localError(c.config, n.info,
"Array length can't be negative, but was " & $e.intVal)
result = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
elif e.kind == nkSym and e.typ.kind == tyStatic:
if e.sym.ast != nil:
return semArrayIndex(c, e.sym.ast)
if e.typ.lastSon.kind != tyGenericParam and not isOrdinalType(e.typ.lastSon):
let info = if n.safeLen > 1: n[1].info else: n.info
localError(c.config, info, errOrdinalTypeExpected % typeToString(e.typ, preferDesc))
result = makeRangeWithStaticExpr(c, e)
if c.inGenericContext > 0: result.flags.incl tfUnresolved
elif e.kind == nkSym and (e.typ.kind == tyStatic or e.typ.kind == tyTypeDesc) :
if e.typ.kind == tyStatic:
if e.sym.ast != nil:
return semArrayIndex(c, e.sym.ast)
if e.typ.lastSon.kind != tyGenericParam and not isOrdinalType(e.typ.lastSon):
let info = if n.safeLen > 1: n[1].info else: n.info
localError(c.config, info, errOrdinalTypeExpected % typeToString(e.typ, preferDesc))
result = makeRangeWithStaticExpr(c, e)
if c.inGenericContext > 0: result.flags.incl tfUnresolved
else:
result = e.typ.skipTypes({tyTypeDesc})
result.flags.incl tfImplicitStatic
elif e.kind in (nkCallKinds + {nkBracketExpr}) and hasUnresolvedArgs(c, e):
if not isOrdinalType(e.typ.skipTypes({tyStatic, tyAlias, tyGenericInst, tySink})):
localError(c.config, n[1].info, errOrdinalTypeExpected % typeToString(e.typ, preferDesc))
@@ -371,12 +412,7 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
elif e.kind == nkIdent:
result = e.typ.skipTypes({tyTypeDesc})
else:
let x = semConstExpr(c, e)
if x.kind in {nkIntLit..nkUInt64Lit}:
result = makeRangeType(c, 0, x.intVal-1, n.info,
x.typ.skipTypes({tyTypeDesc}))
else:
result = x.typ.skipTypes({tyTypeDesc})
result = semArrayIndexConst(c, e, n.info)
#localError(c.config, n[1].info, errConstExprExpected)
proc semArray(c: PContext, n: PNode, prev: PType): PType =
@@ -388,13 +424,16 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
if indxB.kind in {tyGenericInst, tyAlias, tySink}: indxB = lastSon(indxB)
if indxB.kind notin {tyGenericParam, tyStatic, tyFromExpr} and
tfUnresolved notin indxB.flags:
if indxB.skipTypes({tyRange}).kind in {tyUInt, tyUInt64}:
discard
elif not isOrdinalType(indxB):
if not isOrdinalType(indxB):
localError(c.config, n[1].info, errOrdinalTypeExpected % typeToString(indxB, preferDesc))
elif enumHasHoles(indxB):
localError(c.config, n[1].info, "enum '$1' has holes" %
typeToString(indxB.skipTypes({tyRange})))
elif indxB.kind != tyRange and
lengthOrd(c.config, indxB) > high(uint16).int:
# assume range type is intentional
localError(c.config, n[1].info,
"index type '$1' for array is too large" % typeToString(indxB))
base = semTypeNode(c, n[2], nil)
# ensure we only construct a tyArray when there was no error (bug #3048):
result = newOrPrevType(tyArray, prev, c)
@@ -499,7 +538,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
result = newSymG(kind, n, c)
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym =
allowed: TSymFlags, fromTopLevel = false): PSym =
if n.kind == nkPragmaExpr:
checkSonsLen(n, 2, c.config)
result = semIdentVis(c, kind, n[0], allowed)
@@ -514,6 +553,16 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
else: discard
else:
result = semIdentVis(c, kind, n, allowed)
let invalidPragmasForPush = if fromTopLevel and sfWasGenSym notin result.flags:
{}
else:
{wExportc, wExportCpp, wDynlib}
case kind
of skField: implicitPragmas(c, result, n.info, fieldPragmas)
of skVar: implicitPragmas(c, result, n.info, varPragmas-invalidPragmasForPush)
of skLet: implicitPragmas(c, result, n.info, letPragmas-invalidPragmasForPush)
of skConst: implicitPragmas(c, result, n.info, constPragmas-invalidPragmasForPush)
else: discard
proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
let ex = t[branchIndex][currentEx].skipConv
@@ -1219,7 +1268,7 @@ proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
result = semTypeNode(c, n[0], nil)
constraint = semNodeKindConstraints(n, c.config, 1)
elif n.kind == nkCall and
n[0].kind in {nkIdent, nkSym, nkOpenSymChoice, nkClosedSymChoice} and
n[0].kind in {nkIdent, nkSym, nkOpenSymChoice, nkClosedSymChoice, nkOpenSym} and
considerQuotedIdent(c, n[0]).s == "{}":
result = semTypeNode(c, n[1], nil)
constraint = semNodeKindConstraints(n, c.config, 2)
@@ -1297,7 +1346,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
def.typ = makeTypeFromExpr(c, def.copyTree)
break determineType
def = semExprWithType(c, def, {efDetermineType}, defTyp)
def = semExprWithType(c, def, {efDetermineType, efAllowSymChoice}, defTyp)
if def.referencesAnotherParam(getCurrOwner(c)):
def.flags.incl nfDefaultRefsParam
@@ -1394,7 +1443,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
"' is only valid for macros and templates")
# 'auto' as a return type does not imply a generic:
elif r.kind == tyAnything:
discard
r = copyType(r, nextTypeId c.idgen, r.owner)
r.flags.incl tfRetType
elif r.kind == tyStatic:
# type allowed should forbid this type
discard
@@ -1483,6 +1533,14 @@ proc trySemObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType): b
var newf = newNodeI(nkRecList, n.info)
semRecordNodeAux(c, t.n, check, pos, newf, t)
proc containsGenericInvocationWithForward(n: PNode): bool =
if n.kind == nkSym and n.sym.ast != nil and n.sym.ast.len > 1 and n.sym.ast[2].kind == nkObjectTy:
for p in n.sym.ast[2][^1]:
if p.kind == nkIdentDefs and p[1].typ != nil and p[1].typ.kind == tyGenericInvocation and
p[1][0].kind == nkSym and p[1][0].typ.kind == tyForward:
return true
return false
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
if s.typ == nil:
localError(c.config, n.info, "cannot instantiate the '$1' $2" %
@@ -1492,20 +1550,24 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
var t = s.typ.skipTypes({tyAlias})
if t.kind == tyCompositeTypeClass and t.base.kind == tyGenericBody:
t = t.base
result = newOrPrevType(tyGenericInvocation, prev, c)
addSonSkipIntLit(result, t, c.idgen)
template addToResult(typ) =
template addToResult(typ, skip) =
if typ.isNil:
internalAssert c.config, false
rawAddSon(result, typ)
else: addSonSkipIntLit(result, typ, c.idgen)
else:
if skip:
addSonSkipIntLit(result, typ, c.idgen)
else:
rawAddSon(result, makeRangeWithStaticExpr(c, typ.n))
if t.kind == tyForward:
for i in 1..<n.len:
var elem = semGenericParamInInvocation(c, n[i])
addToResult(elem)
addToResult(elem, true)
return
elif t.kind != tyGenericBody:
# we likely got code of the form TypeA[TypeB] where TypeA is
@@ -1525,7 +1587,8 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
return newOrPrevType(tyError, prev, c)
var isConcrete = true
let rType = m.call[0].typ
let mIndex = if rType != nil: rType.len - 1 else: -1
for i in 1..<m.call.len:
var typ = m.call[i].typ
# is this a 'typedesc' *parameter*? If so, use the typedesc type,
@@ -1533,17 +1596,22 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
if m.call[i].kind == nkSym and m.call[i].sym.kind == skParam and
typ.kind == tyTypeDesc and containsGenericType(typ):
isConcrete = false
addToResult(typ)
addToResult(typ, true)
else:
typ = typ.skipTypes({tyTypeDesc})
if containsGenericType(typ): isConcrete = false
addToResult(typ)
var skip = true
if mIndex >= i - 1 and tfImplicitStatic in rType[i - 1].flags and isIntLit(typ):
skip = false
addToResult(typ, skip)
if isConcrete:
if s.ast == nil and s.typ.kind != tyCompositeTypeClass:
# XXX: What kind of error is this? is it still relevant?
localError(c.config, n.info, errCannotInstantiateX % s.name.s)
result = newOrPrevType(tyError, prev, c)
elif containsGenericInvocationWithForward(n[0]):
c.skipTypes.add n #fixes 1500
else:
result = instGenericContainer(c, n.info, result,
allowMetaTypes = false)
@@ -1562,7 +1630,8 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
recomputeFieldPositions(tx, tx.n, position)
proc maybeAliasType(c: PContext; typeExpr, prev: PType): PType =
if typeExpr.kind in {tyObject, tyEnum, tyDistinct, tyForward, tyGenericBody} and prev != nil:
if prev != nil and (prev.kind == tyGenericBody or
typeExpr.kind in {tyObject, tyEnum, tyDistinct, tyForward, tyGenericBody}):
result = newTypeS(tyAlias, c)
result.rawAddSon typeExpr
result.sym = prev.sym
@@ -1755,6 +1824,8 @@ proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType =
proc semTypeOf(c: PContext; n: PNode; prev: PType): PType =
openScope(c)
inc c.inTypeofContext
defer: dec c.inTypeofContext # compiles can raise an exception
let t = semExprWithType(c, n, {efInTypeof})
closeScope(c)
fixupTypeOf(c, prev, t)
@@ -1769,6 +1840,8 @@ proc semTypeOf2(c: PContext; n: PNode; prev: PType): PType =
localError(c.config, n.info, "typeof: cannot evaluate 'mode' parameter at compile-time")
else:
m = mode.intVal
inc c.inTypeofContext
defer: dec c.inTypeofContext # compiles can raise an exception
let t = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
closeScope(c)
fixupTypeOf(c, prev, t)
@@ -1817,7 +1890,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
return errorSym(c, n)
if result.kind != skType and result.magic notin {mStatic, mType, mTypeOf}:
# this implements the wanted ``var v: V, x: V`` feature ...
var ov: TOverloadIter
var ov: TOverloadIter = default(TOverloadIter)
var amb = initOverloadIter(ov, c, n)
while amb != nil and amb.kind != skType:
amb = nextOverloadIter(ov, c, n)
@@ -1860,11 +1933,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of nkTupleConstr: result = semAnonTuple(c, n, prev)
of nkCallKinds:
let x = n[0]
let ident = case x.kind
of nkIdent: x.ident
of nkSym: x.sym.name
of nkClosedSymChoice, nkOpenSymChoice: x[0].sym.name
else: nil
let ident = x.getPIdent
if ident != nil and ident.s == "[]":
let b = newNodeI(nkBracketExpr, n.info)
for i in 1..<n.len: b.add(n[i])
@@ -1954,12 +2023,15 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
elif op.id == ord(wType):
checkSonsLen(n, 2, c.config)
result = semTypeOf(c, n[1], prev)
elif op.s == "typeof" and n[0].kind == nkSym and n[0].sym.magic == mTypeOf:
elif op.s == "typeof" and (
(n[0].kind == nkSym and n[0].sym.magic == mTypeOf) or
(n[0].kind == nkOpenSym and n[0][0].sym.magic == mTypeOf)):
result = semTypeOf2(c, n, prev)
elif op.s == "owned" and optOwnedRefs notin c.config.globalOptions and n.len == 2:
result = semTypeExpr(c, n[1], prev)
else:
if c.inGenericContext > 0 and n.kind == nkCall:
let n = semGenericStmt(c, n)
result = makeTypeFromExpr(c, n.copyTree)
else:
result = semTypeExpr(c, n, prev)
@@ -2040,7 +2112,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
if s.kind != skError: localError(c.config, n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
elif s.kind == skParam and s.typ.kind == tyTypeDesc:
internalAssert c.config, s.typ.base.kind != tyNone and prev == nil
internalAssert c.config, s.typ.base.kind != tyNone
result = s.typ.base
elif prev == nil:
result = s.typ
@@ -2064,7 +2136,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
if s.kind == skType:
s.typ
else:
internalAssert c.config, s.typ.base.kind != tyNone and prev == nil
internalAssert c.config, s.typ.base.kind != tyNone
s.typ.base
let alias = maybeAliasType(c, t, prev)
if alias != nil:
@@ -2113,12 +2185,18 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
else:
let symKind = if n.kind == nkIteratorTy: skIterator else: skProc
result = semProcTypeWithScope(c, n, prev, symKind)
if result == nil:
localError(c.config, n.info, "type expected, but got: " & renderTree(n))
result = newOrPrevType(tyError, prev, c)
if n.kind == nkIteratorTy and result.kind == tyProc:
result.flags.incl(tfIterator)
if result.callConv == ccClosure and c.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
result.flags.incl tfHasAsgn
of nkEnumTy: result = semEnum(c, n, prev)
of nkType: result = n.typ
of nkStmtListType: result = semStmtListType(c, n, prev)
of nkBlockType: result = semBlockType(c, n, prev)
of nkOpenSym: result = semTypeNode(c, n[0], prev)
else:
result = semTypeExpr(c, n, prev)
when false:

View File

@@ -46,7 +46,8 @@ proc searchInstTypes*(g: ModuleGraph; key: PType): PType =
# XXX: This happens for prematurely cached
# types such as Channel[empty]. Why?
# See the notes for PActor in handleGenericInvocation
return
# if this is return the same type gets cached more than it needs to
continue
if not sameFlags(inst, key):
continue
@@ -87,8 +88,8 @@ type
recursionLimit: int
proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym
proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode; start=0): PNode
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym, t: PType): PSym
proc replaceTypeVarsN*(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PType = nil): PNode
proc initLayeredTypeMap*(pt: TIdTable): LayeredIdTable =
result = LayeredIdTable()
@@ -128,11 +129,20 @@ proc prepareNode(cl: var TReplTypeVars, n: PNode): PNode =
else: t.n
result = copyNode(n)
result.typ = t
if result.kind == nkSym: result.sym = replaceTypeVarsS(cl, n.sym)
if result.kind == nkSym:
result.sym =
if n.typ != nil and n.typ == n.sym.typ:
replaceTypeVarsS(cl, n.sym, result.typ)
else:
replaceTypeVarsS(cl, n.sym, replaceTypeVarsT(cl, n.sym.typ))
let isCall = result.kind in nkCallKinds
# don't try to instantiate symchoice symbols, they can be
# generic procs which the compiler will think are uninstantiated
# because their type will contain uninstantiated params
let isSymChoice = result.kind in nkSymChoices
for i in 0..<n.safeLen:
# XXX HACK: ``f(a, b)``, avoid to instantiate `f`
if isCall and i == 0: result.add(n[i])
if isSymChoice or (isCall and i == 0): result.add(n[i])
else: result.add(prepareNode(cl, n[i]))
proc isTypeParam(n: PNode): bool =
@@ -204,7 +214,7 @@ proc hasValuelessStatics(n: PNode): bool =
a
proc doThing(_: MyThing)
]#
if n.safeLen == 0:
if n.safeLen == 0 and n.kind != nkEmpty: # Some empty nodes can get in here
n.typ == nil or n.typ.kind == tyStatic
else:
for x in n:
@@ -212,7 +222,7 @@ proc hasValuelessStatics(n: PNode): bool =
return true
false
proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode =
proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0; expectedType: PType = nil): PNode =
if n == nil: return
result = copyNode(n)
if n.typ != nil:
@@ -223,7 +233,11 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode =
discard
of nkOpenSymChoice, nkClosedSymChoice: result = n
of nkSym:
result.sym = replaceTypeVarsS(cl, n.sym)
result.sym =
if n.typ != nil and n.typ == n.sym.typ:
replaceTypeVarsS(cl, n.sym, result.typ)
else:
replaceTypeVarsS(cl, n.sym, replaceTypeVarsT(cl, n.sym.typ))
if result.sym.typ.kind == tyVoid:
# don't add the 'void' field
result = newNodeI(nkRecList, n.info)
@@ -254,8 +268,8 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode =
when false:
n = reResolveCallsWithTypedescParams(cl, n)
result = if cl.allowMetaTypes: n
else: cl.c.semExpr(cl.c, n)
if not cl.allowMetaTypes:
else: cl.c.semExpr(cl.c, n, {}, expectedType)
if not cl.allowMetaTypes and expectedType != nil:
assert result.kind notin nkCallKinds
else:
if n.len > 0:
@@ -265,7 +279,7 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode =
for i in start..<n.len:
result[i] = replaceTypeVarsN(cl, n[i])
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym, t: PType): PSym =
if s == nil: return nil
# symbol is not our business:
if cl.owner != nil and s.owner != cl.owner:
@@ -306,11 +320,14 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
incl(result.flags, sfFromGeneric)
#idTablePut(cl.symMap, s, result)
result.owner = s.owner
result.typ = replaceTypeVarsT(cl, s.typ)
result.typ = t
if result.kind != skType:
result.ast = replaceTypeVarsN(cl, s.ast)
proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
if tfRetType in t.flags and t.kind == tyAnything:
# don't bind `auto` return type to a previous binding of `auto`
return nil
result = cl.typeMap.lookup(t)
if result == nil:
if cl.allowMetaTypes or tfRetType in t.flags: return
@@ -548,7 +565,9 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
result = t
if t == nil: return
if t.kind in {tyStatic, tyGenericParam, tyConcept} + tyTypeClasses:
const lookupMetas = {tyStatic, tyGenericParam, tyConcept} + tyTypeClasses - {tyAnything}
if t.kind in lookupMetas or
(t.kind == tyAnything and tfRetType notin t.flags):
let lookup = cl.typeMap.lookup(t)
if lookup != nil: return lookup
@@ -559,6 +578,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
result.kind = tyUserTypeClassInst
of tyGenericBody:
if cl.allowMetaTypes: return
localError(
cl.c.config,
cl.info,
@@ -632,7 +652,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
for i in 0..<result.len:
if result[i] != nil:
if result[i].kind == tyGenericBody:
if result[i].kind == tyGenericBody and not cl.allowMetaTypes:
localError(cl.c.config, if t.sym != nil: t.sym.info else: cl.info,
"cannot instantiate '" &
typeToString(result[i], preferDesc) &
@@ -691,12 +711,13 @@ proc initTypeVars*(p: PContext, typeMap: LayeredIdTable, info: TLineInfo;
result.owner = owner
proc replaceTypesInBody*(p: PContext, pt: TIdTable, n: PNode;
owner: PSym, allowMetaTypes = false): PNode =
owner: PSym, allowMetaTypes = false,
fromStaticExpr = false, expectedType: PType = nil): PNode =
var typeMap = initLayeredTypeMap(pt)
var cl = initTypeVars(p, typeMap, n.info, owner)
cl.allowMetaTypes = allowMetaTypes
pushInfoContext(p.config, n.info)
result = replaceTypeVarsN(cl, n)
result = replaceTypeVarsN(cl, n, expectedType = expectedType)
popInfoContext(p.config)
when false:

View File

@@ -260,7 +260,8 @@ when defined(debugSigHashes):
# (select hash from sighashes group by hash having count(*) > 1) order by hash;
proc hashType*(t: PType; conf: ConfigRef; flags: set[ConsiderFlag] = {CoType}): SigHash =
var c: MD5Context
result = default(SigHash)
var c: MD5Context = default(MD5Context)
md5Init c
hashType c, t, flags+{CoOwnerSig}, conf
md5Final c, result.MD5Digest
@@ -269,7 +270,8 @@ proc hashType*(t: PType; conf: ConfigRef; flags: set[ConsiderFlag] = {CoType}):
typeToString(t), $result)
proc hashProc(s: PSym; conf: ConfigRef): SigHash =
var c: MD5Context
result = default(SigHash)
var c: MD5Context = default(MD5Context)
md5Init c
hashType c, s.typ, {CoProc}, conf
@@ -289,7 +291,8 @@ proc hashProc(s: PSym; conf: ConfigRef): SigHash =
md5Final c, result.MD5Digest
proc hashNonProc*(s: PSym): SigHash =
var c: MD5Context
result = default(SigHash)
var c: MD5Context = default(MD5Context)
md5Init c
hashSym(c, s)
var it = s
@@ -305,7 +308,8 @@ proc hashNonProc*(s: PSym): SigHash =
md5Final c, result.MD5Digest
proc hashOwner*(s: PSym): SigHash =
var c: MD5Context
result = default(SigHash)
var c: MD5Context = default(MD5Context)
md5Init c
var m = s
while m.kind != skModule: m = m.owner
@@ -378,7 +382,7 @@ proc symBodyDigest*(graph: ModuleGraph, sym: PSym): SigHash =
graph.symBodyHashes.withValue(sym.id, value):
return value[]
var c: MD5Context
var c: MD5Context = default(MD5Context)
md5Init(c)
c.hashType(sym.typ, {CoProc}, graph.config)
c &= char(sym.kind)

View File

@@ -78,7 +78,8 @@ type
# or when the explain pragma is used. may be
# triggered with an idetools command in the
# future.
inheritancePenalty: int # to prefer closest father object type
# to prefer closest father object type
inheritancePenalty: int
firstMismatch*: MismatchInfo # mismatch info for better error messages
diagnosticsEnabled*: bool
@@ -93,8 +94,9 @@ type
const
isNilConversion = isConvertible # maybe 'isIntConv' fits better?
maxInheritancePenalty = high(int) div 2
proc markUsed*(c: PContext; info: TLineInfo, s: PSym)
proc markUsed*(c: PContext; info: TLineInfo, s: PSym; checkStyle = true)
proc markOwnerModuleAsUsed*(c: PContext; s: PSym)
template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
@@ -113,7 +115,7 @@ proc initCandidateAux(ctx: PContext,
c.call = nil
c.baseTypeMatch = false
c.genericConverter = false
c.inheritancePenalty = 0
c.inheritancePenalty = -1
proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) =
initCandidateAux(ctx, c, callee)
@@ -140,15 +142,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
initCandidateAux(ctx, c, callee.typ)
c.calleeSym = callee
if callee.kind in skProcKinds and calleeScope == -1:
if callee.originatingModule == ctx.module:
c.calleeScope = 2
var owner = callee
while true:
owner = owner.skipGenericOwner
if owner.kind == skModule: break
inc c.calleeScope
else:
c.calleeScope = 1
c.calleeScope = cmpScopes(ctx, callee)
else:
c.calleeScope = calleeScope
c.diagnostics = @[] # if diagnosticsEnabled: @[] else: nil
@@ -175,19 +169,19 @@ proc newCandidate*(ctx: PContext, callee: PSym,
proc newCandidate*(ctx: PContext, callee: PType): TCandidate =
initCandidate(ctx, result, callee)
proc copyCandidate(a: var TCandidate, b: TCandidate) =
a.c = b.c
a.exactMatches = b.exactMatches
a.subtypeMatches = b.subtypeMatches
a.convMatches = b.convMatches
a.intConvMatches = b.intConvMatches
a.genericMatches = b.genericMatches
a.state = b.state
a.callee = b.callee
a.calleeSym = b.calleeSym
a.call = copyTree(b.call)
a.baseTypeMatch = b.baseTypeMatch
copyIdTable(a.bindings, b.bindings)
proc copyCandidate(dest: var TCandidate, src: TCandidate) =
dest.c = src.c
dest.exactMatches = src.exactMatches
dest.subtypeMatches = src.subtypeMatches
dest.convMatches = src.convMatches
dest.intConvMatches = src.intConvMatches
dest.genericMatches = src.genericMatches
dest.state = src.state
dest.callee = src.callee
dest.calleeSym = src.calleeSym
dest.call = copyTree(src.call)
dest.baseTypeMatch = src.baseTypeMatch
copyIdTable(dest.bindings, src.bindings)
proc typeRel*(c: var TCandidate, f, aOrig: PType,
flags: TTypeRelFlags = {}): TTypeRelation
@@ -202,10 +196,10 @@ proc checkGeneric(a, b: TCandidate): int =
let tra = typeRel(ma, bb[i], aa[i], {trDontBind})
var mb = newCandidate(c, aa[i])
let trb = typeRel(mb, aa[i], bb[i], {trDontBind})
if tra == isGeneric and trb == isNone:
if tra == isGeneric and trb in {isNone, isInferred, isInferredConvertible}:
if winner == -1: return 0
winner = 1
if trb == isGeneric and tra == isNone:
if trb == isGeneric and tra in {isNone, isInferred, isInferredConvertible}:
if winner == 1: return 0
winner = -1
result = winner
@@ -215,14 +209,24 @@ proc sumGeneric(t: PType): int =
# and Foo[T] has the value 2 so that we know Foo[Foo[T]] is more
# specific than Foo[T].
var t = t
var isvar = 0
while true:
case t.kind
of tyGenericInst, tyArray, tyRef, tyPtr, tyDistinct, tyUncheckedArray,
tyOpenArray, tyVarargs, tySet, tyRange, tySequence, tyGenericBody,
tyLent, tyOwned:
of tyAlias, tySink, tyNot: t = t.lastSon
of tyArray, tyRef, tyPtr, tyDistinct, tyUncheckedArray,
tyOpenArray, tyVarargs, tySet, tyRange, tySequence,
tyLent, tyOwned, tyVar:
t = t.lastSon
inc result
of tyBool, tyChar, tyEnum, tyObject, tyPointer, tyVoid,
tyString, tyCstring, tyInt..tyInt64, tyFloat..tyFloat128,
tyUInt..tyUInt64, tyCompositeTypeClass, tyBuiltInTypeClass:
inc result
break
of tyGenericBody:
t = t.typeBodyImpl
of tyGenericInst, tyStatic:
t = t[0]
inc result
of tyOr:
var maxBranch = 0
for branch in t.sons:
@@ -230,32 +234,25 @@ proc sumGeneric(t: PType): int =
if branchSum > maxBranch: maxBranch = branchSum
inc result, maxBranch
break
of tyVar:
t = t[0]
inc result
inc isvar
of tyTypeDesc:
t = t.lastSon
if t.kind == tyEmpty: break
inc result
of tyGenericParam:
if t.len > 0:
t = t.skipModifier
else:
inc result
break
of tyUntyped, tyTyped: break
of tyGenericInvocation, tyTuple, tyProc, tyAnd:
result += ord(t.kind in {tyGenericInvocation, tyAnd})
result += ord(t.kind == tyAnd)
for i in 0..<t.len:
if t[i] != nil:
result += sumGeneric(t[i])
break
of tyStatic:
return sumGeneric(t[0]) + 1
of tyGenericParam, tyUntyped, tyTyped: break
of tyAlias, tySink: t = t.lastSon
of tyBool, tyChar, tyEnum, tyObject, tyPointer,
tyString, tyCstring, tyInt..tyInt64, tyFloat..tyFloat128,
tyUInt..tyUInt64, tyCompositeTypeClass:
return isvar + 1
of tyBuiltInTypeClass:
return isvar
else:
return 0
break
proc complexDisambiguation(a, b: PType): int =
# 'a' matches better if *every* argument matches better or equal than 'b'.
@@ -290,7 +287,16 @@ proc writeMatches*(c: TCandidate) =
echo " conv matches: ", c.convMatches
echo " inheritance: ", c.inheritancePenalty
proc cmpCandidates*(a, b: TCandidate): int =
proc cmpInheritancePenalty(a, b: int): int =
var eb = b
var ea = a
if b < 0:
eb = maxInheritancePenalty # defacto max penalty
if a < 0:
ea = maxInheritancePenalty
eb - ea
proc cmpCandidates*(a, b: TCandidate, isFormal=true): int =
result = a.exactMatches - b.exactMatches
if result != 0: return
result = a.genericMatches - b.genericMatches
@@ -301,16 +307,16 @@ proc cmpCandidates*(a, b: TCandidate): int =
if result != 0: return
result = a.convMatches - b.convMatches
if result != 0: return
# the other way round because of other semantics:
result = b.inheritancePenalty - a.inheritancePenalty
result = cmpInheritancePenalty(a.inheritancePenalty, b.inheritancePenalty)
if result != 0: return
# check for generic subclass relation
result = checkGeneric(a, b)
if isFormal:
# check for generic subclass relation
result = checkGeneric(a, b)
if result != 0: return
# prefer more specialized generic over more general generic:
result = complexDisambiguation(a.callee, b.callee)
if result != 0: return
# prefer more specialized generic over more general generic:
result = complexDisambiguation(a.callee, b.callee)
# only as a last resort, consider scoping:
if result != 0: return
result = a.calleeScope - b.calleeScope
proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
@@ -330,16 +336,27 @@ template describeArgImpl(c: PContext, n: PNode, i: int, startIdx = 1; prefer = p
result.add renderTree(n[i][0])
result.add ": "
if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo}:
# XXX we really need to 'tryExpr' here!
arg = c.semOperand(c, n[i][1])
n[i].typ = arg.typ
n[i][1] = arg
arg = c.semTryExpr(c, n[i][1])
if arg == nil:
arg = n[i][1]
arg.typ = newTypeS(tyUntyped, c)
else:
if arg.typ == nil:
arg.typ = newTypeS(tyVoid, c)
n[i].typ = arg.typ
n[i][1] = arg
else:
if arg.typ.isNil and arg.kind notin {nkStmtList, nkDo, nkElse,
nkOfBranch, nkElifBranch,
nkExceptBranch}:
arg = c.semOperand(c, n[i])
n[i] = arg
arg = c.semTryExpr(c, n[i])
if arg == nil:
arg = n[i]
arg.typ = newTypeS(tyUntyped, c)
else:
if arg.typ == nil:
arg.typ = newTypeS(tyVoid, c)
n[i] = arg
if arg.typ != nil and arg.typ.kind == tyError: return
result.add argTypeToString(arg, prefer)
@@ -362,6 +379,7 @@ proc concreteType(c: TCandidate, t: PType; f: PType = nil): PType =
else: result = t
of tyGenericParam, tyAnything, tyConcept:
result = t
if c.isNoCall: return
while true:
result = PType(idTableGet(c.bindings, t))
if result == nil:
@@ -456,6 +474,45 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
else: result = isIntConv
else: result = isNone
proc reduceToBase(f: PType): PType =
#[
Returns the lowest order (most general) type that that is compatible with the input.
E.g.
A[T] = ptr object ... A -> ptr object
A[N: static[int]] = array[N, int] ... A -> array
]#
case f.kind:
of tyGenericParam:
if f.len <= 0 or f.skipModifier == nil:
result = f
else:
result = reduceToBase(f.skipModifier)
of tyGenericInvocation:
result = reduceToBase(f.baseClass)
of tyCompositeTypeClass, tyAlias:
if f.len <= 0 or f[0] == nil:
result = f
else:
result = reduceToBase(f.elementType)
of tyGenericInst:
result = reduceToBase(f.skipModifier)
of tyGenericBody:
result = reduceToBase(f.typeBodyImpl)
of tyUserTypeClass:
if f.isResolvedUserTypeClass:
result = f.base # ?? idk if this is right
else:
result = f.lastSon
of tyStatic, tyOwned, tyVar, tyLent, tySink:
result = reduceToBase(f.base)
of tyInferred:
# This is not true "After a candidate type is selected"
result = reduceToBase(f.base)
of tyRange:
result = f.lastSon
else:
result = f
proc genericParamPut(c: var TCandidate; last, fGenericOrigin: PType) =
if fGenericOrigin != nil and last.kind == tyGenericInst and
last.len-1 == fGenericOrigin.len:
@@ -470,7 +527,8 @@ proc isObjectSubtype(c: var TCandidate; a, f, fGenericOrigin: PType): int =
var depth = 0
var last = a
while t != nil and not sameObjectTypes(f, t):
assert t.kind == tyObject
if t.kind != tyObject: # avoid entering generic params etc
return -1
t = t[0]
if t == nil: break
last = t
@@ -533,7 +591,7 @@ proc minRel(a, b: TTypeRelation): TTypeRelation =
if a <= b: result = a
else: result = b
proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
proc recordRel(c: var TCandidate, f, a: PType, flags: TTypeRelFlags): TTypeRelation =
result = isNone
if sameType(f, a):
result = isEqual
@@ -542,8 +600,13 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
let firstField = if f.kind == tyTuple: 0
else: 1
for i in firstField..<f.len:
var m = typeRel(c, f[i], a[i])
var m = typeRel(c, f[i], a[i], flags)
if m < isSubtype: return isNone
if m == isSubtype and a[i].kind != tyNil and c.inheritancePenalty > -1:
# we can't process individual element type conversions from a
# type conversion for the whole tuple
# subtype relations need type conversions when inheritance is used
return isNone
result = minRel(result, m)
if f.n != nil and a.n != nil:
for i in 0..<f.n.len:
@@ -553,7 +616,7 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
else:
var x = f.n[i].sym
var y = a.n[i].sym
if f.kind == tyObject and typeRel(c, x.typ, y.typ) < isSubtype:
if f.kind == tyObject and typeRel(c, x.typ, y.typ, flags) < isSubtype:
return isNone
if x.name.id != y.name.id: return isNone
@@ -810,7 +873,8 @@ proc maybeSkipDistinct(m: TCandidate; t: PType, callee: PSym): PType =
result = t
proc tryResolvingStaticExpr(c: var TCandidate, n: PNode,
allowUnresolved = false): PNode =
allowUnresolved = false,
expectedType: PType = nil): PNode =
# Consider this example:
# type Value[N: static[int]] = object
# proc foo[N](a: Value[N], r: range[0..(N-1)])
@@ -819,6 +883,8 @@ proc tryResolvingStaticExpr(c: var TCandidate, n: PNode,
# This proc is used to evaluate such static expressions.
let instantiated = replaceTypesInBody(c.c, c.bindings, n, nil,
allowMetaTypes = allowUnresolved)
if instantiated.kind in nkCallKinds:
return nil
result = c.c.semExpr(c.c, instantiated)
proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool =
@@ -932,9 +998,21 @@ proc inferStaticsInRange(c: var TCandidate,
doInferStatic(lowerBound, getInt(upperBound) + 1 - lengthOrd(c.c.config, concrete))
template subtypeCheck() =
if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in {
tyRef, tyPtr, tyVar, tyLent, tyOwned}:
case result
of isIntConv:
result = isNone
of isSubrange:
discard # XXX should be isNone with preview define, warnings
of isConvertible:
if f.lastSon.skipTypes(abstractInst).kind != tyOpenArray:
# exclude var openarray which compiler supports
result = isNone
of isSubtype:
if f.lastSon.skipTypes(abstractInst).kind in {
tyRef, tyPtr, tyVar, tyLent, tyOwned}:
# compiler can't handle subtype conversions with pointer indirection
result = isNone
else: discard
proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
# this proc is always called for a pair of matching types
@@ -991,8 +1069,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
# of the designated type class.
#
# 3) When used with two type classes, it will check whether the types
# matching the first type class are a strict subset of the types matching
# the other. This allows us to compare the signatures of generic procs in
# 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:
#
# seq[seq[any]] is a strict subset of seq[any] and hence more specific.
@@ -1143,12 +1221,16 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
of tyFromExpr:
if c.c.inGenericContext > 0:
# generic type bodies can sometimes compile call expressions
# prevent expressions with unresolved types from
# being passed as parameters
return isNone
if not c.isNoCall:
# generic type bodies can sometimes compile call expressions
# prevent expressions with unresolved types from
# being passed as parameters
return isNone
else:
# Foo[templateCall(T)] shouldn't fail early if Foo has a constraint
# and we can't evaluate `templateCall(T)` yet
return isGeneric
else: discard
case f.kind
of tyEnum:
if a.kind == f.kind and sameEnumTypes(f, a): result = isEqual
@@ -1165,9 +1247,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
if result notin {isNone, isGeneric}:
# resolve any late-bound static expressions
# that may appear in the range:
let expectedType = base(f)
for i in 0..1:
if f.n[i].kind == nkStaticExpr:
f.n[i] = tryResolvingStaticExpr(c, f.n[i])
let r = tryResolvingStaticExpr(c, f.n[i], expectedType = expectedType)
if r != nil:
f.n[i] = r
result = typeRangeRel(f, a)
else:
let f = skipTypes(f, {tyRange})
@@ -1203,13 +1288,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
result = typeRel(c, f.base, aOrig, flags + {trNoCovariance})
subtypeCheck()
of tyArray:
case a.kind
of tyArray:
a = reduceToBase(a)
if a.kind == tyArray:
var fRange = f[0]
var aRange = a[0]
if fRange.kind == tyGenericParam:
if fRange.kind in {tyGenericParam, tyAnything}:
var prev = PType(idTableGet(c.bindings, fRange))
if prev == nil:
if typeRel(c, fRange, aRange) == isNone:
return isNone
put(c, fRange, a[0])
fRange = a
else:
@@ -1222,7 +1309,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
result = isGeneric
else:
result = typeRel(c, ff, aa, flags)
if result < isGeneric:
if nimEnableCovariance and
trNoCovariance notin flags and
@@ -1233,13 +1319,16 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
return isNone
if fRange.rangeHasUnresolvedStatic:
if aRange.kind in {tyGenericParam} and aRange.reduceToBase() == aRange:
return
return inferStaticsInRange(c, fRange, a)
elif c.c.matchedConcept != nil and aRange.rangeHasUnresolvedStatic:
return inferStaticsInRange(c, aRange, f)
elif result == isGeneric and concreteType(c, aa, ff) == nil:
return isNone
else:
if lengthOrd(c.c.config, fRange) != lengthOrd(c.c.config, aRange):
result = isNone
else: discard
of tyUncheckedArray:
if a.kind == tyUncheckedArray:
result = typeRel(c, base(f), base(a), flags)
@@ -1321,16 +1410,20 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
skipOwned(a)
if a.kind == f.kind: result = isEqual
of tyTuple:
if a.kind == tyTuple: result = recordRel(c, f, a)
if a.kind == tyTuple: result = recordRel(c, f, a, flags)
of tyObject:
if a.kind == tyObject:
if sameObjectTypes(f, a):
let effectiveArgType = if useTypeLoweringRuleInTypeClass:
a
else:
reduceToBase(a)
if effectiveArgType.kind == tyObject:
if sameObjectTypes(f, effectiveArgType):
c.inheritancePenalty = if tfFinal in f.flags: -1 else: 0
result = isEqual
# elif tfHasMeta in f.flags: result = recordRel(c, f, a)
elif trIsOutParam notin flags:
var depth = isObjectSubtype(c, a, f, nil)
if depth > 0:
inc(c.inheritancePenalty, depth)
c.inheritancePenalty = isObjectSubtype(c, effectiveArgType, f, nil)
if c.inheritancePenalty > 0:
result = isSubtype
of tyDistinct:
a = a.skipTypes({tyOwned, tyGenericInst, tyRange})
@@ -1353,7 +1446,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
result = isNone
of tyPtr, tyRef:
skipOwned(a)
a = reduceToBase(a)
if a.kind == f.kind:
# ptr[R, T] can be passed to ptr[T], but not the other way round:
if a.len < f.len: return isNone
@@ -1447,8 +1540,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
let origF = f
var f = if prev == nil: f else: prev
let roota = a.skipGenericAlias
let rootf = f.skipGenericAlias
let deptha = a.genericAliasDepth()
let depthf = f.genericAliasDepth()
let skipBoth = deptha == depthf and (a.len > 0 and f.len > 0 and a.base != f.base)
let roota = if skipBoth or deptha > depthf: a.skipGenericAlias else: a
let rootf = if skipBoth or depthf > deptha: f.skipGenericAlias else: f
if a.kind == tyGenericInst:
if roota.base == rootf.base:
@@ -1499,7 +1596,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
if aAsObject.kind == tyObject and trIsOutParam notin flags:
let baseType = aAsObject.base
if baseType != nil:
c.inheritancePenalty += 1
inc c.inheritancePenalty, 1 + int(c.inheritancePenalty < 0)
let ret = typeRel(c, f, baseType, flags)
return if ret in {isEqual,isGeneric}: isSubtype else: ret
@@ -1520,6 +1617,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
of tyGenericInvocation:
var x = a.skipGenericAlias
if x.kind == tyGenericParam and x.len > 0:
x = x.lastSon
let concpt = f[0].skipTypes({tyGenericBody})
var preventHack = concpt.kind == tyConcept
if x.kind == tyOwned and f[0].kind != tyOwned:
@@ -1530,12 +1629,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
c.calleeSym != nil and
c.calleeSym.kind in {skProc, skFunc} and c.call != nil and not preventHack:
let inst = prepareMetatypeForSigmatch(c.c, c.bindings, c.call.info, f)
#echo "inferred ", typeToString(inst), " for ", f
return typeRel(c, inst, a, flags)
if x.kind == tyGenericInvocation:
if f[0] == x[0]:
for i in 1..<f.len:
# Handle when checking against a generic that isn't fully instantiated
if i >= x.len: return
let tr = typeRel(c, f[i], x[i], flags)
if tr <= isSubtype: return
result = isGeneric
@@ -1557,9 +1657,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
var fskip = skippedNone
let aobj = x.skipToObject(askip)
let fobj = genericBody.lastSon.skipToObject(fskip)
var depth = -1
if fobj != nil and aobj != nil and askip == fskip:
depth = isObjectSubtype(c, aobj, fobj, f)
result = typeRel(c, genericBody, x, flags)
if result != isNone:
# see tests/generics/tgeneric3.nim for an example that triggers this
@@ -1585,7 +1682,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
put(c, key, x)
elif typeRel(c, old, x, flags + {trDontBind}) == isNone:
return isNone
var depth = -1
if fobj != nil and aobj != nil and askip == fskip:
depth = isObjectSubtype(c, aobj, fobj, f)
if result == isNone:
# Here object inheriting from generic/specialized generic object
# crossing path with metatypes/aliases, so we need to separate them
@@ -1595,7 +1695,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
depth = -1
if depth >= 0:
c.inheritancePenalty += depth
inc c.inheritancePenalty, depth + int(c.inheritancePenalty < 0)
# bug #4863: We still need to bind generic alias crap, so
# we cannot return immediately:
result = if depth == 0: isGeneric else: isSubtype
@@ -1614,20 +1714,21 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
considerPreviousT:
result = isNone
let oldInheritancePenalty = c.inheritancePenalty
var maxInheritance = 0
var minInheritance = maxInheritancePenalty
for branch in f.sons:
c.inheritancePenalty = 0
c.inheritancePenalty = -1
let x = typeRel(c, branch, aOrig, flags)
maxInheritance = max(maxInheritance, c.inheritancePenalty)
# 'or' implies maximum matching result:
if x > result: result = x
if x >= result:
if c.inheritancePenalty > -1:
minInheritance = min(minInheritance, c.inheritancePenalty)
result = x
if result >= isIntConv:
if minInheritance < maxInheritancePenalty:
c.inheritancePenalty = oldInheritancePenalty + minInheritance
if result > isGeneric: result = isGeneric
bindingRet result
else:
result = isNone
c.inheritancePenalty = oldInheritancePenalty + maxInheritance
of tyNot:
considerPreviousT:
for branch in f.sons:
@@ -1647,10 +1748,13 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
considerPreviousT:
let target = f[0]
let targetKind = target.kind
let effectiveArgType = a.skipTypes({tyRange, tyGenericInst,
tyBuiltInTypeClass, tyAlias, tySink, tyOwned})
var effectiveArgType = reduceToBase(a)
# the skipped child of tyBuiltInTypeClass can be structured differently,
# newConstraint constructs them with no children
let typeClassArg = effectiveArgType.kind == tyBuiltInTypeClass
effectiveArgType = effectiveArgType.skipTypes({tyBuiltInTypeClass})
if targetKind == effectiveArgType.kind:
if effectiveArgType.isEmptyContainer:
if not typeClassArg and effectiveArgType.isEmptyContainer:
return isNone
if targetKind == tyProc:
if target.flags * {tfIterator} != effectiveArgType.flags * {tfIterator}:
@@ -1658,7 +1762,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
if tfExplicitCallConv in target.flags and
target.callConv != effectiveArgType.callConv:
return isNone
put(c, f, a)
if doBind: put(c, f, a)
return isGeneric
else:
return isNone
@@ -1744,18 +1848,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
else:
# check if 'T' has a constraint as in 'proc p[T: Constraint](x: T)'
if f.len > 0 and f[0].kind != tyNone:
let oldInheritancePenalty = c.inheritancePenalty
result = typeRel(c, f[0], a, flags + {trDontBind,trBindGenericParam})
if doBindGP and result notin {isNone, isGeneric}:
let concrete = concreteType(c, a, f)
if concrete == nil: return isNone
put(c, f, concrete)
# bug #6526
if result in {isEqual, isSubtype}:
# 'T: Class' is a *better* match than just 'T'
# but 'T: Subclass' is even better:
c.inheritancePenalty = oldInheritancePenalty - c.inheritancePenalty -
100 * ord(result == isEqual)
result = isGeneric
elif a.kind == tyTypeDesc:
# somewhat special typing rule, the following is illegal:
@@ -1770,7 +1868,12 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
if tfWildcard in a.flags:
a.sym.transitionGenericParamToType()
a.flags.excl tfWildcard
else:
elif doBind:
# careful: `trDontDont` (set by `checkGeneric`) is not always respected in this call graph.
# typRel having two different modes (binding and non-binding) can make things harder to
# reason about and maintain. Refactoring typeRel to not be responsible for setting, or
# at least validating, bindings can have multiple benefits. This is debatable. I'm not 100% sure.
# A design that allows a proper complexity analysis of types like `tyOr` would be ideal.
concrete = concreteType(c, a, f)
if concrete == nil:
return isNone
@@ -1783,7 +1886,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
elif x.kind == tyGenericParam:
result = isGeneric
else:
# This is the bound type - can't benifit from these tallies
let
inheritancePenaltyOld = c.inheritancePenalty
result = typeRel(c, x, a, flags) # check if it fits
c.inheritancePenalty = inheritancePenaltyOld
if result > isGeneric: result = isGeneric
of tyStatic:
let prev = PType(idTableGet(c.bindings, f))
@@ -1885,6 +1992,9 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
# fix the expression, so it contains the already instantiated types
if f.n == nil or f.n.kind == nkEmpty: return isGeneric
let reevaluated = tryResolvingStaticExpr(c, f.n)
if reevaluated == nil:
result = isNone
return
case reevaluated.typ.kind
of tyTypeDesc:
result = typeRel(c, a, reevaluated.typ.base, flags)
@@ -1994,7 +2104,9 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
dest = generateTypeInstance(c, m.bindings, arg, dest)
let fdest = typeRel(m, f, dest)
if fdest in {isEqual, isGeneric} and not (dest.kind == tyLent and f.kind in {tyVar}):
markUsed(c, arg.info, c.converters[i])
# can't fully mark used yet, may not be used in final call
incl(c.converters[i].flags, sfUsed)
markOwnerModuleAsUsed(c, c.converters[i])
var s = newSymNode(c.converters[i])
s.typ = c.converters[i].typ
s.info = arg.info
@@ -2042,7 +2154,7 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
if result != nil:
if result.typ == nil: return nil
# bug #13378, ensure we produce a real generic instantiation:
result = c.semExpr(c, call)
result = c.semExpr(c, call, {efNoSem2Check})
# resulting type must be consistent with the other arguments:
var r = typeRel(m, f[0], result.typ)
if r < isGeneric: return nil
@@ -2069,6 +2181,7 @@ template matchesVoidProc(t: PType): bool =
proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
argSemantized, argOrig: PNode): PNode =
result = nil
var
fMaybeStatic = f.skipTypes({tyDistinct})
arg = argSemantized
@@ -2132,28 +2245,33 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
else:
return argSemantized # argOrig
# If r == isBothMetaConvertible then we rerun typeRel.
# bothMetaCounter is for safety to avoid any infinite loop,
# I don't have any example when it is needed.
# lastBindingsLenth is used to check whether m.bindings remains the same,
# because in that case there is no point in continuing.
var bothMetaCounter = 0
var lastBindingsLength = -1
while r == isBothMetaConvertible and
lastBindingsLength != m.bindings.counter and
bothMetaCounter < 100:
lastBindingsLength = m.bindings.counter
inc(bothMetaCounter)
if arg.kind in {nkProcDef, nkFuncDef, nkIteratorDef} + nkLambdaKinds:
result = c.semInferredLambda(c, m.bindings, arg)
elif arg.kind != nkSym:
return nil
else:
let inferred = c.semGenerateInstance(c, arg.sym, m.bindings, arg.info)
result = newSymNode(inferred, arg.info)
inc(m.convMatches)
arg = result
r = typeRel(m, f, arg.typ)
block instantiateGenericRoutine:
# In the case where the matched value is a generic proc, we need to
# fully instantiate it and then rerun typeRel to make sure it matches.
# instantiationCounter is for safety to avoid any infinite loop,
# I don't have any example when it is needed.
# lastBindingCount is used to check whether m.bindings remains the same,
# because in that case there is no point in continuing.
var instantiationCounter = 0
var lastBindingCount = -1
while r in {isBothMetaConvertible, isInferred, isInferredConvertible} and
lastBindingCount != m.bindings.counter and
instantiationCounter < 100:
lastBindingCount = m.bindings.counter
inc(instantiationCounter)
if arg.kind in {nkProcDef, nkFuncDef, nkIteratorDef} + nkLambdaKinds:
result = c.semInferredLambda(c, m.bindings, arg)
elif arg.kind != nkSym:
return nil
elif arg.sym.kind in {skMacro, skTemplate}:
return nil
else:
if arg.sym.ast == nil:
return nil
let inferred = c.semGenerateInstance(c, arg.sym, m.bindings, arg.info)
result = newSymNode(inferred, arg.info)
arg = result
r = typeRel(m, f, arg.typ)
case r
of isConvertible:
@@ -2180,29 +2298,20 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
result = arg
else:
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
of isInferred, isInferredConvertible:
if arg.kind in {nkProcDef, nkFuncDef, nkIteratorDef} + nkLambdaKinds:
result = c.semInferredLambda(c, m.bindings, arg)
elif arg.kind != nkSym:
return nil
elif arg.sym.kind in {skMacro, skTemplate}:
return nil
else:
if arg.sym.ast == nil:
return nil
let inferred = c.semGenerateInstance(c, arg.sym, m.bindings, arg.info)
result = newSymNode(inferred, arg.info)
if r == isInferredConvertible:
inc(m.convMatches)
result = implicitConv(nkHiddenStdConv, f, result, m, c)
else:
inc(m.genericMatches)
of isInferred:
# result should be set in above while loop:
assert result != nil
inc(m.genericMatches)
of isInferredConvertible:
# result should be set in above while loop:
assert result != nil
inc(m.convMatches)
result = implicitConv(nkHiddenStdConv, f, result, m, c)
of isGeneric:
inc(m.genericMatches)
if arg.typ == nil:
result = arg
elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple or
m.inheritancePenalty > oldInheritancePenalty:
elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple or cmpInheritancePenalty(oldInheritancePenalty, m.inheritancePenalty) > 0:
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
elif arg.typ.isEmptyContainer:
result = arg.copyTree
@@ -2210,8 +2319,10 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
else:
result = arg
of isBothMetaConvertible:
# This is the result for the 101th time.
result = nil
# result should be set in above while loop:
assert result != nil
inc(m.convMatches)
result = arg
of isFromIntLit:
# too lazy to introduce another ``*matches`` field, so we conflate
# ``isIntConv`` and ``isIntLit`` here:
@@ -2286,56 +2397,76 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
if arg == nil or arg.kind notin nkSymChoices:
result = paramTypesMatchAux(m, f, a, arg, argOrig)
else:
# CAUTION: The order depends on the used hashing scheme. Thus it is
# incorrect to simply use the first fitting match. However, to implement
# this correctly is inefficient. We have to copy `m` here to be able to
# roll back the side effects of the unification algorithm.
let c = m.c
var
x = newCandidate(c, m.callee)
y = newCandidate(c, m.callee)
z = newCandidate(c, m.callee)
x.calleeSym = m.calleeSym
y.calleeSym = m.calleeSym
z.calleeSym = m.calleeSym
# symbol kinds that don't participate in symchoice type disambiguation:
let matchSet = {low(TSymKind)..high(TSymKind)} - {skModule, skPackage, skType}
var best = -1
for i in 0..<arg.len:
if arg[i].sym.kind in {skProc, skFunc, skMethod, skConverter,
skIterator, skMacro, skTemplate, skEnumField}:
copyCandidate(z, m)
z.callee = arg[i].typ
if tfUnresolved in z.callee.flags: continue
z.calleeSym = arg[i].sym
# XXX this is still all wrong: (T, T) should be 2 generic matches
# and (int, int) 2 exact matches, etc. Essentially you cannot call
# typeRel here and expect things to work!
let r = typeRel(z, f, arg[i].typ)
incMatches(z, r, 2)
if r != isNone:
z.state = csMatch
case x.state
of csEmpty, csNoMatch:
x = z
best = i
of csMatch:
let cmp = cmpCandidates(x, z)
if cmp < 0:
best = i
x = z
elif cmp == 0:
y = z # z is as good as x
result = arg
if x.state == csEmpty:
result = nil
elif y.state == csMatch and cmpCandidates(x, y) == 0:
if x.state != csMatch:
internalError(m.c.graph.config, arg.info, "x.state is not csMatch")
# ambiguous: more than one symbol fits!
# See tsymchoice_for_expr as an example. 'f.kind == tyUntyped' should match
# anyway:
if f.kind in {tyUntyped, tyTyped}: result = arg
else: result = nil
if f.kind in {tyTyped, tyUntyped}:
var
bestScope = -1
counts = 0
for i in 0..<arg.len:
if arg[i].sym.kind in matchSet:
let thisScope = cmpScopes(m.c, arg[i].sym)
if thisScope > bestScope:
best = i
bestScope = thisScope
counts = 0
elif thisScope == bestScope:
inc counts
if best == -1:
result = nil
elif counts > 0:
best = -1
else:
# CAUTION: The order depends on the used hashing scheme. Thus it is
# incorrect to simply use the first fitting match. However, to implement
# this correctly is inefficient. We have to copy `m` here to be able to
# roll back the side effects of the unification algorithm.
let c = m.c
var
x = newCandidate(c, m.callee) # potential "best"
y = newCandidate(c, m.callee) # potential competitor with x
z = newCandidate(c, m.callee) # buffer for copies of m
x.calleeSym = m.calleeSym
y.calleeSym = m.calleeSym
z.calleeSym = m.calleeSym
for i in 0..<arg.len:
if arg[i].sym.kind in matchSet:
copyCandidate(z, m)
z.callee = arg[i].typ
if tfUnresolved in z.callee.flags: continue
z.calleeSym = arg[i].sym
z.calleeScope = cmpScopes(m.c, arg[i].sym)
# XXX this is still all wrong: (T, T) should be 2 generic matches
# and (int, int) 2 exact matches, etc. Essentially you cannot call
# typeRel here and expect things to work!
let r = typeRel(z, f, arg[i].typ)
incMatches(z, r, 2)
if r != isNone:
z.state = csMatch
case x.state
of csEmpty, csNoMatch:
x = z
best = i
of csMatch:
let cmp = cmpCandidates(x, z, isFormal=false)
if cmp < 0:
best = i
x = z
elif cmp == 0:
y = z # z is as good as x
if x.state == csEmpty:
result = nil
elif y.state == csMatch and cmpCandidates(x, y, isFormal=false) == 0:
if x.state != csMatch:
internalError(m.c.graph.config, arg.info, "x.state is not csMatch")
result = nil
if best > -1 and result != nil:
# only one valid interpretation found:
markUsed(m.c, arg.info, arg[best].sym)
onUse(arg.info, arg[best].sym)
@@ -2395,7 +2526,7 @@ proc arrayConstr(c: PContext, n: PNode): PType =
result = newTypeS(tyArray, c)
rawAddSon(result, makeRangeType(c, 0, 0, n.info))
addSonSkipIntLit(result, skipTypes(n.typ,
{tyGenericInst, tyVar, tyLent, tyOrdinal}), c.idgen)
{tyVar, tyLent, tyOrdinal}), c.idgen)
proc arrayConstr(c: PContext, info: TLineInfo): PType =
result = newTypeS(tyArray, c)
@@ -2623,12 +2754,6 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m: var TCandidate, marker: var Int
m.firstMismatch.arg = a
m.firstMismatch.formal = formal
proc semFinishOperands*(c: PContext, n: PNode) =
# this needs to be called to ensure that after overloading resolution every
# argument has been sem'checked:
for i in 1..<n.len:
n[i] = prepareOperand(c, n[i])
proc partialMatch*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
# for 'suggest' support:
var marker = initIntSet()

View File

@@ -433,10 +433,9 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
typ.paddingAtEnd = typ.base.paddingAtEnd
of tyForward:
# is this really illegal recursion, or maybe just unknown?
typ.size = szIllegalRecursion
typ.align = szIllegalRecursion
typ.paddingAtEnd = szIllegalRecursion
typ.size = szUnknownSize
typ.align = szUnknownSize
typ.paddingAtEnd = szUnknownSize
of tyStatic:
if typ.n != nil:

View File

@@ -11,7 +11,7 @@ type
Mapping = object
## Mapping refers to a line in the JS output.
## It is made up of segments which refer to the tokens in the line
case inSource: bool # Whether the line in JS has Nim equivilant
case inSource: bool # Whether the line in JS has Nim equivalent
of true:
file: int # Index into files list
line: int # 0 indexed line of code in the Nim source

View File

@@ -109,6 +109,16 @@ stmtList:
"""
proc castToVoidPointer(g: ModuleGraph, n: PNode, fvField: PNode): PNode =
if g.config.backend == backendCpp:
result = fvField
else:
let ptrType = getSysType(g, n.info, tyPointer)
result = newNodeI(nkCast, fvField.info)
result.add newNodeI(nkEmpty, fvField.info)
result.add fvField
result.typ = ptrType
proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
varSection, varInit, call, barrier, fv: PNode;
idgen: IdGenerator;
@@ -156,8 +166,9 @@ proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
if barrier == nil:
# by now 'fv' is shared and thus might have beeen overwritten! we need
# to use the thread-local view instead:
let castExpr = castToVoidPointer(g, f, threadLocalProm.newSymNode)
body.add callCodegenProc(g, "nimFlowVarSignal", threadLocalProm.info,
threadLocalProm.newSymNode)
castExpr)
else:
body.add call
if barrier != nil:
@@ -413,7 +424,8 @@ proc wrapProcForSpawn*(g: ModuleGraph; idgen: IdGenerator; owner: PSym; spawnExp
# create flowVar:
result.add newFastAsgnStmt(fvField, callProc(spawnExpr[^1]))
if barrier == nil:
result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField.info, fvField)
let castExpr = castToVoidPointer(g, n, fvField)
result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField.info, castExpr)
elif spawnKind == srByVar:
var field = newSym(skField, getIdent(g.cache, "fv"), idgen, owner, n.info, g.config.options)

View File

@@ -81,7 +81,16 @@ proc cmpSuggestions(a, b: Suggest): int =
# independent of hashing order:
result = cmp(a.name[], b.name[])
proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int =
proc scanForTrailingAsterisk(line: string, start: int): int =
result = 0
while start+result < line.len and line[start+result] in {' ', '\t'}:
inc result
if start+result < line.len and line[start+result] == '*':
inc result
else:
result = 0
proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo; skipTrailingAsterisk: bool = false): int =
let
line = sourceLine(conf, info)
column = toColumn(info)
@@ -103,8 +112,10 @@ proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int
result = 0
elif ident[0] in linter.Letters and ident[^1] != '=':
result = identLen(line, column)
if cmpIgnoreStyle(line[column..column + result - 1], ident) != 0:
if cmpIgnoreStyle(line[column..column + result - 1], ident[0..min(result-1,len(ident)-1)]) != 0:
result = 0
if skipTrailingAsterisk and result > 0:
result += scanForTrailingAsterisk(line, column + result)
else:
var sourceIdent: string
result = parseWhile(line, sourceIdent,
@@ -154,7 +165,10 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info
result.qualifiedPath.add(s.name.s)
if s.typ != nil:
result.forth = typeToString(s.typ)
if section == ideInlayHints:
result.forth = typeToString(s.typ, preferInlayHint)
else:
result.forth = typeToString(s.typ, preferInferredEffects)
else:
result.forth = ""
when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
@@ -173,58 +187,90 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info
result.filePath = toFullPath(g.config, infox)
result.line = toLinenumber(infox)
result.column = toColumn(infox)
result.tokenLen = if section != ideHighlight:
result.tokenLen = if section notin {ideHighlight, ideInlayHints}:
s.name.s.len
else:
getTokenLenFromSource(g.config, s.name.s, infox)
getTokenLenFromSource(g.config, s.name.s, infox, section == ideInlayHints)
result.version = g.config.suggestVersion
result.endLine = endLine
result.endCol = endCol
proc `$`*(suggest: Suggest): string =
result = $suggest.section
proc `$`*(suggest: SuggestInlayHint): string =
result = $suggest.kind
result.add(sep)
if suggest.section == ideHighlight:
if suggest.symkind.TSymKind == skVar and suggest.isGlobal:
result.add("skGlobalVar")
elif suggest.symkind.TSymKind == skLet and suggest.isGlobal:
result.add("skGlobalLet")
result.add($suggest.line)
result.add(sep)
result.add($suggest.column)
result.add(sep)
result.add(suggest.label)
result.add(sep)
result.add($suggest.paddingLeft)
result.add(sep)
result.add($suggest.paddingRight)
result.add(sep)
result.add($suggest.allowInsert)
result.add(sep)
result.add(suggest.tooltip)
proc `$`*(suggest: Suggest): string =
if suggest.section == ideInlayHints:
result = $suggest.inlayHintInfo
else:
result = $suggest.section
result.add(sep)
if suggest.section == ideHighlight:
if suggest.symkind.TSymKind == skVar and suggest.isGlobal:
result.add("skGlobalVar")
elif suggest.symkind.TSymKind == skLet and suggest.isGlobal:
result.add("skGlobalLet")
else:
result.add($suggest.symkind.TSymKind)
result.add(sep)
result.add($suggest.line)
result.add(sep)
result.add($suggest.column)
result.add(sep)
result.add($suggest.tokenLen)
else:
result.add($suggest.symkind.TSymKind)
result.add(sep)
result.add($suggest.line)
result.add(sep)
result.add($suggest.column)
result.add(sep)
result.add($suggest.tokenLen)
else:
result.add($suggest.symkind.TSymKind)
result.add(sep)
if suggest.qualifiedPath.len != 0:
result.add(suggest.qualifiedPath.join("."))
result.add(sep)
result.add(suggest.forth)
result.add(sep)
result.add(suggest.filePath)
result.add(sep)
result.add($suggest.line)
result.add(sep)
result.add($suggest.column)
result.add(sep)
when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
result.add(suggest.doc.escape)
if suggest.version == 0 or suggest.version == 3:
result.add(sep)
result.add($suggest.quality)
if suggest.section == ideSug:
if suggest.qualifiedPath.len != 0:
result.add(suggest.qualifiedPath.join("."))
result.add(sep)
result.add(suggest.forth)
result.add(sep)
result.add(suggest.filePath)
result.add(sep)
result.add($suggest.line)
result.add(sep)
result.add($suggest.column)
result.add(sep)
when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
result.add(suggest.doc.escape)
if suggest.version == 0 or suggest.version == 3:
result.add(sep)
result.add($suggest.prefix)
result.add($suggest.quality)
if suggest.section == ideSug:
result.add(sep)
result.add($suggest.prefix)
if (suggest.version == 3 and suggest.section in {ideOutline, ideExpand}):
result.add(sep)
result.add($suggest.endLine)
result.add(sep)
result.add($suggest.endCol)
if (suggest.version == 3 and suggest.section in {ideOutline, ideExpand}):
result.add(sep)
result.add($suggest.endLine)
result.add(sep)
result.add($suggest.endCol)
proc suggestToSuggestInlayHint*(sug: Suggest): SuggestInlayHint =
SuggestInlayHint(
kind: sihkType,
line: sug.line,
column: sug.column + sug.tokenLen,
label: ": " & sug.forth,
paddingLeft: false,
paddingRight: false,
allowInsert: true,
tooltip: ""
)
proc suggestResult*(conf: ConfigRef; s: Suggest) =
if not isNil(conf.suggestionResultHook):
@@ -507,7 +553,7 @@ proc findDefinition(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym
if s.isNil: return
if isTracked(info, g.config.m.trackPos, s.name.s.len) or (s == usageSym and sfForward notin s.flags):
suggestResult(g.config, symToSuggest(g, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0, useSuppliedInfo = s == usageSym))
if sfForward notin s.flags and g.config.suggestVersion != 3:
if sfForward notin s.flags and g.config.suggestVersion < 3:
suggestQuit()
else:
usageSym = s
@@ -522,7 +568,7 @@ proc suggestSym*(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym; i
## misnamed: should be 'symDeclared'
let conf = g.config
when defined(nimsuggest):
g.suggestSymbols.mgetOrPut(info.fileIndex, @[]).add SymInfoPair(sym: s, info: info)
g.suggestSymbols.mgetOrPut(info.fileIndex, @[]).add SymInfoPair(sym: s, info: info, isDecl: isDecl)
if conf.suggestVersion == 0:
if s.allUsages.len == 0:
@@ -596,7 +642,7 @@ proc markOwnerModuleAsUsed(c: PContext; s: PSym) =
else:
inc i
proc markUsed(c: PContext; info: TLineInfo; s: PSym) =
proc markUsed(c: PContext; info: TLineInfo; s: PSym; checkStyle = true) =
let conf = c.config
incl(s.flags, sfUsed)
if s.kind == skEnumField and s.owner != nil:
@@ -613,7 +659,8 @@ proc markUsed(c: PContext; info: TLineInfo; s: PSym) =
if sfError in s.flags: userError(conf, info, s)
when defined(nimsuggest):
suggestSym(c.graph, info, s, c.graph.usageSym, false)
styleCheckUse(c, info, s)
if checkStyle:
styleCheckUse(c, info, s)
markOwnerModuleAsUsed(c, s)
proc safeSemExpr*(c: PContext, n: PNode): PNode =
@@ -711,7 +758,7 @@ proc suggestSentinel*(c: PContext) =
when defined(nimsuggest):
proc onDef(graph: ModuleGraph, s: PSym, info: TLineInfo) =
if graph.config.suggestVersion == 3 and info.exactEquals(s.info):
if graph.config.suggestVersion >= 3 and info.exactEquals(s.info):
suggestSym(graph, info, s, graph.usageSym)
template getPContext(): untyped =

View File

@@ -57,7 +57,7 @@ proc parsePipe(filename: AbsoluteFile, inputStream: PLLStream; cache: IdentCache
else:
inc(i, 2)
while i < line.len and line[i] in Whitespace: inc(i)
var p: Parser
var p: Parser = default(Parser)
openParser(p, filename, llStreamOpen(substr(line, i)), cache, config)
result = parseAll(p)
closeParser(p)

View File

@@ -100,12 +100,19 @@ proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
else:
result = newSymNode(r)
proc transform(c: PTransf, n: PNode): PNode
proc transform(c: PTransf, n: PNode, noConstFold = false): PNode
proc transformSons(c: PTransf, n: PNode): PNode =
proc transformSons(c: PTransf, n: PNode, noConstFold = false): PNode =
result = newTransNode(n)
for i in 0..<n.len:
result[i] = transform(c, n[i])
result[i] = transform(c, n[i], noConstFold)
proc transformSonsAfterType(c: PTransf, n: PNode, noConstFold = false): PNode =
result = newTransNode(n)
assert n.len != 0
result[0] = copyTree(n[0])
for i in 1..<n.len:
result[i] = transform(c, n[i], noConstFold)
proc newAsgnStmt(c: PTransf, kind: TNodeKind, le: PNode, ri: PNode; isFirstWrite: bool): PNode =
result = newTransNode(kind, ri.info, 2)
@@ -452,6 +459,14 @@ proc transformYield(c: PTransf, n: PNode): PNode =
let rhs = transform(c, e)
result.add(asgnTo(lhs, rhs))
# bug #23536; note that the info of forLoopBody should't change
for idx in 0 ..< result.len:
var changeNode = result[idx]
changeNode.info = c.transCon.forStmt.info
for i, child in changeNode:
child.info = changeNode.info
inc(c.transCon.yieldStmts)
if c.transCon.yieldStmts <= 1:
# common case
@@ -462,15 +477,10 @@ proc transformYield(c: PTransf, n: PNode): PNode =
result.add(introduceNewLocalVars(c, c.transCon.forLoopBody))
c.isIntroducingNewLocalVars = false
for idx in 0 ..< result.len:
var changeNode = result[idx]
changeNode.info = c.transCon.forStmt.info
for i, child in changeNode:
child.info = changeNode.info
proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds): PNode =
result = transformSons(c, n)
if c.graph.config.backend == backendCpp or sfCompileToCpp in c.module.flags: return
proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds, isAddr = false): PNode =
result = transformSons(c, n, noConstFold = isAddr)
# inlining of 'var openarray' iterators; bug #19977
if n.typ.kind != tyOpenArray and (c.graph.config.backend == backendCpp or sfCompileToCpp in c.module.flags): return
var n = result
case n[0].kind
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
@@ -494,7 +504,17 @@ proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds): PNode =
elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind, c.idgen)
else:
if n[0].kind in kinds:
if n[0].kind in kinds and
not (n[0][0].kind == nkSym and n[0][0].sym.kind == skForVar and
n[0][0].typ.skipTypes(abstractVar).kind == tyTuple
) and not (n[0][0].kind == nkSym and n[0][0].sym.kind == skParam and
n.typ.kind == tyVar and
n.typ.skipTypes(abstractVar).kind == tyOpenArray and
n[0][0].typ.skipTypes(abstractVar).kind == tyString) and
not (isAddr and n.typ.kind == tyVar and n[0][0].typ.kind == tyRef and
n[0][0].kind == nkObjConstr)
: # elimination is harmful to `for tuple unpack` because of newTupleAccess
# it is also harmful to openArrayLoc (var openArray) for strings
# addr ( deref ( x )) --> x
result = n[0][0]
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
@@ -822,9 +842,18 @@ proc transformArrayAccess(c: PTransf, n: PNode): PNode =
if n[0].kind == nkSym and n[0].sym.kind == skType:
result = n
else:
result = newTransNode(n)
for i in 0..<n.len:
result[i] = transform(c, skipConv(n[i]))
result = transformSons(c, n)
if n.len >= 2 and result[1].kind in {nkChckRange, nkChckRange64} and
n[1].kind in {nkHiddenStdConv, nkHiddenSubConv}:
# implicit conversion, was transformed into range check
# remove in favor of index check if conversion to array index type
# has to be done here because the array index type needs to be relaxed
# i.e. a uint32 index can implicitly convert to range[0..3] but not int
let arr = skipTypes(n[0].typ, abstractVarRange)
if arr.kind == tyArray and
firstOrd(c.graph.config, arr) == getOrdValue(result[1][1]) and
lastOrd(c.graph.config, arr) == getOrdValue(result[1][2]):
result[1] = result[1].skipConv
proc getMergeOp(n: PNode): PSym =
case n.kind
@@ -872,10 +901,6 @@ proc transformCall(c: PTransf, n: PNode): PNode =
inc(j)
result.add(a)
if result.len == 2: result = result[1]
elif magic == mAddr:
result = newTransNode(nkAddr, n, 1)
result[0] = n[1]
result = transformAddrDeref(c, result, {nkDerefExpr, nkHiddenDeref})
elif magic in {mNBindSym, mTypeOf, mRunnableExamples}:
# for bindSym(myconst) we MUST NOT perform constant folding:
result = n
@@ -970,7 +995,7 @@ proc transformDerefBlock(c: PTransf, n: PNode): PNode =
result[i] = e0[i]
result[e0.len-1] = newTreeIT(nkHiddenDeref, n.info, n.typ, e0[e0.len-1])
proc transform(c: PTransf, n: PNode): PNode =
proc transform(c: PTransf, n: PNode, noConstFold = false): PNode =
when false:
var oldDeferAnchor: PNode
if n.kind in {nkElifBranch, nkOfBranch, nkExceptBranch, nkElifExpr,
@@ -1036,10 +1061,8 @@ proc transform(c: PTransf, n: PNode): PNode =
of nkBreakStmt: result = transformBreak(c, n)
of nkCallKinds:
result = transformCall(c, n)
of nkHiddenAddr:
result = transformAddrDeref(c, n, {nkHiddenDeref})
of nkAddr:
result = transformAddrDeref(c, n, {nkDerefExpr, nkHiddenDeref})
of nkAddr, nkHiddenAddr:
result = transformAddrDeref(c, n, {nkDerefExpr, nkHiddenDeref}, isAddr = true)
of nkDerefExpr:
result = transformAddrDeref(c, n, {nkAddr, nkHiddenAddr})
of nkHiddenDeref:
@@ -1051,6 +1074,9 @@ proc transform(c: PTransf, n: PNode): PNode =
result = transformAddrDeref(c, n, {nkAddr, nkHiddenAddr})
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
result = transformConv(c, n)
of nkObjConstr, nkCast:
# don't try to transform type node
result = transformSonsAfterType(c, n)
of nkDiscardStmt:
result = n
if n[0].kind != nkEmpty:
@@ -1119,7 +1145,7 @@ proc transform(c: PTransf, n: PNode): PNode =
let exprIsPointerCast = n.kind in {nkCast, nkConv, nkHiddenStdConv} and
n.typ != nil and
n.typ.kind == tyPointer
if not exprIsPointerCast:
if not exprIsPointerCast and not noConstFold:
var cnst = getConstExpr(c.module, result, c.idgen, c.graph)
# we inline constants if they are not complex constants:
if cnst != nil and not dontInlineConstant(n, cnst):

View File

@@ -133,10 +133,12 @@ proc whichPragma*(n: PNode): TSpecialWord =
case key.kind
of nkIdent: result = whichKeyword(key.ident)
of nkSym: result = whichKeyword(key.sym.name)
of nkCast: result = wCast
of nkCast: return wCast
of nkClosedSymChoice, nkOpenSymChoice:
result = whichPragma(key[0])
else: result = wInvalid
return whichPragma(key[0])
else: return wInvalid
if result in nonPragmaWordsLow..nonPragmaWordsHigh:
result = wInvalid
proc isNoSideEffectPragma*(n: PNode): bool =
var k = whichPragma(n)
@@ -211,8 +213,7 @@ proc stupidStmtListExpr*(n: PNode): bool =
proc dontInlineConstant*(orig, cnst: PNode): bool {.inline.} =
# symbols that expand to a complex constant (array, etc.) should not be
# inlined, unless it's the empty array:
result = orig.kind != cnst.kind and
cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket, nkObjConstr} and
result = cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket, nkObjConstr} and
cnst.len > ord(cnst.kind == nkObjConstr)
proc isRunnableExamples*(n: PNode): bool =

View File

@@ -26,6 +26,8 @@ type
taIsTemplateOrMacro
taProcContextIsNotMacro
taIsCastable
taIsDefaultField
taVoid # only allow direct void fields of objects/tuples
TTypeAllowedFlags* = set[TTypeAllowedFlag]
@@ -57,6 +59,8 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
if typ == nil: return nil
if containsOrIncl(marker, typ.id): return nil
var t = skipTypes(typ, abstractInst-{tyTypeDesc, tySink})
let flags = if t.kind == tyVoid: flags else: flags-{taVoid}
case t.kind
of tyVar, tyLent:
if kind in {skProc, skFunc, skConst} and (views notin c.features):
@@ -112,7 +116,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
of tyStatic:
if kind notin {skParam}: result = t
of tyVoid:
if taField notin flags: result = t
if taVoid notin flags: result = t
of tyTypeClasses:
if tfGenericTypeParam in t.flags or taConcept in flags: #or taField notin flags:
discard
@@ -170,7 +174,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
elif kind in {skVar, skLet}:
result = t[1]
of tyRef:
if kind == skConst: result = t
if kind == skConst and taIsDefaultField notin flags: result = t
else: result = typeAllowedAux(marker, t.lastSon, kind, c, flags+{taHeap})
of tyPtr:
result = typeAllowedAux(marker, t.lastSon, kind, c, flags+{taHeap})
@@ -180,10 +184,10 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
if result != nil: break
of tyObject, tyTuple:
if kind in {skProc, skFunc, skConst} and
t.kind == tyObject and t[0] != nil:
t.kind == tyObject and t[0] != nil and taIsDefaultField notin flags:
result = t
else:
let flags = flags+{taField}
let flags = flags+{taField, taVoid}
for i in 0..<t.len:
result = typeAllowedAux(marker, t[i], kind, c, flags)
if result != nil: break

View File

@@ -11,7 +11,7 @@
import
intsets, ast, astalgo, trees, msgs, strutils, platform, renderer, options,
lineinfos, int128, modulegraphs, astmsgs
lineinfos, int128, modulegraphs, astmsgs, wordrecg
when defined(nimPreviewSlimSystem):
import std/[assertions, formatfloat]
@@ -28,6 +28,8 @@ type
preferMixed,
# most useful, shows: symbol + resolved symbols if it differs, e.g.:
# tuple[a: MyInt{int}, b: float]
preferInlayHint,
preferInferredEffects,
TTypeRelation* = enum # order is important!
isNone, isConvertible,
@@ -62,8 +64,6 @@ proc addTypeDeclVerboseMaybe*(result: var string, conf: ConfigRef; typ: PType) =
template `$`*(typ: PType): string = typeToString(typ)
proc base*(t: PType): PType =
result = t[0]
# ------------------- type iterator: ----------------------------------------
type
@@ -117,7 +117,7 @@ proc isPureObject*(typ: PType): bool =
proc isUnsigned*(t: PType): bool =
t.skipTypes(abstractInst).kind in {tyChar, tyUInt..tyUInt64}
proc getOrdValue*(n: PNode; onError = high(Int128)): Int128 =
proc getOrdValueAux*(n: PNode, err: var bool): Int128 =
var k = n.kind
if n.typ != nil and n.typ.skipTypes(abstractInst).kind in {tyChar, tyUInt..tyUInt64}:
k = nkUIntLit
@@ -133,13 +133,22 @@ proc getOrdValue*(n: PNode; onError = high(Int128)): Int128 =
toInt128(n.intVal)
of nkNilLit:
int128.Zero
of nkHiddenStdConv: getOrdValue(n[1], onError)
of nkHiddenStdConv:
getOrdValueAux(n[1], err)
else:
# XXX: The idea behind the introduction of int128 was to finally
# have all calculations numerically far away from any
# overflows. This command just introduces such overflows and
# should therefore really be revisited.
onError
err = true
int128.Zero
proc getOrdValue*(n: PNode): Int128 =
var err: bool = false
result = getOrdValueAux(n, err)
#assert err == false
proc getOrdValue*(n: PNode, onError: Int128): Int128 =
var err = false
result = getOrdValueAux(n, err)
if err:
result = onError
proc getFloatValue*(n: PNode): BiggestFloat =
case n.kind
@@ -508,7 +517,7 @@ const
"void", "iterable"]
const preferToResolveSymbols = {preferName, preferTypeName, preferModuleInfo,
preferGenericArg, preferResolved, preferMixed}
preferGenericArg, preferResolved, preferMixed, preferInlayHint, preferInferredEffects}
template bindConcreteTypeToUserTypeClass*(tc, concrete: PType) =
tc.add concrete
@@ -542,7 +551,10 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
if prefer in preferToResolveSymbols and t.sym != nil and
sfAnon notin t.sym.flags and t.kind != tySequence:
if t.kind == tyInt and isIntLit(t):
result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
if prefer == preferInlayHint:
result = t.sym.name.s
else:
result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
elif t.kind == tyAlias and t[0].kind != tyAlias:
result = typeToString(t[0])
elif prefer in {preferResolved, preferMixed}:
@@ -558,7 +570,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
result = t.sym.name.s
if prefer == preferMixed and result != t.sym.name.s:
result = t.sym.name.s & "{" & result & "}"
elif prefer in {preferName, preferTypeName} or t.sym.owner.isNil:
elif prefer in {preferName, preferTypeName, preferInlayHint, preferInferredEffects} or t.sym.owner.isNil:
# note: should probably be: {preferName, preferTypeName, preferGenericArg}
result = t.sym.name.s
if t.kind == tyGenericParam and t.len > 0:
@@ -577,8 +589,11 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
if not isIntLit(t) or prefer == preferExported:
result = typeToStr[t.kind]
else:
if prefer == preferGenericArg:
case prefer:
of preferGenericArg:
result = $t.n.intVal
of preferInlayHint:
result = "int"
else:
result = "int literal(" & $t.n.intVal & ")"
of tyGenericInst, tyGenericInvocation:
@@ -751,12 +766,35 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
result.add(')')
if t.len > 0 and t[0] != nil: result.add(": " & typeToString(t[0]))
var prag = if t.callConv == ccNimCall and tfExplicitCallConv notin t.flags: "" else: $t.callConv
var hasImplicitRaises = false
if not isNil(t.owner) and not isNil(t.owner.ast) and (t.owner.ast.len - 1) >= pragmasPos:
let pragmasNode = t.owner.ast[pragmasPos]
let raisesSpec = effectSpec(pragmasNode, wRaises)
if not isNil(raisesSpec):
addSep(prag)
prag.add("raises: ")
prag.add($raisesSpec)
hasImplicitRaises = true
if tfNoSideEffect in t.flags:
addSep(prag)
prag.add("noSideEffect")
if tfThread in t.flags:
addSep(prag)
prag.add("gcsafe")
if not hasImplicitRaises and prefer == preferInferredEffects and not isNil(t.owner) and not isNil(t.owner.typ) and not isNil(t.owner.typ.n) and (t.owner.typ.n.len > 0):
let effects = t.owner.typ.n[0]
if effects.kind == nkEffectList and effects.len == effectListLen:
var inferredRaisesStr = ""
let effs = effects[exceptionEffects]
if not isNil(effs):
for eff in items(effs):
if not isNil(eff):
addSep(inferredRaisesStr)
inferredRaisesStr.add($eff.typ)
addSep(prag)
prag.add("raises: <inferred> [")
prag.add(inferredRaisesStr)
prag.add("]")
if prag.len != 0: result.add("{." & prag & ".}")
of tyVarargs:
result = typeToStr[t.kind] % typeToString(t[0])
@@ -807,11 +845,11 @@ proc firstOrd*(conf: ConfigRef; t: PType): Int128 =
result = firstOrd(conf, lastSon(t))
of tyOrdinal:
if t.len > 0: result = firstOrd(conf, lastSon(t))
else: internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')')
else: fatal(conf, unknownLineInfo, "invalid kind for firstOrd(" & $t.kind & ')')
of tyUncheckedArray, tyCstring:
result = Zero
else:
internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')')
fatal(conf, unknownLineInfo, "invalid kind for firstOrd(" & $t.kind & ')')
result = Zero
proc firstFloat*(t: PType): BiggestFloat =
@@ -895,11 +933,11 @@ proc lastOrd*(conf: ConfigRef; t: PType): Int128 =
of tyProxy: result = Zero
of tyOrdinal:
if t.len > 0: result = lastOrd(conf, lastSon(t))
else: internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')')
else: fatal(conf, unknownLineInfo, "invalid kind for lastOrd(" & $t.kind & ')')
of tyUncheckedArray:
result = Zero
else:
internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')')
fatal(conf, unknownLineInfo, "invalid kind for lastOrd(" & $t.kind & ')')
result = Zero
proc lastFloat*(t: PType): BiggestFloat =
@@ -960,6 +998,7 @@ type
ExactGcSafety
AllowCommonBase
PickyCAliases # be picky about the distinction between 'cint' and 'int32'
IgnoreFlags # used for borrowed functions and methods; ignores the tfVarIsPtr flag
TTypeCmpFlags* = set[TTypeCmpFlag]
@@ -1153,6 +1192,13 @@ proc sameChildrenAux(a, b: PType, c: var TSameTypeClosure): bool =
proc isGenericAlias*(t: PType): bool =
return t.kind == tyGenericInst and t.lastSon.kind == tyGenericInst
proc genericAliasDepth*(t: PType): int =
result = 0
var it = t
while it.isGenericAlias:
it = it.lastSon
inc result
proc skipGenericAlias*(t: PType): PType =
return if t.isGenericAlias: t.lastSon else: t
@@ -1172,24 +1218,24 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
if containsOrIncl(c, a, b): return true
if x == y: return true
var a = skipTypes(x, {tyGenericInst, tyAlias})
var a = skipTypes(x, {tyAlias})
while a.kind == tyUserTypeClass and tfResolved in a.flags:
a = skipTypes(a[^1], {tyGenericInst, tyAlias})
var b = skipTypes(y, {tyGenericInst, tyAlias})
a = skipTypes(a[^1], {tyAlias})
var b = skipTypes(y, {tyAlias})
while b.kind == tyUserTypeClass and tfResolved in b.flags:
b = skipTypes(b[^1], {tyGenericInst, tyAlias})
b = skipTypes(b[^1], {tyAlias})
assert(a != nil)
assert(b != nil)
if a.kind != b.kind:
case c.cmp
of dcEq: return false
of dcEqIgnoreDistinct:
a = a.skipTypes({tyDistinct, tyGenericInst})
b = b.skipTypes({tyDistinct, tyGenericInst})
if a.kind != b.kind: return false
of dcEqOrDistinctOf:
a = a.skipTypes({tyDistinct, tyGenericInst})
if a.kind != b.kind: return false
case c.cmp
of dcEq:
if a.kind != b.kind: return false
of dcEqIgnoreDistinct:
a = a.skipTypes({tyDistinct, tyGenericInst})
b = b.skipTypes({tyDistinct, tyGenericInst})
if a.kind != b.kind: return false
of dcEqOrDistinctOf:
a = a.skipTypes({tyDistinct, tyGenericInst})
if a.kind != b.kind: return false
#[
The following code should not run in the case either side is an generic alias,
@@ -1197,11 +1243,12 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
objects ie `type A[T] = SomeObject`
]#
# this is required by tunique_type but makes no sense really:
if tyDistinct notin {x.kind, y.kind} and x.kind == tyGenericInst and IgnoreTupleFields notin c.flags:
if c.cmp == dcEq and x.kind == tyGenericInst and
IgnoreTupleFields notin c.flags and tyDistinct != y.kind:
let
lhs = x.skipGenericAlias
rhs = y.skipGenericAlias
if rhs.kind != tyGenericInst or lhs.base != rhs.base:
if rhs.kind != tyGenericInst or lhs.base != rhs.base or rhs.kidsLen != lhs.kidsLen:
return false
for i in 1..<lhs.len - 1:
let ff = rhs[i]
@@ -1274,7 +1321,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
cycleCheck()
if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n
result = sameChildrenAux(a, b, c)
if result:
if result and IgnoreFlags notin c.flags:
if IgnoreTupleFields in c.flags:
result = a.flags * {tfVarIsPtr, tfIsOutParam} == b.flags * {tfVarIsPtr, tfIsOutParam}
else:
@@ -1289,9 +1336,17 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
result = sameTypeOrNilAux(a[0], b[0], c) and
sameValue(a.n[0], b.n[0]) and
sameValue(a.n[1], b.n[1])
of tyGenericInst, tyAlias, tyInferred, tyIterable:
of tyAlias, tyInferred, tyIterable:
cycleCheck()
result = sameTypeAux(a.lastSon, b.lastSon, c)
of tyGenericInst:
# BUG #23445
# The type system must distinguish between `T[int] = object #[empty]#`
# and `T[float] = object #[empty]#`!
cycleCheck()
for ff, aa in underspecifiedPairs(a, b, 1, -1):
if not sameTypeAux(ff, aa, c): return false
result = sameTypeAux(a.skipModifier, b.skipModifier, c)
of tyNone: result = false
of tyConcept:
result = exprStructuralEquivalent(a.n, b.n)
@@ -1370,6 +1425,17 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
a = a[i]
result = a.kind == last
proc lacksMTypeField*(typ: PType): bool {.inline.} =
## Returns true if the type is an object that lacks a m_type field.
## It doesn't check base classes.
(typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags
proc isObjLackingTypeField*(typ: PType): bool {.inline.} =
## Returns true if the type is an object that lacks a type field.
## Object types that store type headers are not final or pure and
## have inheritable root types, which are not pure, neither.
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
(typ.baseClass == nil) or isPureObject(typ))
include sizealignoffsetimpl
@@ -1812,6 +1878,3 @@ proc isCharArrayPtr*(t: PType; allowPointerToChar: bool): bool =
result = allowPointerToChar
else:
discard
proc lacksMTypeField*(typ: PType): bool {.inline.} =
(typ.sym != nil and sfPure in typ.sym.flags) or tfFinal in typ.flags

View File

@@ -431,11 +431,15 @@ proc destMightOwn(c: var Partitions; dest: var VarIndex; n: PNode) =
of nkIfStmt, nkIfExpr:
for i in 0..<n.len:
inc c.inConditional
destMightOwn(c, dest, n[i].lastSon)
dec c.inConditional
of nkCaseStmt:
for i in 1..<n.len:
inc c.inConditional
destMightOwn(c, dest, n[i].lastSon)
dec c.inConditional
of nkStmtList, nkStmtListExpr:
if n.len > 0:
@@ -488,8 +492,17 @@ proc destMightOwn(c: var Partitions; dest: var VarIndex; n: PNode) =
# we know the result is derived from the first argument:
var roots: seq[(PSym, int)]
allRoots(n[1], roots, RootEscapes)
for r in roots:
connect(c, dest.sym, r[0], n[1].info)
if roots.len == 0 and c.inConditional > 0:
# when in a conditional expression,
# to ensure that the first argument isn't outlived
# by the lvalue, we need find the root, otherwise
# it is probably a local temporary
# (e.g. a return value from a call),
# we should prevent cursorfication
dest.flags.incl preventCursor
else:
for r in roots:
connect(c, dest.sym, r[0], n[1].info)
else:
let magic = if n[0].kind == nkSym: n[0].sym.magic else: mNone
@@ -820,6 +833,10 @@ proc computeLiveRanges(c: var Partitions; n: PNode) =
registerVariable(c, child[i])
#deps(c, child[i], last)
if c.inLoop > 0 and child[0].kind == nkSym: # bug #22787
let vid = variableId(c, child[0].sym)
if child[^1].kind != nkEmpty:
markAsReassigned(c, vid)
of nkAsgn, nkFastAsgn, nkSinkAsgn:
computeLiveRanges(c, n[0])
computeLiveRanges(c, n[1])
@@ -979,7 +996,9 @@ proc computeCursors*(s: PSym; n: PNode; g: ModuleGraph) =
if v.flags * {ownsData, preventCursor, isConditionallyReassigned} == {} and
v.sym.kind notin {skParam, skResult} and
v.sym.flags * {sfThread, sfGlobal} == {} and hasDestructor(v.sym.typ) and
v.sym.typ.skipTypes({tyGenericInst, tyAlias}).kind != tyOwned:
v.sym.typ.skipTypes({tyGenericInst, tyAlias}).kind != tyOwned and
(getAttachedOp(g, v.sym.typ, attachedAsgn) == nil or
sfError notin getAttachedOp(g, v.sym.typ, attachedAsgn).flags):
let rid = root(par, i)
if par.s[rid].con.kind == isRootOf and dangerousMutation(par.graphs[par.s[rid].con.graphIndex], par.s[i]):
discard "cannot cursor into a graph that is mutated"

View File

@@ -12,7 +12,7 @@
import semmacrosanity
import
std/[strutils, tables, parseutils],
std/[strutils, tables, intsets, parseutils],
msgs, vmdef, vmgen, nimsets, types,
parser, vmdeps, idents, trees, renderer, options, transf,
gorgeimpl, lineinfos, btrees, macrocacheimpl,
@@ -811,6 +811,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
# a[b] = c
decodeBC(rkNode)
let idx = regs[rb].intVal.int
assert regs[ra].kind == rkNode
let arr = regs[ra].node
case arr.kind
of nkTupleConstr: # refer to `opcSlice`
@@ -824,7 +825,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of nkStrKinds:
src.strVal[int(realIndex)] = char(regs[rc].intVal)
of nkBracket:
src[int(realIndex)] = regs[rc].node
if regs[rc].kind == rkInt:
src[int(realIndex)] = newIntNode(nkIntLit, regs[rc].intVal)
else:
assert regs[rc].kind == rkNode
src[int(realIndex)] = regs[rc].node
else:
stackTrace(c, tos, pc, "opcWrArr internal error")
else:
@@ -1015,7 +1020,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcLenCstring:
decodeBImm(rkInt)
assert regs[rb].kind == rkNode
regs[ra].intVal = regs[rb].node.strVal.cstring.len - imm
if regs[rb].node.kind == nkNilLit:
regs[ra].intVal = -imm
else:
regs[ra].intVal = regs[rb].node.strVal.cstring.len - imm
of opcIncl:
decodeB(rkNode)
let b = regs[rb].regToNode
@@ -1213,6 +1221,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcEqStr:
decodeBC(rkInt)
regs[ra].intVal = ord(regs[rb].node.strVal == regs[rc].node.strVal)
of opcEqCString:
decodeBC(rkInt)
let bNil = regs[rb].node.kind == nkNilLit
let cNil = regs[rc].node.kind == nkNilLit
regs[ra].intVal = ord((bNil and cNil) or
(not bNil and not cNil and regs[rb].node.strVal == regs[rc].node.strVal))
of opcLeStr:
decodeBC(rkInt)
regs[ra].intVal = ord(regs[rb].node.strVal <= regs[rc].node.strVal)
@@ -1345,7 +1359,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
else:
internalError(c.config, c.debug[pc], "opcParseFloat: Incorrectly created openarray")
else:
regs[ra].intVal = parseBiggestFloat(regs[ra].node.strVal, rcAddr.floatVal)
regs[ra].intVal = parseBiggestFloat(regs[rb].node.strVal, rcAddr.floatVal)
of opcRangeChck:
let rb = instr.regB
@@ -1496,7 +1510,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node
c.currentExceptionA = raised
# Set the `name` field of the exception
c.currentExceptionA[2].skipColon.strVal = c.currentExceptionA.typ.sym.name.s
var exceptionNameNode = newStrNode(nkStrLit, c.currentExceptionA.typ.sym.name.s)
if c.currentExceptionA[2].kind == nkExprColonExpr:
exceptionNameNode.typ = c.currentExceptionA[2][1].typ
c.currentExceptionA[2][1] = exceptionNameNode
else:
exceptionNameNode.typ = c.currentExceptionA[2].typ
c.currentExceptionA[2] = exceptionNameNode
c.exceptionInstr = pc
var frame = tos
@@ -1817,7 +1837,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node = opMapTypeInstToAst(c.cache, regs[rb].node.sym.typ, c.debug[pc], c.idgen)
else:
stackTrace(c, tos, pc, "node has no type")
else:
of 3:
# getTypeImpl opcode:
ensureKind(rkNode)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
@@ -1826,6 +1846,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node = opMapTypeImplToAst(c.cache, regs[rb].node.sym.typ, c.debug[pc], c.idgen)
else:
stackTrace(c, tos, pc, "node has no type")
else:
# getTypeInstSkipAlias opcode:
ensureKind(rkNode)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].node = opMapTypeInstToAst(c.cache, regs[rb].node.typ, c.debug[pc], c.idgen, skipAlias = true)
elif regs[rb].kind == rkNode and regs[rb].node.kind == nkSym and regs[rb].node.sym.typ != nil:
regs[ra].node = opMapTypeInstToAst(c.cache, regs[rb].node.sym.typ, c.debug[pc], c.idgen, skipAlias = true)
else:
stackTrace(c, tos, pc, "node has no type")
of opcNGetSize:
decodeBImm(rkInt)
let n = regs[rb].node
@@ -1909,6 +1938,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) =
if error.len == 0 and msg <= errMax:
error = formatMsg(conf, info, msg, arg))
regs[ra].node = newNode(nkEmpty)
if error.len > 0:
c.errorFlag = error
elif ast.len != 1:
@@ -1926,6 +1957,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
error = formatMsg(conf, info, msg, arg))
if error.len > 0:
c.errorFlag = error
regs[ra].node = newNode(nkEmpty)
else:
regs[ra].node = ast
of opcQueryErrorFlag:
@@ -2352,8 +2384,11 @@ proc evalConstExprAux(module: PSym; idgen: IdGenerator;
setupGlobalCtx(module, g, idgen)
var c = PCtx g.vm
let oldMode = c.mode
let oldLocals = c.locals
c.mode = mode
c.locals = initIntSet()
let start = genExpr(c, n, requiresValue = mode!=emStaticStmt)
c.locals = oldLocals
if c.code[start].opcode == opcEof: return newNodeI(nkEmpty, n.info)
assert c.code[start].opcode != opcEof
when debugEchoCode: c.echoCode start

View File

@@ -10,7 +10,7 @@
## This module contains the type definitions for the new evaluation engine.
## An instruction is 1-3 int32s in memory, it is a register based VM.
import std/[tables, strutils]
import std/[tables, strutils, intsets]
import ast, idents, options, modulegraphs, lineinfos
@@ -99,7 +99,7 @@ type
opcLeFloat, opcLtFloat, opcLeu, opcLtu,
opcEqRef, opcEqNimNode, opcSameNodeType,
opcXor, opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt,
opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
opcEqStr, opcEqCString, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
opcMulSet, opcPlusSet, opcMinusSet, opcConcatStr,
opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
opcIsNil, opcOf, opcIs,
@@ -270,6 +270,7 @@ type
templInstCounter*: ref int # gives every template instantiation a unique ID, needed here for getAst
vmstateDiff*: seq[(PSym, PNode)] # we remember the "diff" to global state here (feature for IC)
procToCodePos*: Table[int, int]
locals*: IntSet
PStackFrame* = ref TStackFrame
TStackFrame* {.acyclic.} = object

View File

@@ -40,7 +40,7 @@ proc atomicTypeX(s: PSym; info: TLineInfo): PNode =
result.info = info
proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo; idgen: IdGenerator;
inst=false; allowRecursionX=false): PNode
inst=false; allowRecursionX=false; skipAlias = false): PNode
proc mapTypeToBracketX(cache: IdentCache; name: string; m: TMagic; t: PType; info: TLineInfo;
idgen: IdGenerator;
@@ -68,7 +68,7 @@ proc objectNode(cache: IdentCache; n: PNode; idgen: IdGenerator): PNode =
proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
idgen: IdGenerator;
inst=false; allowRecursionX=false): PNode =
inst=false; allowRecursionX=false; skipAlias = false): PNode =
var allowRecursion = allowRecursionX
template atomicType(name, m): untyped = atomicTypeX(cache, name, m, t, info, idgen)
template atomicType(s): untyped = atomicTypeX(s, info)
@@ -89,7 +89,8 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
id
template newIdentDefs(s): untyped = newIdentDefs(s, s.typ)
if inst and not allowRecursion and t.sym != nil:
if inst and not allowRecursion and t.sym != nil and
not (skipAlias and t.kind == tyAlias):
# getTypeInst behavior: return symbol
return atomicType(t.sym)
@@ -122,7 +123,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
if t.base != nil:
result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
result.add atomicType("typeDesc", mTypeDesc)
result.add mapTypeToAst(t.base, info)
result.add mapTypeToAstX(cache, t.base, info, idgen, inst, skipAlias = skipAlias)
else:
result = atomicType("typeDesc", mTypeDesc)
of tyGenericInvocation:
@@ -133,6 +134,8 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
if inst:
if allowRecursion:
result = mapTypeToAstR(t.lastSon, info)
# keep original type info for getType calls on the output node:
result.typ = t
else:
result = newNodeX(nkBracketExpr)
#result.add mapTypeToAst(t.lastSon, info)
@@ -141,13 +144,15 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
result.add mapTypeToAst(t[i], info)
else:
result = mapTypeToAstX(cache, t.lastSon, info, idgen, inst, allowRecursion)
# keep original type info for getType calls on the output node:
result.typ = t
of tyGenericBody:
if inst:
result = mapTypeToAstR(t.lastSon, info)
else:
result = mapTypeToAst(t.lastSon, info)
of tyAlias:
result = mapTypeToAstX(cache, t.lastSon, info, idgen, inst, allowRecursion)
result = mapTypeToAstX(cache, t.lastSon, info, idgen, inst, allowRecursion, skipAlias = skipAlias)
of tyOrdinal:
result = mapTypeToAst(t.lastSon, info)
of tyDistinct:
@@ -312,8 +317,9 @@ proc opMapTypeToAst*(cache: IdentCache; t: PType; info: TLineInfo; idgen: IdGene
# the "Inst" version includes generic parameters in the resulting type tree
# and also tries to look like the corresponding Nim type declaration
proc opMapTypeInstToAst*(cache: IdentCache; t: PType; info: TLineInfo; idgen: IdGenerator): PNode =
result = mapTypeToAstX(cache, t, info, idgen, inst=true, allowRecursionX=false)
proc opMapTypeInstToAst*(cache: IdentCache; t: PType; info: TLineInfo; idgen: IdGenerator; skipAlias = false): PNode =
# skipAlias: skips aliases and typedesc
result = mapTypeToAstX(cache, t, info, idgen, inst=true, allowRecursionX=false, skipAlias = skipAlias)
# the "Impl" version includes generic parameters in the resulting type tree
# and also tries to look like the corresponding Nim type implementation

View File

@@ -406,13 +406,19 @@ proc genIf(c: PCtx, n: PNode; dest: var TDest) =
c.gen(it[0], tmp)
elsePos = c.xjmp(it[0], opcFJmp, tmp) # if false
c.clearDest(n, dest)
c.gen(it[1], dest) # then part
if isEmptyType(it[1].typ): # maybe noreturn call, don't touch `dest`
c.gen(it[1])
else:
c.gen(it[1], dest) # then part
if i < n.len-1:
endings.add(c.xjmp(it[1], opcJmp, 0))
c.patch(elsePos)
else:
c.clearDest(n, dest)
c.gen(it[0], dest)
if isEmptyType(it[0].typ): # maybe noreturn call, don't touch `dest`
c.gen(it[0])
else:
c.gen(it[0], dest)
for endPos in endings: c.patch(endPos)
c.clearDest(n, dest)
@@ -506,17 +512,25 @@ proc genCase(c: PCtx; n: PNode; dest: var TDest) =
let it = n[i]
if it.len == 1:
# else stmt:
if it[0].kind != nkNilLit or it[0].typ != nil:
let body = it[0]
if body.kind != nkNilLit or body.typ != nil:
# an nkNilLit with nil for typ implies there is no else branch, this
# avoids unused related errors as we've already consumed the dest
c.gen(it[0], dest)
if isEmptyType(body.typ): # maybe noreturn call, don't touch `dest`
c.gen(body)
else:
c.gen(body, dest)
else:
let b = rawGenLiteral(c, it)
c.gABx(it, opcBranch, tmp, b)
let elsePos = c.xjmp(it.lastSon, opcFJmp, tmp)
c.gen(it.lastSon, dest)
let body = it.lastSon
let elsePos = c.xjmp(body, opcFJmp, tmp)
if isEmptyType(body.typ): # maybe noreturn call, don't touch `dest`
c.gen(body)
else:
c.gen(body, dest)
if i < n.len-1:
endings.add(c.xjmp(it.lastSon, opcJmp, 0))
endings.add(c.xjmp(body, opcJmp, 0))
c.patch(elsePos)
c.clearDest(n, dest)
for endPos in endings: c.patch(endPos)
@@ -532,7 +546,10 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
var endings: seq[TPosition] = @[]
let ehPos = c.xjmp(n, opcTry, 0)
c.gen(n[0], dest)
if isEmptyType(n[0].typ): # maybe noreturn call, don't touch `dest`
c.gen(n[0])
else:
c.gen(n[0], dest)
c.clearDest(n, dest)
# Add a jump past the exception handling code
let jumpToFinally = c.xjmp(n, opcJmp, 0)
@@ -550,7 +567,11 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
if it.len == 1:
# general except section:
c.gABx(it, opcExcept, 0, 0)
c.gen(it.lastSon, dest)
let body = it.lastSon
if isEmptyType(body.typ): # maybe noreturn call, don't touch `dest`
c.gen(body)
else:
c.gen(body, dest)
c.clearDest(n, dest)
if i < n.len:
endings.add(c.xjmp(it, opcJmp, 0))
@@ -677,6 +698,9 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
let dest = c.genx(le, {gfNodeAddr})
c.gABC(le, opcWrDeref, dest, 0, value)
c.freeTemp(dest)
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
if sameBackendType(le.typ, le[1].typ):
genAsgnPatch(c, le[1], value)
else:
discard
@@ -845,7 +869,7 @@ proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
genBinaryABC(c, n, dest, opc)
c.genNarrow(n, dest)
proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
proc genConv(c: PCtx; n, arg: PNode; dest: var TDest, flags: TGenFlags = {}; opc=opcConv) =
let t2 = n.typ.skipTypes({tyDistinct})
let targ2 = arg.typ.skipTypes({tyDistinct})
@@ -857,7 +881,7 @@ proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
return true
if implicitConv():
gen(c, arg, dest)
gen(c, arg, dest, flags)
return
let tmp = c.genx(arg)
@@ -875,13 +899,15 @@ proc genCard(c: PCtx; n: PNode; dest: var TDest) =
c.freeTemp(tmp)
proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
const allowedIntegers = {tyInt..tyInt64, tyUInt..tyUInt64, tyChar}
const allowedIntegers = {tyInt..tyInt64, tyUInt..tyUInt64, tyChar, tyEnum, tyBool}
var signedIntegers = {tyInt..tyInt64}
var unsignedIntegers = {tyUInt..tyUInt64, tyChar}
var unsignedIntegers = {tyUInt..tyUInt64, tyChar, tyEnum, tyBool}
let src = n[1].typ.skipTypes(abstractRange)#.kind
let dst = n[0].typ.skipTypes(abstractRange)#.kind
let srcSize = getSize(c.config, src)
let dstSize = getSize(c.config, dst)
const unsupportedCastDifferentSize =
"VM does not support 'cast' from $1 with size $2 to $3 with size $4 due to different sizes"
if src.kind in allowedIntegers and dst.kind in allowedIntegers:
let tmp = c.genx(n[1])
if dest < 0: dest = c.getTemp(n[0].typ)
@@ -898,8 +924,11 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
# is smaller than source.
c.gABC(n, opcNarrowU, dest, TRegister(dstSize*8))
c.freeTemp(tmp)
elif srcSize == dstSize and src.kind in allowedIntegers and
dst.kind in {tyFloat, tyFloat32, tyFloat64}:
elif src.kind in allowedIntegers and
dst.kind in {tyFloat, tyFloat32, tyFloat64}:
if srcSize != dstSize:
globalError(c.config, n.info, unsupportedCastDifferentSize %
[$src.kind, $srcSize, $dst.kind, $dstSize])
let tmp = c.genx(n[1])
if dest < 0: dest = c.getTemp(n[0].typ)
if dst.kind == tyFloat32:
@@ -908,8 +937,11 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
c.gABC(n, opcCastIntToFloat64, dest, tmp)
c.freeTemp(tmp)
elif srcSize == dstSize and src.kind in {tyFloat, tyFloat32, tyFloat64} and
elif src.kind in {tyFloat, tyFloat32, tyFloat64} and
dst.kind in allowedIntegers:
if srcSize != dstSize:
globalError(c.config, n.info, unsupportedCastDifferentSize %
[$src.kind, $srcSize, $dst.kind, $dstSize])
let tmp = c.genx(n[1])
if dest < 0: dest = c.getTemp(n[0].typ)
if src.kind == tyFloat32:
@@ -1011,7 +1043,7 @@ proc whichAsgnOpc(n: PNode; requiresCopy = true): TOpcode =
else:
(if requiresCopy: opcAsgnComplex else: opcFastAsgnComplex)
proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
proc genMagic(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}, m: TMagic) =
case m
of mAnd: c.genAndOr(n, opcFJmp, dest)
of mOr: c.genAndOr(n, opcTJmp, dest)
@@ -1150,8 +1182,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
genConv(c, n, n[1], dest)
of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr)
genConv(c, n, n[1], dest, flags)
of mEqStr: genBinaryABC(c, n, dest, opcEqStr)
of mEqCString: genBinaryABC(c, n, dest, opcEqCString)
of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
of mLtStr: genBinaryABC(c, n, dest, opcLtStr)
of mEqSet: genBinarySet(c, n, dest, opcEqSet)
@@ -1291,7 +1324,8 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of "getType": 0
of "typeKind": 1
of "getTypeInst": 2
else: 3 # "getTypeImpl"
of "getTypeImpl": 3 # "getTypeImpl"
else: 4 # getTypeInstSkipAlias
c.gABC(n, opcNGetType, dest, tmp, rc)
c.freeTemp(tmp)
#genUnaryABC(c, n, dest, opcNGetType)
@@ -1525,6 +1559,8 @@ proc checkCanEval(c: PCtx; n: PNode) =
# little hack ahead for bug #12612: assume gensym'ed variables
# are in the right scope:
if sfGenSym in s.flags and c.prc.sym == nil: discard
elif s.kind == skParam and s.typ.kind == tyTypeDesc: discard
elif s.kind in {skVar, skLet} and s.id in c.locals: discard
else: cannotEval(c, n)
elif s.kind in {skProc, skFunc, skConverter, skMethod,
skIterator} and sfForward in s.flags:
@@ -1614,6 +1650,9 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
c.freeTemp(cc)
else:
gen(c, ri, dest)
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
if sameBackendType(le.typ, le[1].typ):
genAsgn(c, le[1], ri, requiresCopy)
else:
let dest = c.genx(le, {gfNodeAddr})
genAsgn(c, dest, ri, requiresCopy)
@@ -1778,7 +1817,6 @@ proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags
let setLit = c.genx(checkExpr[1])
var rs = c.getTemp(getSysType(c.graph, n.info, tyBool))
c.gABC(n, opcContainsSet, rs, setLit, discVal)
c.freeTemp(discVal)
c.freeTemp(setLit)
# If the check fails let the user know
let lab1 = c.xjmp(n, if negCheck: opcFJmp else: opcTJmp, rs)
@@ -1791,6 +1829,7 @@ proc genCheckedObjAccessAux(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags
strLit.typ = strType
c.genLit(strLit, msgReg)
c.gABC(n, opcInvalidField, msgReg, discVal)
c.freeTemp(discVal)
c.freeTemp(msgReg)
c.patch(lab1)
@@ -1864,10 +1903,10 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
result = newNodeIT(nkUIntLit, info, t)
of tyFloat..tyFloat128:
result = newNodeIT(nkFloatLit, info, t)
of tyCstring, tyString:
of tyString:
result = newNodeIT(nkStrLit, info, t)
result.strVal = ""
of tyVar, tyLent, tyPointer, tyPtr, tyUntyped,
of tyCstring, tyVar, tyLent, tyPointer, tyPtr, tyUntyped,
tyTyped, tyTypeDesc, tyRef, tyNil:
result = newNodeIT(nkNilLit, info, t)
of tyProc:
@@ -1911,7 +1950,7 @@ proc genVarSection(c: PCtx; n: PNode) =
c.gen(lowerTupleUnpacking(c.graph, a, c.idgen, c.getOwner))
elif a[0].kind == nkSym:
let s = a[0].sym
checkCanEval(c, a[0])
c.locals.incl(s.id)
if s.isGlobal:
let runtimeAccessToCompileTime = c.mode == emRepl and
sfCompileTime in s.flags and s.position > 0
@@ -1976,7 +2015,7 @@ proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
c.gABx(n, opcLdNull, dest, c.genType(n.typ))
let intType = getSysType(c.graph, n.info, tyInt)
let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc})
let seqType = n.typ.skipTypes(abstractVar+{tyStatic}-{tyTypeDesc})
if seqType.kind == tySequence:
var tmp = c.getTemp(intType)
c.gABx(n, opcLdImmInt, tmp, n.len)
@@ -2010,6 +2049,8 @@ proc genSetConstr(c: PCtx, n: PNode, dest: var TDest) =
c.freeTemp(a)
proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) =
if tfUnion in n.typ.flags: # bug #22708 # bug #13481
globalError(c.config, n.info, "object with '{.union.}' pragmas is not supported by VM")
if dest < 0: dest = c.getTemp(n.typ)
let t = n.typ.skipTypes(abstractRange+{tyOwned}-{tyTypeDesc})
if t.kind == tyRef:
@@ -2079,8 +2120,13 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
let s = n.sym
checkCanEval(c, n)
case s.kind
of skVar, skForVar, skTemp, skLet, skParam, skResult:
of skVar, skForVar, skTemp, skLet, skResult:
genRdVar(c, n, dest, flags)
of skParam:
if s.typ.kind == tyTypeDesc:
genTypeLit(c, s.typ.skipTypes({tyTypeDesc}), dest)
else:
genRdVar(c, n, dest, flags)
of skProc, skFunc, skConverter, skMacro, skTemplate, skMethod, skIterator:
# 'skTemplate' is only allowed for 'getAst' support:
if s.kind == skIterator and s.typ.callConv == TCallingConvention.ccClosure:
@@ -2117,7 +2163,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
if n[0].kind == nkSym:
let s = n[0].sym
if s.magic != mNone:
genMagic(c, n, dest, s.magic)
genMagic(c, n, dest, flags, s.magic)
elif s.kind == skMethod:
localError(c.config, n.info, "cannot call method " & s.name.s &
" at compile time")
@@ -2174,16 +2220,14 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
unused(c, n, dest)
gen(c, n[0])
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
genConv(c, n, n[1], dest)
genConv(c, n, n[1], dest, flags)
of nkObjDownConv:
genConv(c, n, n[0], dest)
genConv(c, n, n[0], dest, flags)
of nkObjUpConv:
genConv(c, n, n[0], dest)
genConv(c, n, n[0], dest, flags)
of nkVarSection, nkLetSection:
unused(c, n, dest)
genVarSection(c, n)
of declarativeDefs, nkMacroDef:
unused(c, n, dest)
of nkLambdaKinds:
#let s = n[namePos].sym
#discard genProc(c, s)
@@ -2203,7 +2247,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
dest = tmp0
of nkEmpty, nkCommentStmt, nkTypeSection, nkConstSection, nkPragma,
nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt, nkExportStmt,
nkMixinStmt, nkBindStmt:
nkMixinStmt, nkBindStmt, declarativeDefs, nkMacroDef:
unused(c, n, dest)
of nkStringToCString, nkCStringToString:
gen(c, n[0], dest)
@@ -2213,7 +2257,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
of nkPar, nkClosure, nkTupleConstr: genTupleConstr(c, n, dest)
of nkCast:
if allowCast in c.features:
genConv(c, n, n[1], dest, opcCast)
genConv(c, n, n[1], dest, flags, opcCast)
else:
genCastIntFloat(c, n, dest)
of nkTypeOfExpr:

View File

@@ -286,7 +286,7 @@ proc loadAny(p: var JsonParser, t: PType,
proc loadAny*(s: string; t: PType; cache: IdentCache; conf: ConfigRef; idgen: IdGenerator): PNode =
var tab = initTable[BiggestInt, PNode]()
var p: JsonParser
var p: JsonParser = default(JsonParser)
open(p, newStringStream(s), "unknown file")
next(p)
result = loadAny(p, t, tab, cache, conf, idgen)

View File

@@ -91,28 +91,36 @@ type
wRedefine = "redefine", wCallsite = "callsite",
wQuirky = "quirky",
# codegen keywords, but first the ones that are also pragmas:
wExtern = "extern", wGoto = "goto", wRegister = "register",
wUnion = "union", wPacked = "packed", wVirtual = "virtual",
wVolatile = "volatile", wMember = "member",
wByCopy = "bycopy", wByRef = "byref",
# codegen keywords but not pragmas:
wAuto = "auto", wBool = "bool", wCatch = "catch", wChar = "char",
wClass = "class", wCompl = "compl", wConstCast = "const_cast", wDefault = "default",
wDelete = "delete", wDouble = "double", wDynamicCast = "dynamic_cast",
wExplicit = "explicit", wExtern = "extern", wFalse = "false", wFloat = "float",
wFriend = "friend", wGoto = "goto", wInt = "int", wLong = "long", wMutable = "mutable",
wExplicit = "explicit", wFalse = "false", wFloat = "float",
wFriend = "friend", wInt = "int", wLong = "long", wMutable = "mutable",
wNamespace = "namespace", wNew = "new", wOperator = "operator", wPrivate = "private",
wProtected = "protected", wPublic = "public", wRegister = "register",
wProtected = "protected", wPublic = "public",
wReinterpretCast = "reinterpret_cast", wRestrict = "restrict", wShort = "short",
wSigned = "signed", wSizeof = "sizeof", wStaticCast = "static_cast", wStruct = "struct",
wSwitch = "switch", wThis = "this", wThrow = "throw", wTrue = "true", wTypedef = "typedef",
wTypeid = "typeid", wTypeof = "typeof", wTypename = "typename",
wUnion = "union", wPacked = "packed", wUnsigned = "unsigned", wVirtual = "virtual",
wVoid = "void", wVolatile = "volatile", wWchar = "wchar_t",
wUnsigned = "unsigned", wVoid = "void",
wAlignas = "alignas", wAlignof = "alignof", wConstexpr = "constexpr", wDecltype = "decltype",
wNullptr = "nullptr", wNoexcept = "noexcept",
wThreadLocal = "thread_local", wStaticAssert = "static_assert",
wChar16 = "char16_t", wChar32 = "char32_t",
wChar16 = "char16_t", wChar32 = "char32_t", wWchar = "wchar_t",
wStdIn = "stdin", wStdOut = "stdout", wStdErr = "stderr",
wInOut = "inout", wByCopy = "bycopy", wByRef = "byref", wOneWay = "oneway",
wInOut = "inout", wOneWay = "oneway",
# end of codegen keywords
wBitsize = "bitsize", wImportHidden = "all",
wSendable = "sendable"
@@ -125,12 +133,15 @@ const
nimKeywordsLow* = ord(wAsm)
nimKeywordsHigh* = ord(wYield)
ccgKeywordsLow* = ord(wAuto)
ccgKeywordsLow* = ord(wExtern)
ccgKeywordsHigh* = ord(wOneWay)
cppNimSharedKeywords* = {
wAsm, wBreak, wCase, wConst, wContinue, wDo, wElse, wEnum, wExport,
wFor, wIf, wReturn, wStatic, wTemplate, wTry, wWhile, wUsing}
nonPragmaWordsLow* = wAuto
nonPragmaWordsHigh* = wOneWay
from std/enumutils import genEnumCaseStmt

View File

@@ -14,12 +14,12 @@ cc = gcc
# additional options always passed to the compiler:
--parallel_build: "0" # 0 to auto-detect number of processors
@if nimHasAmbiguousEnumHint:
# not needed if hint is a style check
hint[AmbiguousEnum]=off
@end
#hint[XDeclaredButNotUsed]=off
@if not nimHasNolineTooLong:
hint[LineTooLong]=off
@end
threads:on
# Examples of how to setup a cross-compiler:

View File

@@ -237,10 +237,10 @@ doc.file = """<?xml version="1.0" encoding="utf-8" ?>
<link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
<!-- CSS -->
<link rel="stylesheet" type="text/css" href="$nimdoccss">
<link rel="stylesheet" type="text/css" href="${nimdoccss}?v=$nimVersion">
<!-- JS -->
<script type="text/javascript" src="$dochackjs"></script>
<script type="text/javascript" src="${dochackjs}?v=$nimVersion"></script>
</head>
<body>
<div class="document" id="documentId">

View File

@@ -41,6 +41,9 @@ written as:
for i in 0..<x.len: `=destroy`(x.data[i])
dealloc(x.data)
proc `=wasMoved`*[T](x: var myseq[T]) =
x.data = nil
proc `=trace`[T](x: var myseq[T]; env: pointer) =
# `=trace` allows the cycle collector `--mm:orc`
# to understand how to trace the object graph.
@@ -51,7 +54,7 @@ written as:
# do nothing for self-assignments:
if a.data == b.data: return
`=destroy`(a)
wasMoved(a)
`=wasMoved`(a)
a.len = b.len
a.cap = b.cap
if b.data != nil:
@@ -62,8 +65,7 @@ written as:
proc `=dup`*[T](a: myseq[T]): myseq[T] {.nodestroy.} =
# an optimized version of `=wasMoved(tmp); `=copy(tmp, src)`
# usually present if a custom `=copy` hook is overridden
result.len = a.len
result.cap = a.cap
result = myseq[T](len: a.len, cap: a.cap, data: nil)
if a.data != nil:
result.data = cast[typeof(result.data)](alloc(result.cap * sizeof(T)))
for i in 0..<result.len:
@@ -73,7 +75,6 @@ written as:
# move assignment, optional.
# Compiler is using `=destroy` and `copyMem` when not provided
`=destroy`(a)
wasMoved(a)
a.len = b.len
a.cap = b.cap
a.data = b.data
@@ -94,9 +95,10 @@ written as:
x.data[i] = y
proc createSeq*[T](elems: varargs[T]): myseq[T] =
result.cap = elems.len
result.len = elems.len
result.data = cast[typeof(result.data)](alloc(result.cap * sizeof(T)))
result = myseq[T](
len: elems.len,
cap: elems.len,
data: cast[typeof(result.data)](alloc(result.cap * sizeof(T))))
for i in 0..<result.len: result.data[i] = elems[i]
proc len*[T](x: myseq[T]): int {.inline.} = x.len
@@ -151,6 +153,25 @@ but this of little utility as a raising destructor is implementation defined
behavior. Later versions of the language specification might cover this case precisely.
`=wasMoved` hook
----------------
A `=wasMoved` hook sets the object to a state that signifies to the destructor there is nothing to destroy.
The prototype of this hook for a type `T` needs to be:
```nim
proc `=wasMoved`(x: var T)
```
Usually some pointer field inside the object is set to `nil`:
```nim
proc `=wasMoved`(x: var T) =
x.field = nil
```
`=sink` hook
------------
@@ -272,21 +293,11 @@ The general pattern in using `=destroy` with `=trace` looks like:
**Note**: The `=trace` hooks (which are only used by `--mm:orc`) are currently more experimental and less refined
than the other hooks.
`=WasMoved` hook
----------------
A `wasMoved` hook resets the memory of an object to its initial (binary zero) value to signify it was "moved" and to signify its destructor should do nothing and ideally be optimized away.
The prototype of this hook for a type `T` needs to be:
```nim
proc `=wasMoved`(x: var T)
```
`=dup` hook
-----------
A `=dup` hook duplicates the memory of an object. `=dup(x)` can be regarded as an optimization replacing the `wasMoved(dest); =copy(dest, x)` operation.
A `=dup` hook duplicates an object. `=dup(x)` can be regarded as an optimization replacing a `wasMoved(dest); =copy(dest, x)` operation.
The prototype of this hook for a type `T` needs to be:
@@ -317,6 +328,24 @@ document uses the notation `lastReadOf(x)` to describe that `x` is not
used afterward. This property is computed by a static control flow analysis
but can also be enforced by using `system.move` explicitly.
One can query if the analysis is able to perform a move with `system.ensureMove`.
`move` enforces a move operation and calls `=wasMoved` whereas `ensureMove` is
an annotation that implies no runtime operation. An `ensureMove` annotation leads to a static error
if the compiler cannot prove that a move would be safe.
For example:
```nim
proc main(normalParam: string; sinkParam: sink string) =
var x = "abc"
# valid:
let valid = ensureMove x
# invalid:
let invalid = ensureMove normalParam
# valid:
let alsoValid = ensureMove sinkParam
```
Swap
====
@@ -434,7 +463,7 @@ destroyed at the scope exit.
x = lastReadOf z
------------------ (move-optimization)
`=sink`(x, z)
wasMoved(z)
`=wasMoved`(z)
v = v
@@ -461,7 +490,7 @@ destroyed at the scope exit.
f_sink(lastReadOf y)
----------------------- (move-to-sink)
f_sink(y)
wasMoved(y)
`=wasMoved`(y)
Object and array construction
@@ -474,7 +503,7 @@ function has `sink` parameters.
Destructor removal
==================
`wasMoved(x);` followed by a `=destroy(x)` operation cancel each other
`=wasMoved(x)` followed by a `=destroy(x)` operation cancel each other
out. An implementation is encouraged to exploit this in order to improve
efficiency and code sizes. The current implementation does perform this
optimization.
@@ -483,11 +512,11 @@ optimization.
Self assignments
================
`=sink` in combination with `wasMoved` can handle self-assignments but
`=sink` in combination with `=wasMoved` can handle self-assignments but
it's subtle.
The simple case of `x = x` cannot be turned
into `=sink(x, x); wasMoved(x)` because that would lose `x`'s value.
into `=sink(x, x); =wasMoved(x)` because that would lose `x`'s value.
The solution is that simple self-assignments that consist of
- Symbols: `x = x`
@@ -522,10 +551,10 @@ Is transformed into:
try:
if cond:
`=sink`(result, a)
wasMoved(a)
`=wasMoved`(a)
else:
`=sink`(result, b)
wasMoved(b)
`=wasMoved`(b)
finally:
`=destroy`(b)
`=destroy`(a)
@@ -539,10 +568,10 @@ Is transformed into:
`=sink`(y, "xyz")
`=sink`(x, select(true,
let blitTmp = x
wasMoved(x)
`=wasMoved`(x)
blitTmp,
let blitTmp = y
wasMoved(y)
`=wasMoved`(y)
blitTmp))
echo [x]
finally:
@@ -578,7 +607,7 @@ for expressions of type `lent T` or of type `var T`.
proc construct(kids: sink seq[Tree]): Tree =
result = Tree(kids: kids)
# converted into:
`=sink`(result.kids, kids); wasMoved(kids)
`=sink`(result.kids, kids); `=wasMoved`(kids)
`=destroy`(kids)
proc `[]`*(x: Tree; i: int): lent Tree =

View File

@@ -192,7 +192,7 @@ conceptDecl = 'concept' conceptParam ^* ',' (pragma)? ('of' typeDesc ^* ',')?
&IND{>} stmt
typeDef = identVisDot genericParamList? pragma '=' optInd typeDefValue
indAndComment?
varTupleLhs = '(' optInd (identWithPragma / varTupleLhs) ^+ comma optPar ')'
varTupleLhs = '(' optInd (identWithPragma / varTupleLhs) ^+ comma optPar ')' (':' optInd typeDescExpr)?
varTuple = varTupleLhs '=' optInd expr
colonBody = colcom stmt postExprBlocks?
variable = (varTuple / identColonEquals) colonBody? indAndComment

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