Compare commits

..

609 Commits

Author SHA1 Message Date
ringabout
88f556b486 merge upstream code 2023-10-04 15:07:11 +08:00
ringabout
343b304461 Merge remote-tracking branch 'upstream/araq-nir' into pr_ast2ir 2023-10-04 15:03:36 +08:00
Araq
37e3573b61 NIR: implemented builtin 2023-10-03 23:57:38 +02:00
ringabout
09d40ea41b adds entry point and debug code 2023-10-03 22:27:19 +08:00
Araq
326a4592f1 progress 2023-10-03 09:08:20 +02:00
araq
df71f4602e baby steps 2023-10-02 14:23:42 +02:00
araq
f496c0e14c progress 2023-10-01 12:53:38 +02:00
araq
9d9d860797 support for annotations that can be used for calling conventions 2023-10-01 10:34:37 +02:00
araq
ef5c4ffaa2 same chance recursive types work [CI skip] 2023-10-01 09:41:37 +02:00
Araq
95c9d4cd7b bugfix 2023-10-01 07:49:05 +02:00
araq
7f92d26470 type generation for closures 2023-10-01 01:43:06 +02:00
araq
284bbe2eb7 some varargs handling 2023-10-01 01:28:19 +02:00
araq
42ebed76e6 progress 2023-10-01 01:15:53 +02:00
araq
4fada54c6b WIP: translate the AST into the IR 2023-10-01 00:06:56 +02:00
araq
9510e1a55c NIR: An immediate representation for Nim. WIP 2023-09-30 21:02:01 +02:00
Andreas Rumpf
8f5b90f886 produce better code for object constructions and 'result' [backport] (#22668) 2023-09-11 18:48:20 +02:00
Juan M Gómez
7e86cd6fa7 fixes #22680 Nim zero clear an object inherits C++ imported class when a proc return it (#22684) 2023-09-11 12:55:11 +02:00
ringabout
b1a8d6976f fixes the discVal register is used after free in vmgen (#22688)
follow up https://github.com/nim-lang/Nim/pull/11955
2023-09-11 10:54:41 +02:00
Amjad Ben Hedhili
fbb5ac512c 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>
2023-09-10 17:36:49 +02:00
ringabout
f8f6a3c926 renderIr should print the actual return assign node (#22682)
follow up https://github.com/nim-lang/Nim/pull/10806

Eventually we need a new option to print high level IR. It's confusing
when I'm debugging the compiler without showing `return result = 1`
using the expandArc option.

For 
```nim
proc foo: int =
  return 2
```
It now outputs when expanding ARC IR
```nim
proc foo: int =
  return result = 2
```
2023-09-10 17:35:40 +02:00
Juan M Gómez
8032f252b2 fixes #22669 constructor pragma doesnt init Nim default fields (#22670)
fixes #22669 constructor pragma doesnt init Nim default fields

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-09-10 12:45:36 +02:00
Juan M Gómez
cd24195d44 fixes #22679 Nim zero clear an object contains C++ imported class when a proc return it (#22681) 2023-09-10 12:30:03 +02:00
ringabout
2ce9197d3a [minor] merge similar branches in vmgen (#22683) 2023-09-10 10:43:46 +02:00
Amjad Ben Hedhili
8853fb0775 Make newSeqOfCap not initialize memory. (#21842)
It's used in `newSeqUninitialized`.

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2023-09-09 21:11:45 +02:00
ringabout
5717a4843d fixes #22676; remove wMerge which is a noop for more than 8 years (#22678)
fixes #22676

If csource or CI forbids it, we can always fall back to adding it to the
nonPragmaWords list. I doubt it was used outside of the system since it
was used to implement & or something for magics.
2023-09-09 17:25:48 +02:00
Juan M Gómez
e6ca13ec85 Instantiates generics in the module that uses it (#22513)
Attempts to move the generic instantiation to the module that uses it.
This should decrease re-compilation times as the source module where the
generic lives doesnt need to be recompiled

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-09-09 10:34:20 +02:00
ringabout
5f13e15e0a fixes #22664; guard against potential seqs self assignments (#22671)
fixes #22664
2023-09-08 17:05:57 +02:00
Juan M Gómez
d45270bdf7 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>
2023-09-08 10:46:40 +02:00
SirOlaf
2a8c759df0 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 <>
2023-09-08 06:50:39 +02:00
SirOlaf
ee4a219012 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 <>
2023-09-07 05:46:45 +02:00
Amjad Ben Hedhili
a4df44d9fb Remove some unnecessary initialization in string operations (#22579)
* `prepareAdd`
* `toNimStr`
* `setLengthStrV2`
* `NimAsgnStrV2`
* `prepareMutation`
* Some cleanups
2023-09-07 05:45:54 +02:00
metagn
e5106d1ef3 minor refactoring, move some sym/type construction to semdata (#22654)
Move `symFromType` and `symNodeFromType` from `sem`, and `isSelf` and
`makeTypeDesc` from `concepts` into `semdata`.

`makeTypeDesc` was moved out from semdata [when the `concepts` module
was
added](6278b5d89a),
so its old position might have been intended. If not, `isSelf` can also
go in `ast`.
2023-09-07 05:33:01 +02:00
metagn
ad7c1c38ff run docs CI on compiler changes (#22656)
refs #22650

Docs CI cover standard library runnable examples that aren't covered by
the test suite and can be affected by compiler changes without knowing
2023-09-07 05:31:15 +02:00
metagn
ed9e3cba07 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.
2023-09-07 05:30:37 +02:00
metagn
b9f039e0c3 switch back to main neo in CI (#22660)
refs https://github.com/andreaferretti/neo/pull/53
2023-09-06 12:37:51 +03:00
ringabout
009ce1e17e add union to packages (#22658) 2023-09-06 09:05:01 +02:00
metagn
90f87bcab7 fully revert generic inst sym change, test #22646 (#22653)
reverts #22642, reopens #22639, closes #22646, refs #22650, refs
https://github.com/alaviss/union/issues/51, refs #22652

The fallout is too much from #22642, we can come back to it if we can
account for all the affected code.
2023-09-06 05:45:07 +03:00
ringabout
eb91cf991a 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>
2023-09-05 10:31:28 +02:00
metagn
6000cc8c0f fix sym of created generic instantiation type (#22642)
fixes #22639

A `tyGenericInst` has its last son as the instantiated body of the
original generic type. However this type keeps its original `sym` field
from the original generic types, which means the sym's type is
uninstantiated. This causes problems in the implementation of `getType`,
where it uses the `sym` fields of types to represent them in AST, the
relevant example for the issue being
[here](d13aab50cf/compiler/vmdeps.nim (L191))
called from
[here](d13aab50cf/compiler/vmdeps.nim (L143)).

To fix this, create a new symbol from the original symbol for the
instantiated body during the creation of `tyGenericInst`s with the
appropriate type. Normally `replaceTypeVarsS` would be used for this,
but here it seems to cause some recursion issue (immediately gives an
error like "cannot instantiate HSlice[T, U]"), so we directly set the
symbol's type to the instantiated type.

Avoiding recursion means we also cannot use `replaceTypeVarsN` for the
symbol AST, and the symbol not having any AST crashes the implementation
of `getType` again
[here](d13aab50cf/compiler/vmdeps.nim (L167)),
so the symbol AST is set to the original generic type AST for now which
is what it was before anyway.

Not sure about this because not sure why the recursion issue is
happening, putting it at the end of the proc doesn't help either. Also
not sure if the `cl.owner != nil and s.owner != cl.owner` condition from
`replaceTypeVarsS` is relevant here. This might also break some code if
it depended on the original generic type symbol being given.
2023-09-05 10:30:13 +02:00
Amjad Ben Hedhili
8f7aedb3d1 Add hasDefaultValue type trait (#22636)
Needed for #21842.
2023-09-04 23:18:58 +02:00
ringabout
3fbb078a3c update checkout to v4 (#22640)
ref https://github.com/actions/checkout/issues/1448

probably nodejs needs to be updated to 20.x
2023-09-04 23:09:27 +02:00
ringabout
d13aab50cf fixes branches interacting with break, raise etc. in strictdefs (#22627)
```nim
{.experimental: "strictdefs".}

type Test = object
  id: int

proc test(): Test =
  if true:
    return Test()
  else:
    return
echo test()
```

I will tackle https://github.com/nim-lang/Nim/issues/16735 and #21615 in
the following PR.


The old code just premises that in branches ended with returns, raise
statements etc. , all variables including the result variable are
initialized for that branch. It's true for noreturn statements. But it
is false for the result variable in a branch tailing with a return
statement, in which the result variable is not initialized. The solution
is not perfect for usages below branch statements with the result
variable uninitialized, but it should suffice for now, which gives a
proper warning.

It also fixes

```nim

{.experimental: "strictdefs".}

type Test = object
  id: int

proc foo {.noreturn.} = discard

proc test9(x: bool): Test =
  if x:
    foo()
  else:
    foo()
```
which gives a warning, but shouldn't
2023-09-04 14:36:45 +02:00
Andrey Makarov
c5495f40d5 docgen: add Pandoc footnotes (fixes #21080) (#22591)
This implements Pandoc Markdown-style footnotes,
that are compatible with Pandoc referencing syntax:

    Ref. [^ftn].

    [^ftn]: Block.

See https://pandoc.org/MANUAL.html#footnotes for more examples.
2023-09-03 16:09:36 +02:00
metagn
480e98c479 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.
2023-09-03 13:59:03 +02:00
SirOlaf
d2f36c071b Exclude block from endsInNoReturn, fix regression (#22632)
Co-authored-by: SirOlaf <>
2023-09-02 20:42:40 +02:00
metagn
bd6adbcc9d fix isNil folding for compile time closures (#22574)
fixes #20543
2023-09-02 10:32:46 +02:00
Pylgos
9f1fe8a2da Fix the problem where instances of generic objects with sendable pragmas are not being cached (#22622)
remove `tfSendable` from `eqTypeFlags`
2023-09-02 06:00:26 +02:00
metagn
2542dc09c8 use dummy dest for void branches to fix noreturn in VM (#22617)
fixes #22216
2023-09-01 15:38:25 +02:00
metagn
6738f44af3 unify explicit generic param semchecking in calls (#22618)
fixes #9040
2023-09-01 15:37:16 +02:00
Juan M Gómez
0c6e13806d 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
2023-09-01 13:42:47 +02:00
metagn
f1789cc465 resolve local symbols in generic type call RHS (#22610)
resolve local symbols in generic type call

fixes #14509
2023-09-01 09:00:15 +02:00
metagn
53d9fb259f don't update const symbol on const section re-sems (#22609)
fixes #19849
2023-09-01 08:59:48 +02:00
ringabout
affd3f7858 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
2023-09-01 08:55:19 +02:00
SirOlaf
3b206ed988 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 <>
2023-09-01 06:41:39 +02:00
metagn
ba158d73dc 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
2023-09-01 06:26:53 +02:00
ringabout
b3912c25d3 remove outdated config (#22603) 2023-08-31 18:01:29 +02:00
ringabout
5387b30211 closes #22600; adds a test case (#22602)
closes #22600
2023-08-31 22:30:19 +08:00
ringabout
5bd1afc3f9 fixes #17197; fixes #22560; fixes the dest of newSeqOfCap in refc (#22594) 2023-08-31 19:04:32 +08:00
ringabout
dfb3a88cc3 fixes yaml tests (#22595) 2023-08-31 15:26:09 +08:00
metagn
2e4e2f8f50 handle typedesc params in VM (#22581)
* handle typedesc params in VM

fixes #15760

* add test

* fix getType(typedesc) test
2023-08-30 07:23:14 +02:00
Juan M Gómez
d7634c1bd4 fixes an issue where sometimes wasMoved produced bad codegen for cpp (#22587) 2023-08-30 07:22:36 +02:00
ringabout
a7a0105d8c 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
2023-08-29 15:00:13 +02:00
metagn
b6cea7b599 clearer error for different size int/float cast in VM (#22582)
refs #16547
2023-08-29 14:59:49 +02:00
ringabout
e53c66ef39 fixes #22555; implements newStringUninit (#22572)
* fixes newStringUninitialized; implement `newStringUninitialized`

* add a simple test case

* adds a changelog

* Update lib/system.nim

* Apply suggestions from code review

rename to newStringUninit
2023-08-29 13:29:42 +02:00
ringabout
1fcb53cded 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
2023-08-29 10:40:19 +02:00
ringabout
d8ffc6a75e minor style changes in the compiler (#22584)
* minor style changes in the compiler

* use raiseAssert
2023-08-29 13:59:51 +08:00
metagn
6b955ac4af properly fold constants for dynlib pragma (#22575)
fixes #12929
2023-08-28 21:41:18 +02:00
metagn
3de8d75513 correct logic for qualified symbol in templates (#22577)
* correct logic for qualified symbol in templates

fixes #19865

* add test
2023-08-28 21:40:46 +02:00
metagn
94454addb2 define toList procs after add for lists [backport] (#22573)
fixes #22543
2023-08-28 15:09:43 +02:00
ringabout
2e7c8a339f newStringOfCap now won't initialize all elements anymore (#22568)
newStringOfCap nows won't initialize all elements anymore
2023-08-28 10:43:58 +02:00
ringabout
306b9aca48 initCandidate and friends now return values (#22570)
* `initCandidate` and friends now return values

* fixes semexprs.nim

* fixes semcall.nim

* Update compiler/semcall.nim
2023-08-28 15:57:24 +08:00
Bung
094a29eb31 add test case for #19095 (#22566) 2023-08-28 12:31:16 +08:00
Bung
100eb6820c close #9334 (#22565) 2023-08-27 22:56:50 +08:00
Bung
0b78b7f595 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
2023-08-27 14:29:24 +02:00
metagn
c19fd69b69 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
2023-08-27 11:27:47 +02:00
Juan Carlos
a108a451c5 Improve compiler cli args (#22509)
* .

* Fix cli args out of range with descriptive error instead of crash

* https://github.com/nim-lang/Nim/pull/22509#issuecomment-1692259451
2023-08-25 22:55:17 +02:00
metagn
1cc4d3f622 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
2023-08-25 21:08:47 +02:00
ringabout
d677ed31e5 follow up #22549 (#22551) 2023-08-25 06:48:08 +02:00
Amjad Ben Hedhili
fc6a388780 Add cursor to lists iterator variables (#22531)
* followup #21507
2023-08-24 20:57:49 +02:00
ringabout
1013378854 fixes a strictdef ten years long vintage bug, which counts the same thing twice (#22549)
fixes a strictdef ten years long vintage bug
2023-08-24 20:56:58 +02:00
Jacek Sieka
bc9785c08d Fix getAppFilename exception handling (#22544)
* Fix `getAppFilename` exception handling

avoid platform-dependendent error handling strategies

* more fixes

* space
2023-08-24 15:41:29 +02:00
ringabout
c56a712e7d fixes #22541; peg matchLen can raise an unlisted exception: Exception (#22545)
The `mopProc` is a recursive function.
2023-08-24 12:59:45 +02:00
metagn
53d43e9671 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>
2023-08-24 06:11:48 +02:00
metagn
03f267c801 make jsffi properly gensym (#22539)
fixes #21208
2023-08-23 19:25:26 +02:00
metagn
4f891aa50c don't render underscore identifiers with id (#22538) 2023-08-23 13:43:02 +02:00
SirOlaf
3de75ffc02 Fix #21532: Check if template return is untyped (#22517)
* Don't ignore return in semTemplateDef

* Add test

---------

Co-authored-by: SirOlaf <>
2023-08-23 06:18:35 +02:00
Andreas Rumpf
6b04d0395a allow tuples and procs in 'toTask' + minor things (#22530) 2023-08-22 21:01:08 +02:00
Hamid Bluri
a26ccb3476 fix #22492 (#22511)
* fix #22492

* Update nimdoc.css

remove scroll-y

* Update nimdoc.out.css

* Update nimdoc.css

* make it sticky again

* Update nimdoc.out.css

* danm sticky, use fixed

* Update nimdoc.out.css

* fix margin

* Update nimdoc.out.css

* make search input react to any change (not just keyboard events) according to https://github.com/nim-lang/Nim/pull/22511#issuecomment-1685218787
2023-08-22 18:31:21 +02:00
metagn
602f537eb2 allow non-pragma special words as user pragmas (#22526)
allow non-pragma special words as macro pragmas

fixes #22525
2023-08-21 20:08:57 +02:00
metagn
942f846f04 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
2023-08-21 20:08:00 +02:00
metagn
a4781dc4bc use old typeinfo generation for hot code reloading (#22518)
* use old typeinfo generation for hot code reloading

* at least test hello world compilation on orc
2023-08-20 06:30:36 +02:00
SirOlaf
c0ecdb01a9 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>
2023-08-19 21:04:25 +02:00
PhilippMDoerner
93407096db #22514 expand testament option docs (#22516)
* #22514 Expand docs on testament spec options

The file, line and column options of testament are not in the docs,
but can be very important to know.
They allow you to specify where a compile-time error originated from.

Particularly given that testament assumes the origin to always be
the test-file, this is important to know.

* #22514 Specify nimout relevance a bit more

* #22514 Fix slightly erroneous doc-link

* #22514 Add example

* #22514 Add some docs on ccodecheck
2023-08-19 17:25:38 +02:00
Amjad Ben Hedhili
d77ada5bdf Markdown code blocks migration part 9 (#22506)
* Markdown code blocks migration part 9

* fix [skip ci]
2023-08-19 15:14:56 +02:00
Nan Xiao
6eb722c47d replace getOpt with getopt (#22515) 2023-08-19 15:05:17 +02:00
Juan Carlos
c44c8ddb44 Remove Deprecated Babel (#22507) 2023-08-19 07:05:06 +02:00
Alberto Torres
20cbdc2741 Fix #22366 by making nimlf_/nimln_ part of the same line (#22503)
Fix #22366 by making nimlf_/nimln_ part of the same line so the debugger doesn't advance to the next line before executing it
2023-08-18 21:13:27 +02:00
Tomohiro
eb83d20d0d Add staticFileExists and staticDirExists (#22278) 2023-08-18 16:47:47 +02:00
ringabout
7fababd583 make float32 literals stringifying behave in JS the same as in C (#22500) 2023-08-17 18:52:38 +02:00
metagn
98c39e8e57 cascade tyFromExpr in type conversions in generic bodies (#22499)
fixes #22490, fixes #22491, adapts #22029 to type conversions
2023-08-17 18:52:28 +02:00
ringabout
fede757238 bump checksums (#22497) 2023-08-17 16:48:28 +02:00
Nan Xiao
019b488e1f fixes syncio document (#22498) 2023-08-17 20:26:33 +08:00
ringabout
2e3d9cdbee fixes #22441; build documentation for more modules in the checksums (#22453)
Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>
2023-08-17 13:54:00 +02:00
ringabout
ee817557ec close #22748; cursorinference + -d:nimNoLentIterators results in err… (#22495)
closed #22748; cursorinference + -d:nimNoLentIterators results in erroneous recursion
2023-08-17 13:33:19 +02:00
Juan M Gómez
60307cc373 updates manual with codegenDecl on params docs (#22333)
* documents member

* Update doc/manual_experimental.md

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

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>
2023-08-17 12:20:22 +02:00
Amjad Ben Hedhili
299394d21a Fix seq.capacity (#22488) 2023-08-17 06:38:15 +02:00
ringabout
940b1607b8 fixes #22357; don't sink elements of var tuple cursors (#22486) 2023-08-16 13:46:44 +02:00
ringabout
ade75a1483 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>
2023-08-15 23:31:44 +02:00
Jason Beetham
6c4e7835bf When in object handles procedure call again, fixes #22474 (#22480)
Ping @narimiran please backport to the 2.0 line.
2023-08-15 17:48:31 +02:00
ringabout
9296b45de4 update test command of important packages (#22485) 2023-08-15 21:42:26 +08:00
Andrey Makarov
a660c17d30 Markdown code blocks migration part 8 (#22478) 2023-08-15 06:27:36 +02:00
Emery Hemingway
1927ae72d0 Add Linux constant SO_BINDTODEVICE (#22468) 2023-08-14 21:00:48 +02:00
ringabout
09d0fda7fd fixes #22469; generates nimTestErrorFlag for top level statements (#22472)
fixes #22469; generates `nimTestErrorFlag` for top level statements
2023-08-14 13:08:01 +02:00
ringabout
7bb2462d06 fixes CI (#22471)
Revert "fixes bareExcept warnings; catch specific exceptions (#21119)"

This reverts commit 9207d77848.
2023-08-14 15:04:02 +08:00
Nan Xiao
9bf605cf98 fixes syncio document (#22467) 2023-08-14 08:44:50 +08:00
ringabout
9207d77848 fixes bareExcept warnings; catch specific exceptions (#21119)
* fixes bareExcept warnings; catch specific exceptions

* Update lib/pure/coro.nim
2023-08-13 00:02:36 +02:00
ringabout
4c89223171 relax the parameter of ensureMove; allow let statements (#22466)
* relax the parameter of `ensureMove`; allow let statements

* fixes the test
2023-08-12 13:23:54 +02:00
Juan M Gómez
f642c9dbf1 documents member (#22460)
* documents member

* Apply suggestions from code review

Co-authored-by: Juan Carlos <juancarlospaco@gmail.com>

* Update doc/manual_experimental.md

* Update doc/manual_experimental.md

* Update doc/manual_experimental.md

* Update doc/manual_experimental.md

* Update doc/manual_experimental.md

* Update doc/manual_experimental.md

---------

Co-authored-by: Juan Carlos <juancarlospaco@gmail.com>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-08-12 10:37:52 +02:00
ringabout
23f3f9ae2c better initialization patterns for seminst (#22456)
* better initialization patterns for seminst

* Update compiler/seminst.nim

* Update compiler/seminst.nim
2023-08-12 08:30:17 +08:00
ringabout
3f7e1d7daa replace doAssert false with raiseAssert in lib, which works better with strictdefs (#22458) 2023-08-11 18:24:46 +02:00
Pylgos
48da472dd2 fix #22448 Remove structuredErrorHook temporary in tryConstExpr (#22450)
* fix #22448

* add test
2023-08-11 18:23:09 +02:00
ringabout
469c9cfab4 unpublic the sons field of PType; the precursor to PType refactorings (#22446)
* unpublic the sons field of PType

* tiny fixes

* fixes an omittance

* fixes IC

* fixes
2023-08-11 22:18:24 +08:00
ringabout
72bc72bf9e refactor result = default(...) into object construction (#22455) 2023-08-11 22:16:58 +08:00
Bung
277393d0f1 close #17045;Compiler crash when a tuple iterator with when nimvm is … (#22452)
close #17045;Compiler crash when a tuple iterator with when nimvm is iterated in a closure iterator
2023-08-11 19:11:47 +08:00
Bung
3bb75f2dea close #18103 internal error: inconsistent environment type (#22451) 2023-08-11 18:50:31 +08:00
ringabout
9fed58d5a0 modernize lambdalifting (#22449)
* modernize lambdalifting

* follow @beef331's suggestions
2023-08-11 17:08:51 +08:00
ringabout
0bf286583a initNodeTable and friends now return (#22444) 2023-08-11 12:50:41 +08:00
ringabout
faf1c91e6a fixes move sideeffects issues [backport] (#22439)
* fixes move sideeffects issues [backport]

* fix openarray

* fixes openarray
2023-08-10 18:04:29 +02:00
ringabout
7be2e2bef5 replaces doAssert false with raiseAssert for unreachable branches, which works better with strictdefs (#22436)
replaces `doAssert false` with `raiseAssert`, which works better with strictdefs
2023-08-10 14:26:40 +02:00
ringabout
8523b543d6 getTemp and friends now return TLoc as requested (#22440)
getTemp and friends now return `TLoc`
2023-08-10 14:17:15 +02:00
Juan M Gómez
8625e71250 adds support for functor in member (#22433)
* adds support for functor in member

* improves functor test
2023-08-10 14:15:23 +02:00
ringabout
05f7c4f79d fixes a typo (#22437) 2023-08-10 16:41:24 +08:00
Bung
2aab03bdfb 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
2023-08-10 16:26:23 +08:00
ringabout
a6610745d8 initLocExpr and friends now return TLoc (#22434)
`initLocExpr` and friends now return TLoc
2023-08-10 07:57:34 +02:00
SirOlaf
baf350493b Fix #21760 (#22422)
* Remove call-specific replaceTypeVarsN

* Run for all call kinds and ignore typedesc

* Testcase

---------

Co-authored-by: SirOlaf <>
2023-08-10 07:56:09 +02:00
ringabout
fa58d23080 modernize sempass2; initEffects now returns TEffects (#22435) 2023-08-10 11:29:42 +08:00
Juan M Gómez
6ec1c80779 makes asmnostackframe work with cpp member #22411 (#22429) 2023-08-09 20:57:52 +02:00
ringabout
91c3221855 simplify isAtom condition (#22430) 2023-08-09 20:57:13 +02:00
Bung
46e94c83d4 Fix #5780 (#22428)
* fix #5780
2023-08-09 23:17:08 +08:00
ringabout
5ec81d076b fixes cascades of out parameters, which produces wrong ProveInit warnings (#22413) 2023-08-09 13:49:30 +02:00
Bung
d53a89e453 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
2023-08-09 12:45:43 +02:00
ringabout
5334dc921f 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>
2023-08-09 12:43:17 +02:00
Bung
989da75b84 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
2023-08-09 09:43:39 +02:00
ringabout
c622e58db9 make the name of procs consistent with the name forwards (#22424)
It seems that `--stylecheck:error` acts up when the name forwards is involved.


```nim
proc thisOne*(x: var int)
proc thisone(x: var int) = x = 1
```

It cannot understand this at all.
2023-08-09 13:18:50 +08:00
ringabout
28b2e429ef refactors initSrcGen and initTokRender into returning objects (#22421) 2023-08-09 06:40:17 +02:00
ringabout
ce079a8da4 modernize jsgen; clean up some leftovers (#22423) 2023-08-09 06:33:19 +02:00
metagn
3aaef9e4cf block ambiguous type conversion dotcalls in generics (#22375)
fixes #22373
2023-08-09 06:12:14 +02:00
ringabout
d136af0122 modernize lineinfos; it seems that array access hinders strict def analysis like field access (#22420)
modernize lineinfos; array access hinders strict def analysis like field access

A bug ?

```nim
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
  result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept}
  result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt}
  result[1] = result[2] - {warnProveField, warnProveIndex,
    warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
    hintSource, hintGlobalVar, hintGCStats, hintMsgOrigin, hintPerformance}
  result[0] = result[1] - {hintSuccessX, hintSuccess, hintConf,
    hintProcessing, hintPattern, hintExecuting, hintLinking, hintCC}
```
2023-08-09 08:18:47 +08:00
ringabout
73e661d01b modernize compiler/reorder, which exposes yet another strictdefs bug (#22415)
```nim
{.experimental: "strictdefs".}

type
  NodeKind = enum
    nkImportStmt
    nkStmtList
    nkNone

  PNode = ref object
    kind: NodeKind

proc hasImportStmt(n: PNode): bool =
  # Checks if the node is an import statement or
  # i it contains one
  case n.kind
  of nkImportStmt:
    return true
  of nkStmtList:
    if false:
      return true
  else:
    result = false

var n = PNode()
echo hasImportStmt(n)
```
It compiles without warnings, but shouldn't. As a contrast, 

```nim
{.experimental: "strictdefs".}

type
  NodeKind = enum
    nkImportStmt
    nkStmtList
    nkNone

  PNode = ref object
    kind: NodeKind

proc hasImportStmt(n: PNode): bool =
  # Checks if the node is an import statement or
  # i it contains one
  case n.kind
  of nkImportStmt:
    result = true
  of nkStmtList:
    if false:
      return true
  else:
    result = false

var n = PNode()
echo hasImportStmt(n)
```
This gives a proper warning.
2023-08-08 21:12:54 +08:00
ringabout
10a6e4c236 clean up gc:arc or gc:orc in docs and in error messages (#22408)
* clean up gc:arc/orc in docs

* in error messages
2023-08-08 05:55:18 -04:00
ringabout
bf5d173bc6 fixes LineTooLong hints on old compilers (#22412)
* fixes LineTooLong hints on old compilers

* fixes config/nim.cfg
2023-08-08 17:53:21 +08:00
ringabout
4c6be40b34 modernize compiler/filter_tmpl.nim (#22407) 2023-08-08 16:08:16 +08:00
Bung
37d8f32ae9 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
2023-08-08 16:06:47 +08:00
ringabout
47d06d3d4c fixes #22387; Undefined behavior when with hash(...) (#22404)
* fixes #22387; Undefined behavior when with hash(...)

* fixes vm

* fixes nimscript
2023-08-08 13:42:08 +08:00
Bung
0219c5a607 fix #22287 nimlf_ undefined error (#22382) 2023-08-08 06:13:14 +02:00
ringabout
b4b555d8d1 tiny change on action.nim (#22405) 2023-08-08 11:13:38 +08:00
ringabout
260b4236fc use out parameters for getTemp (#22399) 2023-08-07 10:11:59 +02:00
Juan M Gómez
b5b4b48c94 [C++] Member pragma RFC (https://github.com/nim-lang/RFCs/issues/530) (#22272)
* [C++] Member pragma RFC #530
rebase devel

* changes the test so `echo` is not used before Nim is init

* rebase devel

* fixes Error: use explicit initialization of X for clarity [Uninit]
2023-08-07 10:11:00 +02:00
Bung
fe9ae2c69a nimIoselector option (#22395)
* selectors.nim: Add define to select event loop implementation

* rename to nimIoselector

---------

Co-authored-by: Jan Pobrislo <ccx@webprojekty.cz>
2023-08-07 10:09:35 +02:00
ringabout
614a18cd05 Delete parse directory, which was pushed wrongly before [backport] (#22401)
Delete parse directory
2023-08-07 15:49:30 +08:00
ringabout
26eb0a944f a bit modern code for depends (#22400)
* a bit modern code for depends

* simplify
2023-08-07 15:40:39 +08:00
ringabout
e7b4c7cddb unify starting blank lines in the experimental manual (#22396)
unify starting blank lines in the experimental manal
2023-08-06 17:59:43 +02:00
ringabout
93ced31353 use strictdefs for compiler (#22365)
* wip; use strictdefs for compiler

* checkpoint

* complete the chores

* more fixes

* first phase cleanup

* Update compiler/bitsets.nim

* cleanup
2023-08-06 14:26:21 +02:00
konsumlamm
53586d1f32 Fix some jsgen bugs (#22330)
Fix `succ`, `pred`
Fix `genRangeChck` for unsigned ints
Fix typo in `dec`
2023-08-06 14:24:35 +02:00
SirOlaf
67122a9cb6 Let inferGenericTypes continue if a param is already bound (#22384)
* Play with typeRel

* Temp solution: Fixup call's param types

* Test result type with two generic params

* Asserts

* Tiny cleanup

* Skip sink

* Ignore proc

* Use changeType

* Remove conversion

* Remove last bits of conversion

* Flag

---------

Co-authored-by: SirOlaf <>
2023-08-06 14:23:00 +02:00
Bung
d2b197bdcd Stick search result (#22394)
* nimdoc: stick search result inside browser viewport

* fix nimdoc.out.css

---------

Co-authored-by: Locria Cyber <74560659+locriacyber@users.noreply.github.com>
2023-08-06 19:07:36 +08:00
Bung
f18e4c4050 fix set op related to {sfGlobal, sfPure} (#22393) 2023-08-06 19:07:01 +08:00
Bung
95c751a9e4 fix #15005; [ARC] Global variable declared in a block is destroyed too… (#22388)
* fix #15005 [ARC] Global variable declared in a block is destroyed too early
2023-08-06 15:46:43 +08:00
Bung
137d608d7d add test for #3907 (#21069)
* add test for #3907
2023-08-06 15:21:24 +08:00
ringabout
b2c3b8f931 introduces online bisecting (#22390)
* introduces online bisecting

* Update .github/ISSUE_TEMPLATE/bug_report.yml
2023-08-06 08:52:17 +08:00
Daniel Belmes
7bf7496557 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
2023-08-06 02:50:47 +08:00
norrath-hero-cn
e0396900ed Prevent early destruction of gFuns, fixes AddressSanitizer: heap-use-after-free (#22386)
Prevent destruction of gFuns before callClosures
2023-08-05 19:38:32 +02:00
Andreas Rumpf
9872453365 destructors: better docs [backport:2.0] (#22391) 2023-08-05 19:35:37 +02:00
konsumlamm
e15e19308e Revert adding generic V: Ordinal parameter to succ, pred, inc, dec (#22328)
* Use `int` in `digitsutils`, `dragonbox`, `schubfach`

* Fix error message
2023-08-06 00:38:46 +08:00
Andreas Rumpf
873eaa3f65 compiler/llstream: modern code for llstream (#22385) 2023-08-04 22:52:31 +02:00
Tomohiro
db435a4a79 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
2023-08-04 20:00:43 +02:00
norrath-hero-cn
73a29d72e3 fixes AddressSanitizer: global-buffer-overflow in getAppFilename on windows 10 (#22380)
fixes AddressSanitizer: global-buffer-overflow
2023-08-04 19:59:05 +02:00
Bung
26f183043f 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
2023-08-04 13:35:43 +02:00
Jake Leahy
3efabd3ec6 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
2023-08-04 12:21:36 +02:00
ringabout
7c2a2c8dc8 fixes a typo in the manual (#22383)
ref 0d3bde95f5 (commitcomment-122093273)
2023-08-04 18:00:00 +08:00
ringabout
fb7acd6600 follow up #22322; fixes changelog (#22381) 2023-08-04 09:08:41 +02:00
konsumlamm
d37b620757 Make repr(HSlice) always available (#22332)
Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2023-08-04 05:29:48 +02:00
awr1
14bc3f3268 Allow libffi to work via koch boot (#22322)
* Divert libffi from nimble path, impl into koch

* Typo in koch

* Update options.nim comment

* Fix CI Test

* Update changelog

* Clarify libffi nimble comment

* Future pending changelog

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2023-08-03 23:06:30 +02:00
SirOlaf
8d8d75706c Add experimental inferGenericTypes switch (#22317)
* Infer generic bindings

* Simple test

* Add t

* Allow it to work for templates too

* Fix some builds by putting bindings in a template

* Fix builtins

* Slightly more exotic seq test

* Test value-based generics using array

* Pass expectedType into buildBindings

* Put buildBindings into a proc

* Manual entry

* Remove leftover `

* Improve language used in the manual

* Experimental flag and fix basic constructors

* Tiny commend cleanup

* Move to experimental manual

* Use 'kind' so tuples continue to fail like before

* Explicitly disallow tuples

* Table test and document tuples

* Test type reduction

* Disable inferGenericTypes check for CI tests

* Remove tuple info in manual

* Always reduce types. Testing CI

* Fixes

* Ignore tyGenericInst

* Prevent binding already bound generic params

* tyUncheckedArray

* Few more types

* Update manual and check for flag again

* Update tests/generics/treturn_inference.nim

* var candidate, remove flag check again for CI

* Enable check once more

---------

Co-authored-by: SirOlaf <>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2023-08-03 22:49:52 +02:00
Bung
6b913b4741 Revert "fix #22173 sink paramers not moved into closure (refc) (#22… (#22376)
Revert "fix #22173 `sink` paramers not moved into closure (refc) (#22359)"

This reverts commit b40da812f7.
2023-08-03 19:56:05 +02:00
Bung
b40da812f7 fix #22173 sink paramers not moved into closure (refc) (#22359)
* use genRefAssign when assign to sink string

* add test case
2023-08-02 14:08:51 +02:00
ringabout
825a0e7df4 fixes #22362; Compiler crashes with staticBoundsCheck on (#22363) 2023-08-02 11:00:34 +02:00
ringabout
f3a7622514 fixes #22360; compare with the half of randMax (#22361)
* fixes #22360; compare with the half of randMax

* add a test
2023-08-02 10:58:29 +02:00
Michal Maršálek
da368885da Fix the position of "Grey" in colors.nim (#22358)
Update the position of "Grey"
2023-08-01 20:56:38 +02:00
ringabout
1d2c27d2e6 bump the devel version to 211 (#22356) 2023-08-01 16:48:52 +02:00
ringabout
a23e53b490 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
2023-08-01 15:18:08 +02:00
Andreas Rumpf
35ff70f36c Tomorrow is the release. I hope. (#22353) 2023-07-31 20:19:18 +02:00
ringabout
0b3ddd4e47 Revert "fixes #22246; generate __builtin_unreachable hints for case defaults" (#22351)
Revert "fixes #22246; generate `__builtin_unreachable` hints for case defaults (#22350)"

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

* use elif

* indentation

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

* Update doc/destructors.md

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

---------

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

* Update changelogs/changelog_2_0_0_details.md

---------

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

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

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

* use an additional flag

* improve some logics

* progress: fixes discard ensureMove

* forbids nested expressions

* improve error messages

* checkpoint

* fixes cursor

* ADD MORE TESTS

* fixes cursorinference again

* tiny cleanup

* improve error messages

* fixes docs

* implement comments add more tests

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

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

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

* undefault nimPreviewRangeDefault

* fixes tests

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

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

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

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

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

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

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

* add a test case for #22210

* minor

* inserts a needsCompletion flag

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

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

* Moving example

* typo

* adding code example back and fix terms

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

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

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

This is done instead of adding another inXyz bool parameter

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

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

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

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

* Always suggest tuple fields if it passes the filter

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

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

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

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

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

* clean up and add comments

* Update compiler/ccgtypes.nim

* tidy up

* fixes comments

* fixes cpp

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

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

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

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

* Go with alternative fix: Sem comments but ignore them

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

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

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

* changelog that people want to actually read

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

* cleans up and adds a test case for #19101

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

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

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

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

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

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

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

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

* fixes system

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

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

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

* add `newRefdestructor`

* adds ref overload for destructors

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

Just so the regression doesn't happen again

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

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

fixes #13302

* remove comment for brevity

* try note

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

fixes #19929

* fix float -> uint64 conversion too

* no need to mask to source type

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

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

* use default computation

* Update lib/pure/collections/tables.nim

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

* Update lib/pure/collections/tables.nim

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

* Update lib/pure/collections/tables.nim

* Update lib/pure/collections/tables.nim

* Update t20023.nim

---------

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

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

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

* Avoiding nimvm differences in tests

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

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

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

* Adding support to VM

* Wrapped C structs and funcs

* Fix javascript impl

* Fixing struct compat

* Segregate tests, better compiletime defs

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

* Apply suggestions from code review

* Explicit structures

---------

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

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

was fixed by #22029

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

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

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

* rethink fixes

* add test cases

* templates only

* fixes var tuples

* keep varness no matter what

* fixes typ.isNil

* make it work for generics

* restore isSubrange

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

fixes #16005

* correct logic for nkRecList children, inject fields

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

* Update tsets.nim

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

* prevents ilegal recursion

* fixes ilegal recursion. Test passes with a better message

* Apply suggestions from code review

---------

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

hopefully actually fixes (space) #22059

* forward declare

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

* legacy switch for CI, maybe experimental later

* convert to experimental

* apparently untyped needs the experimental switch

* try special case call semcheck

* try fix

* fix compilation

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

* remove last needed use of untyped

* fix unused warning in test

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

* simplify

* fixes

* fixes

* allow ".."

* cleanup

* add a test case

* slightly modify the import

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

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

* make old code work

* fix custom number literals test

* remove leftover debug marker

* enable "bug 9" test too

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

fixes #16324

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

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

* Add changelog entry

---------

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

* progress

* make tests green

* progress

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

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

* generate by detect.nim

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

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

* fixes tests

* fixes spawn finally

* fixes views

* rename to internalMove

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

* updates constructor docs

* Update doc/manual_experimental.md

---------

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

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

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

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

* remove owned

* fixes refs

* lift destructors

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

* Update .github/workflows/stale.yml

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

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

* Apply suggestions from code review

---------

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

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

* mention exact slice issue

* magics into system

* move trangechecks into overflow

* move tmemory to system

* try fix CI

* try fix CI

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

fixes #21982

* fix dochelpers

* this is remarkably common

* use head for unchained

* fix atlas

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

* mirrors semoperand

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

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

* silly typo

* make tests green; lockfile implementation begins to make sense

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

* Update important_packages.nim

---------

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

* document `=dup`

* typo

* minor improvement

* typo

* Update doc/destructors.md

* Update doc/destructors.md

* Update doc/destructors.md

---------

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

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

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

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

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

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

* Add github action stale,remove deprecated stalebot

* Add github action stale,remove deprecated stalebot

* Update .github/workflows/stale.yml

* Update .github/workflows/stale.yml

---------

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

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

t

* fix test so it doesnt use echo in globals

* Update compiler/ccgtypes.nim

* Update lib/std/private/dragonbox.nim

---------

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

* ignore define for now to test

* remove cstring

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

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

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

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

* fixes merge conflict

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

* Determine if we should use v prefix

* get tag from latest tag, patch nimble file

* Just do tags for now

* atlas tag now tags and pushes

* Improve UX of `atlas tag`

* better description for `tag`

* Small fixup

* Consistent naming

* strip after checking status

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

* undo testing comment

* Fix for `v` prefixed versions

* Avoid useless assignment

* Remove uselss enum assignment

* Consistent parameter seperation

* Add error handling for non-semver tags

* Use `assert` to quit on error

* Update tools/atlas/atlas.nim

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

* Don't push tags if errors occurred

* Allow `atlas tag [tag]` again

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

* Document the three input options

* Take up less lines in help

* Less or in help

* One last doc pass

* Check args length

* clarify last tag

* consistency/order

---------

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

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

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

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

* Clean out nimbase.h

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

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

* Allow running `atlas search` outside of a workspace

* Check `len` instead of `dirExists`

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

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

* Fix nimgrab client not closing

* Fix nimgrab client not closing

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

* remove comments

* add a test case

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

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

* better workspace/project handling

* make tests green again

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

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

This removes the problem with the symbol having different types

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

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

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

fixes #16985, fixes #16074

* fix

* add changelog too

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

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

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

* Fix jsgen FrameInfo

* Fix jsgen FrameInfo

* .

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

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

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

* Update compiler/pragmas.nim

---------

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

* use temporary PR branch for neo

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

* Apply suggestions from code review

---------

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

* marks virtual procs as infix

* forward declare vfuncs inside the typedef

* adds naked callConv to virtual

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

* first param is now this. extracts genvirtualheaderproc

* WIP syntax

* supports obj. Removes the need for the prefix

* parameter count starts as this. Cleanup

* clean up

* sem tests

* adds integration tests

* uses constraint to store the virtual content

* introduces genVirtualProcParams

---------

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

* skip nimnodes

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

* wip

* docs update, WIP

* progress

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

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

* reuse `osappdirs.getDataDir`

* Update lib/std/appdirs.nim

---------

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

* use original types

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

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

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

* Update lib/pure/collections/sequtils.nim

* Add minmax note to changelog.

---------

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

* fixes typo

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

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

* Update doc/destructors.md

* Update doc/destructors.md

---------

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

* adds tests and multiple fixes

* add test cases

* refactor and remove startId

* fixes custom hooks and adds tests

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

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

* fixes a space

* fixes `shrink` instead

* tiny fix

* fixes vm

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

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

* fixes cpp tests

---------

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

fixes #21803

* try fix clang, debug linux failure

* just make duplicated procs not rtl

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

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

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

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

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

* Add build-id=none to Clang

* Fix

* Fix

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

* Update lib/nimbase.h

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

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

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

This reverts commit b74d49c037.

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

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

* Update tests/enum/tenum.nim

* Update tests/enum/tenum.nim

* fixes tests

* Update tests/enum/tenum.nim

---------

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

* add dup

* add a test for dup

* fixes documentation

* fixes signature

* resolve comments

* fixes tests

* fixes tests

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

* fix CI

* showcase for more reductions, will revert

* Revert "showcase for more reductions, will revert"

This reverts commit 5ba48591f4.

* make line and column int32

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

Fixes these bugs:

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

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

* remove nfIsRef from the output of macros

* make the logic better

* try again

* act together

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

* Fix typos

* Fix manual.md

* Update doc/manual.md

---------

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

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

* fixes #21792

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

fixes #21724 but might break code

* alternative, should fix CI

* other alternative, add test for previous CI failure

* not needed

* make sure call doesn't compile too

* ok actual second test

* ok final actual correct test

* apply performance idea

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

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

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

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

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

* also better tuple subscript error message

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

* boot the compiler

* fixes tests

* build the documentation

* fixes docs

* lol, I forgot koch.nim

* add `nimHasChecksums` define

* clone checksums but maybe copying is better

* bump nimble hash

* use ChecksumsStableCommit

* fixes tests

* deprecate them

* fixes paths

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

* add a test case for #21483

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

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

* doc update

* progress

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

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

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

* Update .github/workflows/ci_bench.yml

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

---------

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

* Update doc/manual.md

---------

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

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

* use new disamb field

* see if this makes tests green

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

fixes #21706

* all targets

* and isNil and repr

* separate overloads, fix sameType

* more restricted sameType?

* merge overloads again??

* remove sametype change for now

* fix sameType anyway (CI failure was not related)

---------

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

refs #21709

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

* even better, cannot use alias syntax with generics

* more type tests, improve comment

* fix again

* consistent error message + make t5167_5 work

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

* typo

* fixes line numbers

* disable cpp

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

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

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

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

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

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

Because EINTR is not a const on i386

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

* add a test case

* add one more test

* fixes the type of block

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

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

fixes #21635

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

* more tests

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

* add test for #21677

* don't export

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

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

* oh my god

* boot at least

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

* fix runnable example

* test assuming 0..255 for int literal

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

* add a test case

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

* [skip ci] Update changelogs/changelog_2_0_0.md

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

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

---------

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

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

refs #19802

* in any case

* just be honest

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

fixes #21652

* fix other test

* different patch

* fix tests

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

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

fixes #19225

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

* fix CI

* convert to compile option

* fix lie

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

* please don't tell me other packages do this

* fix CI + test typeclass callconv pragma

* better logic in parser

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

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

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

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

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

* Fixup: this should still be a func

* Run test case on js target

* Adapt testcase to contributor guide and best practices

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

* Add example code to lib/system.nim

* Fix compile error

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

Fixes #21593

* Properly cast intVal as unsigned

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

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

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

fixes #20687, fixes #21435

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

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

* set temp symbol AST

* hopeful fix some issues, add test for #19364

* always use temp for consts

* document, fix small issue

* fix manual indentation

* actually fix manual

* use helper proc

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

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

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

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

View File

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

69
.github/stale.yml vendored
View File

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

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

@@ -0,0 +1,23 @@
# See https://github.com/juancarlospaco/nimrun-action/issues/3#issuecomment-1607344901
name: issue comments bisects
on:
issue_comment:
types: created
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# nimrun-action requires Nim installed.
- uses: jiro4989/setup-nim-action@v1
with:
nim-version: 'devel'
- name: Install Dependencies
run: sudo apt-get install --no-install-recommends -yq valgrind
- uses: juancarlospaco/nimrun-action@nim
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

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

@@ -0,0 +1,115 @@
name: Benchmarks CI
on:
pull_request:
push:
branches:
- 'devel'
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04]
cpu: [amd64]
name: '${{ matrix.os }}'
runs-on: ${{ matrix.os }}
timeout-minutes: 60 # refs bug #18178
steps:
- name: 'Checkout'
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: 'Install node.js 16.x'
uses: actions/setup-node@v3
with:
node-version: '16.x'
- name: 'Install dependencies (Linux amd64)'
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
run: |
sudo apt-fast update -qq
DEBIAN_FRONTEND='noninteractive' \
sudo apt-fast install --no-install-recommends -yq \
libcurl4-openssl-dev libgc-dev libsdl1.2-dev libsfml-dev \
valgrind libc6-dbg libblas-dev xorg-dev
- name: 'Add build binaries to PATH'
shell: bash
run: echo "${{ github.workspace }}/bin" >> "${GITHUB_PATH}"
- name: 'Build csourcesAny'
shell: bash
run: . ci/funs.sh && nimBuildCsourcesIfNeeded CC=gcc ucpu='${{ matrix.cpu }}'
- name: 'Build koch'
shell: bash
run: nim c koch
- name: 'Build Nim'
shell: bash
run: ./koch boot -d:release -d:nimStrictMode --lib:lib
- name: 'Build Nimble'
shell: bash
run: ./koch nimble
- name: 'Action'
shell: bash
run: nim c -r -d:release ci/action.nim
- name: 'Checkout minimize'
uses: actions/checkout@v4
with:
repository: 'nim-lang/ci_bench'
path: minimize
- name: 'Run minimize benchmarks'
shell: bash
run: ./minimize/minimize ci-bench
- name: 'Restore minimize cached database'
uses: actions/cache/restore@v3
with:
path: minimize.csv
key: minimize-db-key
- name: 'Update minimize db'
shell: bash
run: ./minimize/minimize update-db
- name: 'Save minimize cached database'
if: |
github.event_name == 'push' && github.ref == 'refs/heads/devel' &&
matrix.target == 'linux'
uses: actions/cache/save@v3
with:
path: minimize.csv
key: minimize-db-key
- name: 'Generate minimize report'
shell: bash
run: ./minimize/minimize generate-report
- name: 'Archive minimize report'
uses: actions/upload-artifact@v3
with:
name: minimize-report
path: |
minimize/minimize.html
minimize/minimize.csv
# Requires additional permissions, see:
# https://github.com/nim-lang/Nim/actions/runs/4778177321/jobs/8494423792?pr=21566
# - name: 'Publish HTML report'
# uses: rossjrw/pr-preview-action@v1
# with:
# source-dir: minimize
# umbrella-dir: minimize
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Extract md summary
run: |
cat minimize/summary.md >> $GITHUB_STEP_SUMMARY

View File

@@ -2,8 +2,7 @@ name: Nim Docs CI
on:
push:
paths:
- 'compiler/docgen.nim'
- 'compiler/renderverbatim.nim'
- 'compiler/**.nim'
- 'config/nimdoc.cfg'
- 'doc/**.rst'
- 'doc/**.md'
@@ -18,8 +17,7 @@ on:
pull_request:
# Run only on changes on these files.
paths:
- 'compiler/docgen.nim'
- 'compiler/renderverbatim.nim'
- 'compiler/**.nim'
- 'config/nimdoc.cfg'
- 'doc/**.rst'
- 'doc/**.md'
@@ -55,7 +53,7 @@ jobs:
steps:
- name: 'Checkout'
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2

View File

@@ -28,7 +28,7 @@ jobs:
NIM_TESTAMENT_BATCH: ${{ matrix.batch }}
steps:
- name: 'Checkout'
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2

View File

@@ -17,7 +17,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: 'Checkout'
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2

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

@@ -0,0 +1,25 @@
# https://github.com/actions/stale#usage
name: Stale pull requests
on:
schedule:
- cron: '0 0 * * *' # Midnight.
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v8
with:
days-before-pr-stale: 365
days-before-pr-close: 30
days-before-issue-stale: -1
days-before-issue-close: -1
exempt-pr-labels: "ARC,bounty,Codegen,Crash,Generics,High Priority,Macros,Next release,Showstopper,Static[T]"
exempt-issue-labels: "Showstopper,Severe,bounty,Compiler Crash,Medium Priority"
stale-pr-message: >
This pull request is stale because it has been open for 1 year with no activity.
Contribute more commits on the pull request and rebase it on the latest devel,
or it will be closed in 30 days. Thank you for your contributions.
close-pr-message: >
This pull request has been marked as stale and closed due to inactivity after 395 days.

2
.gitignore vendored
View File

@@ -110,3 +110,5 @@ htmldocs
nimdoc.out.css
# except here:
!/nimdoc/testproject/expected/*
pkgs/
/compiler/compiler/

View File

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

View File

@@ -23,11 +23,11 @@ jobs:
vmImage: 'ubuntu-20.04'
CPU: amd64
# regularly breaks, refs bug #17325
Linux_i386:
# on 'ubuntu-16.04' (not supported anymore anyways) it errored with:
# g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed
vmImage: 'ubuntu-18.04'
CPU: i386
# Linux_i386:
# # on 'ubuntu-16.04' (not supported anymore anyways) it errored with:
# # g++-multilib : Depends: gcc-multilib (>= 4:5.3.1-1ubuntu1) but it is not going to be installed
# vmImage: 'ubuntu-18.04'
# CPU: i386
OSX_amd64:
vmImage: 'macOS-11'
CPU: amd64

View File

@@ -10,7 +10,9 @@
[//]: # "Additions:"
- Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes.
- Added `newStringUninit` to system, which creates a new string of length `len` like `newString` but with uninitialized content.
- Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value.
[//]: # "Deprecations:"
@@ -25,7 +27,7 @@
## Compiler changes
## Tool changes
- koch now allows bootstrapping with `-d:nimHasLibFFI`, replacing the older option of building the compiler directly w/ the `libffi` nimble package in tow.

View File

@@ -1,367 +1,330 @@
# v2.0.0 - yyyy-mm-dd
# v2.0.0 - 2023-08-01
Version 2.0 is a big milestone with too many changes to list them all here.
## Changes affecting backward compatibility
- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response. It follows Apache HttpClient(Java), http(go) and .Net HttpWebResponse(C#) behavior. Previously it raised `ValueError`.
For a full list see [details](changelog_2_0_0_details.html).
- `addr` is now available for all addressable locations,
`unsafeAddr` is now deprecated and an alias for `addr`.
- Certain definitions from the default `system` module have been moved to
the following new modules:
## New features
- `std/syncio`
- `std/assertions`
- `std/formatfloat`
- `std/objectdollar`
- `std/widestrs`
- `std/typedthreads`
- `std/sysatomics`
### Better tuple unpacking
In the future, these definitions will be removed from the `system` module,
and their respective modules will have to be imported to use them.
Currently, to make these imports required, the `-d:nimPreviewSlimSystem` option
may be used.
Tuple unpacking for variables is now treated as syntax sugar that directly
expands into multiple assignments. Along with this, tuple unpacking for
variables can now be nested.
- Enabling `-d:nimPreviewSlimSystem` also removes the following deprecated
symbols in the `system` module:
- Aliases with `Error` suffix to exception types that have a `Defect` suffix
(see [exceptions](https://nim-lang.github.io/Nim/exceptions.html)):
`ArithmeticError`, `DivByZeroError`, `OverflowError`,
`AccessViolationError`, `AssertionError`, `OutOfMemError`, `IndexError`,
`FieldError`, `RangeError`, `StackOverflowError`, `ReraiseError`,
`ObjectAssignmentError`, `ObjectConversionError`, `FloatingPointError`,
`FloatOverflowError`, `FloatUnderflowError`, `FloatInexactError`,
`DeadThreadError`, `NilAccessError`
- `addQuitProc`, replaced by `exitprocs.addExitProc`
- Legacy unsigned conversion operations: `ze`, `ze64`, `toU8`, `toU16`, `toU32`
- `TaintedString`, formerly a distinct alias to `string`
- `PInt32`, `PInt64`, `PFloat32`, `PFloat64`, aliases to
`ptr int32`, `ptr int64`, `ptr float32`, `ptr float64`
```nim
proc returnsNestedTuple(): (int, (int, int), int, int) = (4, (5, 7), 2, 3)
- Enabling `-d:nimPreviewSlimSystem` removes the import of `channels_builtin` in
in the `system` module.
# Now nesting is supported!
let (x, (_, y), _, z) = returnsNestedTuple()
- Enabling `-d:nimPreviewCstringConversion`, `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` don't support conversion to cstring anymore.
```
- The `gc:v2` option is removed.
### Improved type inference
- The `mainmodule` and `m` options are removed.
A new form of type inference called [top-down inference](https://nim-lang.github.io/Nim/manual_experimental.html#topminusdown-type-inference) has been implemented for a variety of basic cases.
- The `threads:on` option is now the default.
For example, code like the following now compiles:
- Optional parameters in combination with `: body` syntax (RFC #405) are now opt-in via
`experimental:flexibleOptionalParams`.
```nim
let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")]
```
- Automatic dereferencing (experimental feature) is removed.
### Forbidden Tags
- The `Math.trunc` polyfill for targeting Internet Explorer was
previously included in most JavaScript output files.
Now, it is only included with `-d:nimJsMathTruncPolyfill`.
If you are targeting Internet Explorer, you may choose to enable this option
or define your own `Math.trunc` polyfill using the [`emit` pragma](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma).
Nim uses `Math.trunc` for the division and modulo operators for integers.
[Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) now supports the definition
of forbidden tags by the `.forbids` pragma which can be used to disable certain effects in proc types.
- `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and
`sink` for optimization purposes.
For example:
- The experimental `nimPreviewDotLikeOps` switch is going to be removed or deprecated because it didn't fullfill its promises.
```nim
- The `{.this.}` pragma, deprecated since 0.19, has been removed.
- `nil` literals can no longer be directly assigned to variables or fields of `distinct` pointer types. They must be converted instead.
```nim
type Foo = distinct ptr int
# Before:
var x: Foo = nil
# After:
var x: Foo = Foo(nil)
```
- Removed two type pragma syntaxes deprecated since 0.20, namely
`type Foo = object {.final.}`, and `type Foo {.final.} [T] = object`.
- `foo a = b` now means `foo(a = b)` rather than `foo(a) = b`. This is consistent
with the existing behavior of `foo a, b = c` meaning `foo(a, b = c)`.
This decision was made with the assumption that the old syntax was used rarely;
if your code used the old syntax, please be aware of this change.
- [Overloadable enums](https://nim-lang.github.io/Nim/manual.html#overloadable-enum-value-names) and Unicode Operators
are no longer experimental.
type IO = object ## input/output effect
proc readLine(): string {.tags: [IO].} = discard
proc echoLine(): void = discard
- Removed the `nimIncrSeqV3` define.
proc no_IO_please() {.forbids: [IO].} =
# this is OK because it didn't define any tag:
echoLine()
# the compiler prevents this:
let y = readLine()
- `macros.getImpl` for `const` symbols now returns the full definition node
(as `nnkConstDef`) rather than the AST of the constant value.
```
- Lock levels are deprecated, now a noop.
### New standard library modules
- ORC is now the default memory management strategy. Use
`--mm:refc` for a transition period.
- `strictEffects` are no longer experimental.
Use `legacy:laxEffects` to keep backward compatibility.
- The `gorge`/`staticExec` calls will now return a descriptive message in the output
if the execution fails for whatever reason. To get back legacy behaviour use `-d:nimLegacyGorgeErrors`.
- Pointer to `cstring` conversion now triggers a `[PtrToCstringConv]` warning.
This warning will become an error in future versions! Use a `cast` operation
like `cast[cstring](x)` instead.
- `logging` will default to flushing all log level messages. To get the legacy behaviour of only flushing Error and Fatal messages, use `-d:nimV1LogFlushBehavior`.
- Redefining templates with the same signature was previously
allowed to support certain macro code. To do this explicitly, the
`{.redefine.}` pragma has been added. Note that this is only for templates.
Implicit redefinition of templates is now deprecated and will give an error in the future.
- Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead.
- Several Standard libraries are moved to nimble packages, use `nimble` to install them:
- `std/punycode` => `punycode`
- `std/asyncftpclient` => `asyncftpclient`
- `std/smtp` => `smtp`
- `std/db_common` => `db_connector/db_common`
- `std/db_sqlite` => `db_connector/db_sqlite`
- `std/db_mysql` => `db_connector/db_mysql`
- `std/db_postgres` => `db_connector/db_postgres`
- `std/db_odbc` => `db_connector/db_odbc`
- Previously, calls like `foo(a, b): ...` or `foo(a, b) do: ...` where the final argument of
`foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`.
This behavior is now deprecated. Use `foo(a, b) do (): ...` or `foo(a, b, proc () = ...)` instead.
- If no exception or any exception deriving from Exception but not Defect or CatchableError given in except, a `warnBareExcept` warning will be triggered.
- The experimental strictFuncs feature now disallows a store to the heap via a `ref` or `ptr` indirection.
- Underscores (`_`) as routine parameters are now ignored and cannot be used in the routine body.
The following code now does not compile:
```nim
proc foo(_: int): int = _ + 1
echo foo(1)
```
Instead, the following code now compiles:
```nim
proc foo(_, _: int): int = 123
echo foo(1, 2)
```
- Underscores (`_`) as generic parameters are not supported and cannot be used.
Generics that use `_` as parameters will no longer compile requires you to replace `_` with something else:
```nim
proc foo[_](t: typedesc[_]): string = "BAR" # Can not compile
proc foo[T](t: typedesc[T]): string = "BAR" # Can compile
```
- - Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages.
## Standard library additions and changes
[//]: # "Changes:"
- OpenSSL 3 is now supported.
- `macros.parseExpr` and `macros.parseStmt` now accept an optional
filename argument for more informative errors.
- Module `colors` expanded with missing colors from the CSS color standard.
`colPaleVioletRed` and `colMediumPurple` have also been changed to match the CSS color standard.
- Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)).
- The `md5` module now works at compile time and in JavaScript.
- Changed `mimedb` to use an `OrderedTable` instead of `OrderedTableRef` to support `const` tables.
- `strutils.find` now uses and defaults to `last = -1` for whole string searches,
making limiting it to just the first char (`last = 0`) valid.
- `random.rand` now works with `Ordinal`s.
- Undeprecated `os.isvalidfilename`.
- `std/oids` now uses `int64` to store time internally (before it was int32).
- `std/uri.Uri` dollar `$` improved, precalculates the `string` result length from the `Uri`.
- `std/uri.Uri.isIpv6` is now exported.
- `std/logging.ConsoleLogger` and `FileLogger` now have a `flushThreshold` attribute to set what log message levels are automatically flushed. For Nim v1 use `-d:nimFlushAllLogs` to automatically flush all message levels. Flushing all logs is the default behavior for Nim v2.
- `std/net.IpAddress` dollar `$` improved, uses a fixed capacity for the `string` result based from the `IpAddressFamily`.
- `std/jsfetch.newFetchOptions` now has default values for all parameters
- `std/jsformdata` now accepts `Blob` data type.
- `std/sharedlist` and `std/sharedtables` are now deprecated, see RFC [#433](https://github.com/nim-lang/RFCs/issues/433).
- New compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove dependency on linux `getrandom` syscall.
This compile flag only affects linux builds and is necessary if either compiling on a linux kernel version < 3.17, or if code built will be executing on kernel < 3.17.
On linux kernels < 3.17 (such as kernel 3.10 in RHEL7 and CentOS7), the `getrandom` syscall was not yet introduced. Without this, the `std/sysrand` module will not build properly, and if code is built on a kernel >= 3.17 without the flag, any usage of the `std/sysrand` module will fail to execute on a kernel < 3.17 (since it attempts to perform a syscall to `getrandom`, which isn't present in the current kernel). A compile flag has been added to force the `std/sysrand` module to use /dev/urandom (available since linux kernel 1.3.30), rather than the `getrandom` syscall. This allows for use of a cryptographically secure PRNG, regardless of kernel support for the `getrandom` syscall.
When building for RHEL7/CentOS7 for example, the entire build process for nim from a source package would then be:
```sh
$ yum install devtoolset-8 # Install GCC version 8 vs the standard 4.8.5 on RHEL7/CentOS7. Alternatively use -d:nimEmulateOverflowChecks. See issue #13692 for details
$ scl enable devtoolset-8 bash # Run bash shell with default toolchain of gcc 8
$ sh build.sh # per unix install instructions
$ bin/nim c koch # per unix install instructions
$ ./koch boot -d:release # per unix install instructions
$ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall
```
This is necessary to pass when building nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for stdlib (sysrand in particular).
[//]: # "Additions:"
- Added ISO 8601 week date utilities in `times`:
- Added `IsoWeekRange`, a range type for weeks in a week-based year.
- Added `IsoYear`, a distinct type for a week-based year in contrast to a regular year.
- Added a `initDateTime` overload to create a datetime from an ISO week date.
- Added `getIsoWeekAndYear` to get an ISO week number and week-based year from a datetime.
- Added `getIsoWeeksInYear` to return the number of weeks in a week-based year.
- Added new modules which were part of `std/os`:
- Added `std/oserrors` for OS error reporting. Added `std/envvars` for environment variables handling.
- Added `std/paths`, `std/dirs`, `std/files`, `std/symlinks` and `std/appdirs`.
- Added `std/cmdline` for reading command line parameters.
- Added `sep` parameter in `std/uri` to specify the query separator.
- Added bindings to [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift)
and [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask)
in `jscore` for JavaScript targets.
- Added `UppercaseLetters`, `LowercaseLetters`, `PunctuationChars`, `PrintableChars` sets to `std/strutils`.
- Added `complex.sgn` for obtaining the phase of complex numbers.
- Added `insertAdjacentText`, `insertAdjacentElement`, `insertAdjacentHTML`,
`after`, `before`, `closest`, `append`, `hasAttributeNS`, `removeAttributeNS`,
`hasPointerCapture`, `releasePointerCapture`, `requestPointerLock`,
`replaceChildren`, `replaceWith`, `scrollIntoViewIfNeeded`, `setHTML`,
`toggleAttribute`, and `matches` to `std/dom`.
- Added [`jsre.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices)
- Added `capacity` for `string` and `seq` to return the current capacity, see https://github.com/nim-lang/RFCs/issues/460
- Added `openArray[char]` overloads for `std/parseutils` allowing more code reuse.
- Added `openArray[char]` overloads for `std/unicode` allowing more code reuse.
- Added `safe` parameter to `base64.encodeMime`.
[//]: # "Deprecations:"
- Deprecated `selfExe` for Nimscript.
- Deprecated `std/sums`.
- Deprecated `std/base64.encode` for collections of arbitrary integer element type.
Now only `byte` and `char` are supported.
[//]: # "Removals:"
- Removed deprecated module `parseopt2`.
- Removed deprecated module `sharedstrings`.
- Removed deprecated module `dom_extensions`.
- Removed deprecated module `LockFreeHash`.
- Removed deprecated module `events`.
- Removed deprecated `oids.oidToString`.
- Removed define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`.
- Removed deprecated `jsre.test` and `jsre.toString`.
- Removed deprecated `math.c_frexp`.
- Removed deprecated `` httpcore.`==` ``.
- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that takes wrong argument types.
- Removed deprecated `osproc.poDemon`, symbol with typo.
- Removed deprecated `tables.rightSize`.
- Removed deprecated `posix.CLONE_STOPPED`.
## Language changes
- [Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) supports the definition of forbidden tags by the `.forbids` pragma
which can be used to disable certain effects in proc types.
- [Case statement macros](https://nim-lang.github.io/Nim/manual.html#macros-case-statement-macros) are no longer experimental,
meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them.
- Full command syntax and block arguments i.e. `foo a, b: c` are now allowed
for the right-hand side of type definitions in type sections. Previously
they would error with "invalid indentation".
- Compile-time define changes:
- `defined` now accepts identifiers separated by dots, i.e. `defined(a.b.c)`.
In the command line, this is defined as `-d:a.b.c`. Older versions can
use accents as in ``defined(`a.b.c`)`` to access such defines.
- [Define pragmas for constants](https://nim-lang.github.io/Nim/manual.html#implementation-specific-pragmas-compileminustime-define-pragmas)
now support a string argument for qualified define names.
```nim
# -d:package.FooBar=42
const FooBar {.intdefine: "package.FooBar".}: int = 5
echo FooBar # 42
```
This was added to help disambiguate similar define names for different packages.
In older versions, this could only be achieved with something like the following:
```nim
const FooBar = block:
const `package.FooBar` {.intdefine.}: int = 5
`package.FooBar`
```
- A generic `define` pragma for constants has been added that interprets
the value of the define based on the type of the constant value.
See the [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#generic-define-pragma)
for a list of supported types.
- [Macro pragmas](https://nim-lang.github.io/Nim/manual.html#userminusdefined-pragmas-macro-pragmas) changes:
- Templates now accept macro pragmas.
- Macro pragmas for var/let/const sections have been redesigned in a way that works
similarly to routine macro pragmas. The new behavior is documented in the
[experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#extended-macro-pragmas).
- Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`,
allowing multiple type definitions to be injected in place of the original type definition.
```nim
import macros
macro multiply(amount: static int, s: untyped): untyped =
let name = $s[0].basename
result = newNimNode(nnkTypeSection)
for i in 1 .. amount:
result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2]))
type
Foo = object
Bar {.multiply: 3.} = object
x, y, z: int
Baz = object
# becomes
type
Foo = object
Bar1 = object
x, y, z: int
Bar2 = object
x, y, z: int
Bar3 = object
x, y, z: int
Baz = object
```
- A new form of type inference called [top-down inference](https://nim-lang.github.io/Nim/manual_experimental.html#topminusdown-type-inference)
has been implemented for a variety of basic cases. For example, code like the following now compiles:
```nim
let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")]
```
- `cstring` is now accepted as a selector in `case` statements, removing the
need to convert to `string`. On the JS backend, this is translated directly
to a `switch` statement.
- Nim now supports `out` parameters and ["strict definitions"](https://nim-lang.github.io/Nim/manual_experimental.html#strict-definitions-and-nimout-parameters).
- Nim now offers a [strict mode](https://nim-lang.github.io/Nim/manual_experimental.html#strict-case-objects) for `case objects`.
- IBM Z architecture and macOS m1 arm64 architecture are supported.
- `=wasMoved` can be overridden by users.
## Compiler changes
- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the
reality better. (Nim moved away from all techniques based on "tracing".)
- Defines the `gcRefc` symbol which allows writing specific code for the refc GC.
- `nim` can now compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off compiler/nim`,
without requiring `-d:nimVersion140` which is now a noop.
- `--styleCheck`, `--hintAsError` and `--warningAsError` now only apply to the current package.
- The switch `--nimMainPrefix:prefix` has been added to add a prefix to the names of `NimMain` and
related functions produced on the backend. This prevents conflicts with other Nim
static libraries.
- When compiling for Release the flag `-fno-math-errno` is used for GCC.
The famous `os` module got an overhaul. Several of its features are available
under a new interface that introduces a `Path` abstraction. A `Path` is
a `distinct string`, which improves the type safety when dealing with paths, files
and directories.
Use:
- `std/oserrors` for OS error reporting.
- `std/envvars` for environment variables handling.
- `std/paths` for path handling.
- `std/dirs` for directory creation/deletion/traversal.
- `std/files` for file existence checking, file deletions and moves.
- `std/symlinks` for symlink handling.
- `std/appdirs` for accessing configuration/home/temp directories.
- `std/cmdline` for reading command line parameters.
### Consistent underscore handling
The underscore identifier (`_`) is now generally not added to scope when
used as the name of a definition. While this was already the case for
variables, it is now also the case for routine parameters, generic
parameters, routine declarations, type declarations, etc. This means that the following code now does not compile:
```nim
proc foo(_: int): int = _ + 1
echo foo(1)
proc foo[_](t: typedesc[_]): seq[_] = @[default(_)]
echo foo[int]()
proc _() = echo "_"
_()
type _ = int
let x: _ = 3
```
Whereas the following code now compiles:
```nim
proc foo(_, _: int): int = 123
echo foo(1, 2)
proc foo[_, _](): int = 123
echo foo[int, bool]()
proc foo[T, U](_: typedesc[T], _: typedesc[U]): (T, U) = (default(T), default(U))
echo foo(int, bool)
proc _() = echo "one"
proc _() = echo "two"
type _ = int
type _ = float
```
### JavaScript codegen improvement
The JavaScript backend now uses [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
for 64-bit integer types (`int64` and `uint64`) by default. As this affects
JS code generation, code using these types to interface with the JS backend
may need to be updated. Note that `int` and `uint` are not affected.
For compatibility with [platforms that do not support BigInt](https://caniuse.com/bigint)
and in the case of potential bugs with the new implementation, the
old behavior is currently still supported with the command line option
`--jsbigint64:off`.
## Docgen improvements
`Markdown` is now the default markup language of doc comments (instead
of the legacy `RstMarkdown` mode). In this release we begin to separate
RST and Markdown features to better follow specification of each
language, with the focus on Markdown development.
See also [the docs](https://nim-lang.github.io/Nim/markdown_rst.html).
* Added a `{.doctype: Markdown | RST | RstMarkdown.}` pragma allowing to
select the markup language mode in the doc comments of the current `.nim`
file for processing by `nim doc`:
1. `Markdown` (default) is basically CommonMark (standard Markdown) +
some Pandoc Markdown features + some RST features that are missing
in our current implementation of CommonMark and Pandoc Markdown.
2. `RST` closely follows the RST spec with few additional Nim features.
3. `RstMarkdown` is a maximum mix of RST and Markdown features, which
is kept for the sake of compatibility and ease of migration.
* Added separate `md2html` and `rst2html` commands for processing
standalone `.md` and `.rst` files respectively (and also `md2tex`/`rst2tex`).
* Added Pandoc Markdown bracket syntax `[...]` for making anchor-less links.
* Docgen now supports concise syntax for referencing Nim symbols:
instead of specifying HTML anchors directly one can use original
Nim symbol declarations (adding the aforementioned link brackets
`[...]` around them).
* To use this feature across modules, a new `importdoc` directive was added.
Using this feature for referencing also helps to ensure that links
(inside one module or the whole project) are not broken.
* Added support for RST & Markdown quote blocks (blocks starting with `>`).
* Added a popular Markdown definition lists extension.
* Added Markdown indented code blocks (blocks indented by >= 4 spaces).
* Added syntax for additional parameters to Markdown code blocks:
```nim test="nim c $1"
...
```
## C++ interop enhancements
Nim 2.0 takes C++ interop to the next level. With the new [virtual](https://nim-lang.github.io/Nim/manual_experimental.html#virtual-pragma) pragma and the extended [constructor](https://nim-lang.github.io/Nim/manual_experimental.html#constructor-pragma) pragma.
Now one can define constructors and virtual procs that maps to C++ constructors and virtual methods, allowing one to further customize
the interoperability. There is also extended support for the [codeGenDecl](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-codegendecl-pragma) pragma, so that it works on types.
It's a common pattern in C++ to use inheritance to extend a library. Some even use multiple inheritance as a mechanism to make interfaces.
Consider the following example:
```cpp
struct Base {
int someValue;
Base(int inValue) {
someValue = inValue;
};
};
class IPrinter {
public:
virtual void print() = 0;
};
```
```nim
type
Base* {.importcpp, inheritable.} = object
someValue*: int32
IPrinter* {.importcpp.} = object
const objTemplate = """
struct $1 : public $3, public IPrinter {
$2
};
""";
type NimChild {.codegenDecl: objTemplate .} = object of Base
proc makeNimChild(val: int32): NimChild {.constructor: "NimClass('1 #1) : Base(#1)".} =
echo "It calls the base constructor passing " & $this.someValue
this.someValue = val * 2 # Notice how we can access `this` inside the constructor. It's of the type `ptr NimChild`.
proc print*(self: NimChild) {.virtual.} =
echo "Some value is " & $self.someValue
let child = makeNimChild(10)
child.print()
```
It outputs:
```
It calls the base constructor passing 10
Some value is 20
```
## ARC/ORC refinements
With the 2.0 release, the ARC/ORC model got refined once again and is now finally complete:
1. Programmers now have control over the "item was moved from" state as `=wasMoved` is overridable.
2. There is a new `=dup` hook which is more efficient than the old combination of `=wasMoved(tmp); =copy(tmp, x)` operations.
3. Destructors now take a parameter of the attached object type `T` directly and don't have to take a `var T` parameter.
With these important optimizations we improved the runtime of the compiler and important benchmarks by 0%! Wait ... what?
Yes, unfortunately it turns out that for a modern optimizer like in GCC or LLVM there is no difference.
But! This refined model is more efficient once separate compilation enters the picture. In other words, as we think of
providing a stable ABI it is important not to lose any efficiency in the calling conventions.
## Tool changes
- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs`).
- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs` before). Use `nimble develop --global` to create an old style link file in the special links directory documented at https://github.com/nim-lang/nimble#nimble-develop.
- nimgrep now offers the option `--inContext` (and `--notInContext`), which
allows to filter only matches with the context block containing a given pattern.
- nimgrep: names of options containing "include/exclude" are deprecated,
e.g. instead of `--includeFile` and `--excludeFile` we have
`--filename` and `--notFilename` respectively.
Also, the semantics are now consistent for such positive/negative filters.
- Nim now ships with an alternative package manager called Atlas. More on this in upcoming versions.
## Porting guide
### Block and Break
Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead. In other words, turn:
```nim
block:
a()
if cond:
break
b()
```
Into:
```nim
block maybePerformB:
a()
if cond:
break maybePerformB
b()
```
### Strict funcs
The definition of `"strictFuncs"` was changed.
The old definition was roughly: "A store to a ref/ptr deref is forbidden unless it's coming from a `var T` parameter".
The new definition is: "A store to a ref/ptr deref is forbidden."
This new definition is much easier to understand, the price is some expressitivity. The following code used to be
accepted:
```nim
{.experimental: "strictFuncs".}
type Node = ref object
s: string
func create(s: string): Node =
result = Node()
result.s = s # store to result[]
```
Now it has to be rewritten to:
```nim
{.experimental: "strictFuncs".}
type Node = ref object
s: string
func create(s: string): Node =
result = Node(s: s)
```
### Standard library
Several standard library modules have been moved to nimble packages, use `nimble` or `atlas` to install them:
- `std/punycode` => `punycode`
- `std/asyncftpclient` => `asyncftpclient`
- `std/smtp` => `smtp`
- `std/db_common` => `db_connector/db_common`
- `std/db_sqlite` => `db_connector/db_sqlite`
- `std/db_mysql` => `db_connector/db_mysql`
- `std/db_postgres` => `db_connector/db_postgres`
- `std/db_odbc` => `db_connector/db_odbc`
- `std/md5` => `checksums/md5`
- `std/sha1` => `checksums/sha1`
- `std/sums` => `sums`

View File

@@ -0,0 +1,560 @@
# v2.0.0 - 2023-08-01
## Changes affecting backward compatibility
- ORC is now the default memory management strategy. Use
`--mm:refc` for a transition period.
- The `threads:on` option is now the default.
- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response. It follows Apache's `HttpClient` (Java), `http` (go) and .NET `HttpWebResponse` (C#) behaviors. Previously it raised a `ValueError`.
- `addr` is now available for all addressable locations,
`unsafeAddr` is now deprecated and an alias for `addr`.
- Certain definitions from the default `system` module have been moved to
the following new modules:
- `std/syncio`
- `std/assertions`
- `std/formatfloat`
- `std/objectdollar`
- `std/widestrs`
- `std/typedthreads`
- `std/sysatomics`
In the future, these definitions will be removed from the `system` module,
and their respective modules will have to be imported to use them.
Currently, to make these imports required, the `-d:nimPreviewSlimSystem` option
may be used.
- Enabling `-d:nimPreviewSlimSystem` also removes the following deprecated
symbols in the `system` module:
- Aliases with an `Error` suffix to exception types that have a `Defect` suffix
(see [exceptions](https://nim-lang.github.io/Nim/exceptions.html)):
`ArithmeticError`, `DivByZeroError`, `OverflowError`,
`AccessViolationError`, `AssertionError`, `OutOfMemError`, `IndexError`,
`FieldError`, `RangeError`, `StackOverflowError`, `ReraiseError`,
`ObjectAssignmentError`, `ObjectConversionError`, `FloatingPointError`,
`FloatOverflowError`, `FloatUnderflowError`, `FloatInexactError`,
`DeadThreadError`, `NilAccessError`
- `addQuitProc`, replaced by `exitprocs.addExitProc`
- Legacy unsigned conversion operations: `ze`, `ze64`, `toU8`, `toU16`, `toU32`
- `TaintedString`, formerly a distinct alias to `string`
- `PInt32`, `PInt64`, `PFloat32`, `PFloat64`, aliases to
`ptr int32`, `ptr int64`, `ptr float32`, `ptr float64`
- Enabling `-d:nimPreviewSlimSystem` removes the import of `channels_builtin` in
in the `system` module, which is replaced by [threading/channels](https://github.com/nim-lang/threading/blob/master/threading/channels.nim). Use the command `nimble install threading` and import `threading/channels`.
- Enabling `-d:nimPreviewCstringConversion` causes `ptr char`, `ptr array[N, char]` and `ptr UncheckedArray[N, char]` to not support conversion to `cstring` anymore.
- Enabling `-d:nimPreviewProcConversion` causes `proc` to not support conversion to
`pointer` anymore. `cast` may be used instead.
- The `gc:v2` option is removed.
- The `mainmodule` and `m` options are removed.
- Optional parameters in combination with `: body` syntax ([RFC #405](https://github.com/nim-lang/RFCs/issues/405))
are now opt-in via `experimental:flexibleOptionalParams`.
- Automatic dereferencing (experimental feature) is removed.
- The `Math.trunc` polyfill for targeting Internet Explorer was
previously included in most JavaScript output files.
Now, it is only included with `-d:nimJsMathTruncPolyfill`.
If you are targeting Internet Explorer, you may choose to enable this option
or define your own `Math.trunc` polyfill using the [`emit` pragma](https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma).
Nim uses `Math.trunc` for the division and modulo operators for integers.
- `shallowCopy` and `shallow` are removed for ARC/ORC. Use `move` when possible or combine assignment and
`sink` for optimization purposes.
- The experimental `nimPreviewDotLikeOps` switch is going to be removed or deprecated because it didn't fullfill its promises.
- The `{.this.}` pragma, deprecated since 0.19, has been removed.
- `nil` literals can no longer be directly assigned to variables or fields of `distinct` pointer types. They must be converted instead.
```nim
type Foo = distinct ptr int
# Before:
var x: Foo = nil
# After:
var x: Foo = Foo(nil)
```
- Removed two type pragma syntaxes deprecated since 0.20, namely
`type Foo = object {.final.}`, and `type Foo {.final.} [T] = object`. Instead,
use `type Foo[T] {.final.} = object`.
- `foo a = b` now means `foo(a = b)` rather than `foo(a) = b`. This is consistent
with the existing behavior of `foo a, b = c` meaning `foo(a, b = c)`.
This decision was made with the assumption that the old syntax was used rarely;
if your code used the old syntax, please be aware of this change.
- [Overloadable enums](https://nim-lang.github.io/Nim/manual.html#overloadable-enum-value-names) and Unicode Operators
are no longer experimental.
- `macros.getImpl` for `const` symbols now returns the full definition node
(as `nnkConstDef`) rather than the AST of the constant value.
- Lock levels are deprecated, now a noop.
- `strictEffects` are no longer experimental.
Use `legacy:laxEffects` to keep backward compatibility.
- The `gorge`/`staticExec` calls will now return a descriptive message in the output
if the execution fails for whatever reason. To get back legacy behaviour, use `-d:nimLegacyGorgeErrors`.
- Pointer to `cstring` conversions now trigger a `[PtrToCstringConv]` warning.
This warning will become an error in future versions! Use a `cast` operation
like `cast[cstring](x)` instead.
- `logging` will default to flushing all log level messages. To get the legacy behaviour of only flushing Error and Fatal messages, use `-d:nimV1LogFlushBehavior`.
- Redefining templates with the same signature was previously
allowed to support certain macro code. To do this explicitly, the
`{.redefine.}` pragma has been added. Note that this is only for templates.
Implicit redefinition of templates is now deprecated and will give an error in the future.
- Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead.
- Several Standard libraries have been moved to nimble packages, use `nimble` to install them:
- `std/punycode` => `punycode`
- `std/asyncftpclient` => `asyncftpclient`
- `std/smtp` => `smtp`
- `std/db_common` => `db_connector/db_common`
- `std/db_sqlite` => `db_connector/db_sqlite`
- `std/db_mysql` => `db_connector/db_mysql`
- `std/db_postgres` => `db_connector/db_postgres`
- `std/db_odbc` => `db_connector/db_odbc`
- `std/md5` => `checksums/md5`
- `std/sha1` => `checksums/sha1`
- `std/sums` => `std/sums`
- Previously, calls like `foo(a, b): ...` or `foo(a, b) do: ...` where the final argument of
`foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`.
This behavior is now deprecated. Use `foo(a, b) do (): ...` or `foo(a, b, proc () = ...)` instead.
- When `--warning[BareExcept]:on` is enabled, if an `except` specifies no exception or any exception not inheriting from `Defect` or `CatchableError`, a `warnBareExcept` warning will be triggered. For example, the following code will emit a warning:
```nim
try:
discard
except: # Warning: The bare except clause is deprecated; use `except CatchableError:` instead [BareExcept]
discard
```
- The experimental `strictFuncs` feature now disallows a store to the heap via a `ref` or `ptr` indirection.
- The underscore identifier (`_`) is now generally not added to scope when
used as the name of a definition. While this was already the case for
variables, it is now also the case for routine parameters, generic
parameters, routine declarations, type declarations, etc. This means that the following code now does not compile:
```nim
proc foo(_: int): int = _ + 1
echo foo(1)
proc foo[_](t: typedesc[_]): seq[_] = @[default(_)]
echo foo[int]()
proc _() = echo "_"
_()
type _ = int
let x: _ = 3
```
Whereas the following code now compiles:
```nim
proc foo(_, _: int): int = 123
echo foo(1, 2)
proc foo[_, _](): int = 123
echo foo[int, bool]()
proc foo[T, U](_: typedesc[T], _: typedesc[U]): (T, U) = (default(T), default(U))
echo foo(int, bool)
proc _() = echo "one"
proc _() = echo "two"
type _ = int
type _ = float
```
- Added the `--legacy:verboseTypeMismatch` switch to get legacy type mismatch error messages.
- The JavaScript backend now uses [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
for 64-bit integer types (`int64` and `uint64`) by default. As this affects
JS code generation, code using these types to interface with the JS backend
may need to be updated. Note that `int` and `uint` are not affected.
For compatibility with [platforms that do not support BigInt](https://caniuse.com/bigint)
and in the case of potential bugs with the new implementation, the
old behavior is currently still supported with the command line option
`--jsbigint64:off`.
- The `proc` and `iterator` type classes now respectively only match
procs and iterators. Previously both type classes matched any of
procs or iterators.
```nim
proc prc(): int =
123
iterator iter(): int =
yield 123
proc takesProc[T: proc](x: T) = discard
proc takesIter[T: iterator](x: T) = discard
# always compiled:
takesProc(prc)
takesIter(iter)
# no longer compiles:
takesProc(iter)
takesIter(prc)
```
- The `proc` and `iterator` type classes now accept a calling convention pragma
(i.e. `proc {.closure.}`) that must be shared by matching proc or iterator
types. Previously, pragmas were parsed but discarded if no parameter list
was given.
This is represented in the AST by an `nnkProcTy`/`nnkIteratorTy` node with
an `nnkEmpty` node in the place of the `nnkFormalParams` node, and the pragma
node in the same place as in a concrete `proc` or `iterator` type node. This
state of the AST may be unexpected to existing code, both due to the
replacement of the `nnkFormalParams` node as well as having child nodes
unlike other type class AST.
- Signed integer literals in `set` literals now default to a range type of
`0..255` instead of `0..65535` (the maximum size of sets).
- `case` statements with `else` branches put before `elif`/`of` branches in macros
are rejected with "invalid order of case branches".
- Destructors now default to `.raises: []` (i.e. destructors must not raise
unlisted exceptions) and explicitly raising destructors are implementation
defined behavior.
- The very old, undocumented `deprecated` pragma statement syntax for
deprecated aliases is now a no-op. The regular deprecated pragma syntax is
generally sufficient instead.
```nim
# now does nothing:
{.deprecated: [OldName: NewName].}
# instead use:
type OldName* {.deprecated: "use NewName instead".} = NewName
const oldName* {.deprecated: "use newName instead".} = newName
```
`defined(nimalias)` can be used to check for versions when this syntax was
available; however since code that used this syntax is usually very old,
these deprecated aliases are likely not used anymore and it may make sense
to simply remove these statements.
- `getProgramResult` and `setProgramResult` in `std/exitprocs` are no longer
declared when they are not available on the backend. Previously it would call
`doAssert false` at runtime despite the condition being checkable at compile-time.
- Custom destructors now supports non-var parameters, e.g. ``proc `=destroy`[T: object](x: T)`` is valid. ``proc `=destroy`[T: object](x: var T)`` is deprecated.
- Relative imports will not resolve to searched paths anymore, e.g. `import ./tables` now reports an error properly.
## Standard library additions and changes
[//]: # "Changes:"
- OpenSSL 3 is now supported.
- `macros.parseExpr` and `macros.parseStmt` now accept an optional
`filename` argument for more informative errors.
- The `colors` module is expanded with missing colors from the CSS color standard.
`colPaleVioletRed` and `colMediumPurple` have also been changed to match the CSS color standard.
- Fixed `lists.SinglyLinkedList` being broken after removing the last node ([#19353](https://github.com/nim-lang/Nim/pull/19353)).
- The `md5` module now works at compile time and in JavaScript.
- Changed `mimedb` to use an `OrderedTable` instead of `OrderedTableRef`, to support `const` tables.
- `strutils.find` now uses and defaults to `last = -1` for whole string searches,
making limiting it to just the first char (`last = 0`) valid.
- `strutils.split` and `strutils.rsplit` now return the source string as a single element for an empty separator.
- `random.rand` now works with `Ordinal`s.
- Undeprecated `os.isvalidfilename`.
- `std/oids` now uses `int64` to store time internally (before, it was int32).
- `std/uri.Uri` dollar (`$`) improved, precalculates the `string` result length from the `Uri`.
- `std/uri.Uri.isIpv6` is now exported.
- `std/logging.ConsoleLogger` and `FileLogger` now have a `flushThreshold` attribute to set what log message levels are automatically flushed. For Nim v1 use `-d:nimFlushAllLogs` to automatically flush all message levels. Flushing all logs is the default behavior for Nim v2.
- `std/jsfetch.newFetchOptions` now has default values for all parameters.
- `std/jsformdata` now accepts the `Blob` data type.
- `std/sharedlist` and `std/sharedtables` are now deprecated, see [RFC #433](https://github.com/nim-lang/RFCs/issues/433).
- There is a new compile flag (`-d:nimNoGetRandom`) when building `std/sysrand` to remove the dependency on the Linux `getrandom` syscall.
This compile flag only affects Linux builds and is necessary if either compiling on a Linux kernel version < 3.17, or if code built will be executing on kernel < 3.17.
On Linux kernels < 3.17 (such as kernel 3.10 in RHEL7 and CentOS7), the `getrandom` syscall was not yet introduced. Without this, the `std/sysrand` module will not build properly, and if code is built on a kernel >= 3.17 without the flag, any usage of the `std/sysrand` module will fail to execute on a kernel < 3.17 (since it attempts to perform a syscall to `getrandom`, which isn't present in the current kernel). A compile flag has been added to force the `std/sysrand` module to use /dev/urandom (available since Linux kernel 1.3.30), rather than the `getrandom` syscall. This allows for use of a cryptographically secure PRNG, regardless of kernel support for the `getrandom` syscall.
When building for RHEL7/CentOS7 for example, the entire build process for nim from a source package would then be:
```sh
$ yum install devtoolset-8 # Install GCC version 8 vs the standard 4.8.5 on RHEL7/CentOS7. Alternatively use -d:nimEmulateOverflowChecks. See issue #13692 for details
$ scl enable devtoolset-8 bash # Run bash shell with default toolchain of gcc 8
$ sh build.sh # per unix install instructions
$ bin/nim c koch # per unix install instructions
$ ./koch boot -d:release # per unix install instructions
$ ./koch tools -d:nimNoGetRandom # pass the nimNoGetRandom flag to compile std/sysrand without support for getrandom syscall
```
This is necessary to pass when building Nim on kernel versions < 3.17 in particular to avoid an error of "SYS_getrandom undeclared" during the build process for the stdlib (`sysrand` in particular).
[//]: # "Additions:"
- Added ISO 8601 week date utilities in `times`:
- Added `IsoWeekRange`, a range type for weeks in a week-based year.
- Added `IsoYear`, a distinct type for a week-based year in contrast to a regular year.
- Added an `initDateTime` overload to create a `DateTime` from an ISO week date.
- Added `getIsoWeekAndYear` to get an ISO week number and week-based year from a datetime.
- Added `getIsoWeeksInYear` to return the number of weeks in a week-based year.
- Added new modules which were previously part of `std/os`:
- Added `std/oserrors` for OS error reporting.
- Added `std/envvars` for environment variables handling.
- Added `std/cmdline` for reading command line parameters.
- Added `std/paths`, `std/dirs`, `std/files`, `std/symlinks` and `std/appdirs`.
- Added `sep` parameter in `std/uri` to specify the query separator.
- Added `UppercaseLetters`, `LowercaseLetters`, `PunctuationChars`, `PrintableChars` sets to `std/strutils`.
- Added `complex.sgn` for obtaining the phase of complex numbers.
- Added `insertAdjacentText`, `insertAdjacentElement`, `insertAdjacentHTML`,
`after`, `before`, `closest`, `append`, `hasAttributeNS`, `removeAttributeNS`,
`hasPointerCapture`, `releasePointerCapture`, `requestPointerLock`,
`replaceChildren`, `replaceWith`, `scrollIntoViewIfNeeded`, `setHTML`,
`toggleAttribute`, and `matches` to `std/dom`.
- Added [`jsre.hasIndices`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/hasIndices).
- Added `capacity` for `string` and `seq` to return the current capacity, see [RFC #460](https://github.com/nim-lang/RFCs/issues/460).
- Added `openArray[char]` overloads for `std/parseutils` and `std/unicode`, allowing for more code reuse.
- Added a `safe` parameter to `base64.encodeMime`.
- Added `parseutils.parseSize` - inverse to `strutils.formatSize` - to parse human readable sizes.
- Added `minmax` to `sequtils`, as a more efficient `(min(_), max(_))` over sequences.
- `std/jscore` for the JavaScript target:
+ Added bindings to [`Array.shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift)
and [`queueMicrotask`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask).
+ Added `toDateString`, `toISOString`, `toJSON`, `toTimeString`, `toUTCString` converters for `DateTime`.
- Added `BackwardsIndex` overload for `CacheSeq`.
- Added support for nested `with` blocks in `std/with`.
- Added `ensureMove` to the system module. It ensures that the passed argument is moved, otherwise an error is given at the compile time.
[//]: # "Deprecations:"
- Deprecated `selfExe` for Nimscript.
- Deprecated `std/base64.encode` for collections of arbitrary integer element type.
Now only `byte` and `char` are supported.
[//]: # "Removals:"
- Removed deprecated module `parseopt2`.
- Removed deprecated module `sharedstrings`.
- Removed deprecated module `dom_extensions`.
- Removed deprecated module `LockFreeHash`.
- Removed deprecated module `events`.
- Removed deprecated `oids.oidToString`.
- Removed define `nimExperimentalAsyncjsThen` for `std/asyncjs.then` and `std/jsfetch`.
- Removed deprecated `jsre.test` and `jsre.toString`.
- Removed deprecated `math.c_frexp`.
- Removed deprecated `` httpcore.`==` ``.
- Removed deprecated `std/posix.CMSG_SPACE` and `std/posix.CMSG_LEN` that take wrong argument types.
- Removed deprecated `osproc.poDemon`, symbol with typo.
- Removed deprecated `tables.rightSize`.
- Removed deprecated `posix.CLONE_STOPPED`.
## Language changes
- [Tag tracking](https://nim-lang.github.io/Nim/manual.html#effect-system-tag-tracking) now supports the definition of forbidden tags by the `.forbids` pragma
which can be used to disable certain effects in proc types.
- [Case statement macros](https://nim-lang.github.io/Nim/manual.html#macros-case-statement-macros) are no longer experimental,
meaning you no longer need to enable the experimental switch `caseStmtMacros` to use them.
- Full command syntax and block arguments i.e. `foo a, b: c` are now allowed
for the right-hand side of type definitions in type sections. Previously
they would error with "invalid indentation".
- Compile-time define changes:
- `defined` now accepts identifiers separated by dots, i.e. `defined(a.b.c)`.
In the command line, this is defined as `-d:a.b.c`. Older versions can
use backticks as in ``defined(`a.b.c`)`` to access such defines.
- [Define pragmas for constants](https://nim-lang.github.io/Nim/manual.html#implementation-specific-pragmas-compileminustime-define-pragmas)
now support a string argument for qualified define names.
```nim
# -d:package.FooBar=42
const FooBar {.intdefine: "package.FooBar".}: int = 5
echo FooBar # 42
```
This was added to help disambiguate similar define names for different packages.
In older versions, this could only be achieved with something like the following:
```nim
const FooBar = block:
const `package.FooBar` {.intdefine.}: int = 5
`package.FooBar`
```
- A generic `define` pragma for constants has been added that interprets
the value of the define based on the type of the constant value.
See the [experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#generic-nimdefine-pragma)
for a list of supported types.
- [Macro pragmas](https://nim-lang.github.io/Nim/manual.html#userminusdefined-pragmas-macro-pragmas) changes:
- Templates now accept macro pragmas.
- Macro pragmas for var/let/const sections have been redesigned in a way that works
similarly to routine macro pragmas. The new behavior is documented in the
[experimental manual](https://nim-lang.github.io/Nim/manual_experimental.html#extended-macro-pragmas).
- Pragma macros on type definitions can now return `nnkTypeSection` nodes as well as `nnkTypeDef`,
allowing multiple type definitions to be injected in place of the original type definition.
```nim
import macros
macro multiply(amount: static int, s: untyped): untyped =
let name = $s[0].basename
result = newNimNode(nnkTypeSection)
for i in 1 .. amount:
result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2]))
type
Foo = object
Bar {.multiply: 3.} = object
x, y, z: int
Baz = object
# becomes
type
Foo = object
Bar1 = object
x, y, z: int
Bar2 = object
x, y, z: int
Bar3 = object
x, y, z: int
Baz = object
```
- A new form of type inference called [top-down inference](https://nim-lang.github.io/Nim/manual_experimental.html#topminusdown-type-inference)
has been implemented for a variety of basic cases. For example, code like the following now compiles:
```nim
let foo: seq[(float, byte, cstring)] = @[(1, 2, "abc")]
```
- `cstring` is now accepted as a selector in `case` statements, removing the
need to convert to `string`. On the JS backend, this is translated directly
to a `switch` statement.
- Nim now supports `out` parameters and ["strict definitions"](https://nim-lang.github.io/Nim/manual_experimental.html#strict-definitions-and-nimout-parameters).
- Nim now offers a [strict mode](https://nim-lang.github.io/Nim/manual_experimental.html#strict-case-objects) for `case objects`.
- IBM Z architecture and macOS m1 arm64 architecture are supported.
- `=wasMoved` can now be overridden by users.
- There is a new pragma called [quirky](https://nim-lang.github.io/Nim/manual_experimental.html#quirky-routines) that can be used to affect the code
generation of goto based exception handling. It can improve the produced code size but its effects can be subtle so use it with care.
- Tuple unpacking for variables is now treated as syntax sugar that directly
expands into multiple assignments. Along with this, tuple unpacking for
variables can now be nested.
```nim
proc returnsNestedTuple(): (int, (int, int), int, int) = (4, (5, 7), 2, 3)
let (x, (_, y), _, z) = returnsNestedTuple()
# roughly becomes
let
tmpTup1 = returnsNestedTuple()
x = tmpTup1[0]
tmpTup2 = tmpTup1[1]
y = tmpTup2[1]
z = tmpTup1[3]
```
As a result `nnkVarTuple` nodes in variable sections will no longer be
reflected in `typed` AST.
- C++ interoperability:
- New [`virtual`](https://nim-lang.github.io/Nim/manual_experimental.html#virtual-pragma) pragma added.
- Improvements to [`constructor`](https://nim-lang.github.io/Nim/manual_experimental.html#constructor-pragma) pragma.
## Compiler changes
- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the
reality better. (Nim moved away from all techniques based on "tracing".)
- Defines the `gcRefc` symbol which allows writing specific code for the refc GC.
- `nim` can now compile version 1.4.0 as follows: `nim c --lib:lib --stylecheck:off compiler/nim`,
without requiring `-d:nimVersion140` which is now a noop.
- `--styleCheck`, `--hintAsError` and `--warningAsError` now only apply to the current package.
- The switch `--nimMainPrefix:prefix` has been added to add a prefix to the names of `NimMain` and
related functions produced on the backend. This prevents conflicts with other Nim
static libraries.
- When compiling for release, the flag `-fno-math-errno` is used for GCC.
- Removed deprecated `LineTooLong` hint.
- Line numbers and file names of source files work correctly inside templates for JavaScript targets.
- Removed support for LCC (Local C), Pelles C, Digital Mars and Watcom compilers.
## Docgen
- `Markdown` is now the default markup language of doc comments (instead
of the legacy `RstMarkdown` mode). In this release we begin to separate
RST and Markdown features to better follow specification of each
language, with the focus on Markdown development.
See also [the docs](https://nim-lang.github.io/Nim/markdown_rst.html).
* Added a `{.doctype: Markdown | RST | RstMarkdown.}` pragma allowing to
select the markup language mode in the doc comments of the current `.nim`
file for processing by `nim doc`:
1. `Markdown` (default) is basically CommonMark (standard Markdown) +
some Pandoc Markdown features + some RST features that are missing
in our current implementation of CommonMark and Pandoc Markdown.
2. `RST` closely follows the RST spec with few additional Nim features.
3. `RstMarkdown` is a maximum mix of RST and Markdown features, which
is kept for the sake of compatibility and ease of migration.
* Added separate `md2html` and `rst2html` commands for processing
standalone `.md` and `.rst` files respectively (and also `md2tex`/`rst2tex`).
- Added Pandoc Markdown bracket syntax `[...]` for making anchor-less links.
- Docgen now supports concise syntax for referencing Nim symbols:
instead of specifying HTML anchors directly one can use original
Nim symbol declarations (adding the aforementioned link brackets
`[...]` around them).
* To use this feature across modules, a new `importdoc` directive was added.
Using this feature for referencing also helps to ensure that links
(inside one module or the whole project) are not broken.
- Added support for RST & Markdown quote blocks (blocks starting with `>`).
- Added a popular Markdown definition lists extension.
- Added Markdown indented code blocks (blocks indented by >= 4 spaces).
- Added syntax for additional parameters to Markdown code blocks:
```nim test="nim c $1"
...
```
## Tool changes
- Nim now ships Nimble version 0.14 which added support for lock-files. Libraries are stored in `$nimbleDir/pkgs2` (it was `$nimbleDir/pkgs` before). Use `nimble develop --global` to create an old style link file in the special links directory documented at https://github.com/nim-lang/nimble#nimble-develop.
- nimgrep added the option `--inContext` (and `--notInContext`), which
allows to filter only matches with the context block containing a given pattern.
- nimgrep: names of options containing "include/exclude" are deprecated,
e.g. instead of `--includeFile` and `--excludeFile` we have
`--filename` and `--notFilename` respectively.
Also the semantics are now consistent for such positive/negative filters.
- koch now supports the `--skipIntegrityCheck` option. The command `koch --skipIntegrityCheck boot -d:release` always builds the compiler twice.

View File

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

View File

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

View File

@@ -58,7 +58,11 @@ _nimNumCpu(){
# FreeBSD | macOS: $(sysctl -n hw.ncpu)
# OpenBSD: $(sysctl -n hw.ncpuonline)
# windows: $NUMBER_OF_PROCESSORS ?
echo $(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || 1)
if env | grep -q '^NIMCORES='; then
echo $NIMCORES
else
echo $(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || 1)
fi
}
_nimBuildCsourcesIfNeeded(){

View File

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

View File

@@ -114,6 +114,8 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
# use expensive type check:
if isPartOf(a.sym.typ, b.sym.typ) != arNo:
result = arMaybe
else:
result = arNo
of nkBracketExpr:
result = isPartOf(a[0], b[0])
if a.len >= 2 and b.len >= 2:
@@ -149,7 +151,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
result = isPartOf(a[1], b[1])
of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
result = isPartOf(a[0], b[0])
else: discard
else: result = arNo
# Calls return a new location, so a default of ``arNo`` is fine.
else:
# go down recursively; this is quite demanding:
@@ -165,6 +167,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
of DerefKinds:
# a* !<| b[] iff
result = arNo
if isPartOf(a.typ, b.typ) != arNo:
result = isPartOf(a, b[0])
if result == arNo: result = arMaybe
@@ -186,7 +189,9 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
if isPartOf(a.typ, b.typ) != arNo:
result = isPartOf(a[0], b)
if result == arNo: result = arMaybe
else: discard
else:
result = arNo
else: result = arNo
of nkObjConstr:
result = arNo
for i in 1..<b.len:
@@ -204,4 +209,6 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
of nkBracket:
if b.len > 0:
result = isPartOf(a, b[0])
else: discard
else:
result = arNo
else: result = arNo

View File

@@ -231,7 +231,7 @@ type
TNodeKinds* = set[TNodeKind]
type
TSymFlag* = enum # 49 flags!
TSymFlag* = enum # 51 flags!
sfUsed, # read access of sym (for warnings) or simply used
sfExported, # symbol is exported from module
sfFromGeneric, # symbol is instantiation of a generic; this is needed
@@ -283,7 +283,7 @@ type
sfNamedParamCall, # symbol needs named parameter call syntax in target
# language; for interfacing with Objective C
sfDiscardable, # returned value may be discarded implicitly
sfOverriden, # proc is overridden
sfOverridden, # proc is overridden
sfCallsite # A flag for template symbols to tell the
# compiler it should use line information from
# the calling side of the macro, not from the
@@ -303,6 +303,8 @@ type
sfUsedInFinallyOrExcept # symbol is used inside an 'except' or 'finally'
sfSingleUsedTemp # For temporaries that we know will only be used once
sfNoalias # 'noalias' annotation, means C's 'restrict'
# for templates and macros, means cannot be called
# as a lone symbol (cannot use alias syntax)
sfEffectsDelayed # an 'effectsDelayed' parameter
sfGeneratedType # A anonymous generic type that is generated by the compiler for
# objects that do not have generic parameters in case one of the
@@ -310,6 +312,10 @@ type
#
# This is disallowed but can cause the typechecking to go into
# an infinite loop, this flag is used as a sentinel to stop it.
sfVirtual # proc is a C++ virtual function
sfByCopy # param is marked as pass bycopy
sfMember # proc is a C++ member of a type
sfCodegenDecl # type, proc, global or proc param is marked as codegenDecl
TSymFlags* = set[TSymFlag]
@@ -335,13 +341,14 @@ const
sfCompileToCpp* = sfInfixCall # compile the module as C++ code
sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
sfExperimental* = sfOverriden # module uses the .experimental switch
sfGoto* = sfOverriden # var is used for 'goto' code generation
sfExperimental* = sfOverridden # module uses the .experimental switch
sfGoto* = sfOverridden # var is used for 'goto' code generation
sfWrittenTo* = sfBorrow # param is assigned to
# currently unimplemented
sfBase* = sfDiscriminant
sfCustomPragma* = sfRegister # symbol is custom pragma template
sfTemplateRedefinition* = sfExportc # symbol is a redefinition of an earlier template
sfCppMember* = { sfVirtual, sfMember, sfConstructor } # proc is a C++ member, meaning it will be attached to the type definition
const
# getting ready for the future expr/stmt merge
@@ -513,7 +520,7 @@ type
nfSkipFieldChecking # node skips field visable checking
TNodeFlags* = set[TNodeFlag]
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 46)
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 47)
tfVarargs, # procedure has C styled varargs
# tyArray type represeting a varargs list
tfNoSideEffect, # procedure type does not allow side effects
@@ -583,6 +590,8 @@ type
tfIsConstructor
tfEffectSystemWorkaround
tfIsOutParam
tfSendable
tfImplicitStatic
TTypeFlags* = set[TTypeFlag]
@@ -618,13 +627,12 @@ type
# file (it is loaded on demand, which may
# mean: never)
skPackage, # symbol is a package (used for canonicalization)
skAlias # an alias (needs to be resolved immediately)
TSymKinds* = set[TSymKind]
const
routineKinds* = {skProc, skFunc, skMethod, skIterator,
skConverter, skMacro, skTemplate}
ExportableSymKinds* = {skVar, skLet, skConst, skType, skEnumField, skStub, skAlias} + routineKinds
ExportableSymKinds* = {skVar, skLet, skConst, skType, skEnumField, skStub} + routineKinds
tfUnion* = tfNoSideEffect
tfGcSafe* = tfThread
@@ -685,7 +693,7 @@ type
mIsPartOf, mAstToStr, mParallel,
mSwap, mIsNil, mArrToSeq, mOpenArrayToSeq,
mNewString, mNewStringOfCap, mParseBiggestFloat,
mMove, mWasMoved, mDestroy, mTrace,
mMove, mEnsureMove, mWasMoved, mDup, mDestroy, mTrace,
mDefault, mUnown, mFinished, mIsolate, mAccessEnv, mAccessTypeField, mReset,
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
@@ -818,9 +826,6 @@ type
locOther # location is something other
TLocFlag* = enum
lfIndirect, # backend introduced a pointer
lfFullExternalName, # only used when 'conf.cmd == cmdNimfix': Indicates
# that the symbol has been imported via 'importc: "fullname"' and
# no format string.
lfNoDeepCopy, # no need for a deep copy
lfNoDecl, # do not declare it in C
lfDynamicLib, # link symbol to dynamic library
@@ -855,7 +860,7 @@ type
# keep in sync with PackedLib
kind*: TLibKind
generated*: bool # needed for the backends:
isOverriden*: bool
isOverridden*: bool
name*: Rope
path*: PNode # can be a string literal!
@@ -917,7 +922,9 @@ type
# for modules, an unique index corresponding
# to the module's fileIdx
# for variables a slot index for the evaluator
offset*: int # offset of record field
offset*: int32 # offset of record field
disamb*: int32 # disambiguation number; the basic idea is that
# `<procname>__<module>_<disamb>`
loc*: TLoc
annex*: PLib # additional fields (seldom used, so we use a
# reference to another object to save space)
@@ -925,10 +932,11 @@ type
cname*: string # resolved C declaration name in importc decl, e.g.:
# proc fun() {.importc: "$1aux".} => cname = funaux
constraint*: PNode # additional constraints like 'lit|result'; also
# misused for the codegenDecl pragma in the hope
# misused for the codegenDecl and virtual pragmas in the hope
# it won't cause problems
# for skModule the string literal to output for
# deprecated modules.
instantiatedFrom*: PSym # for instances, the generic symbol where it came from.
when defined(nimsuggest):
allUsages*: seq[TLineInfo]
@@ -938,6 +946,7 @@ type
attachedWasMoved,
attachedDestructor,
attachedAsgn,
attachedDup,
attachedSink,
attachedTrace,
attachedDeepCopy
@@ -950,7 +959,7 @@ type
kind*: TTypeKind # kind of type
callConv*: TCallingConvention # for procs
flags*: TTypeFlags # flags of the type
sons*: TTypeSeq # base types, etc.
sons: TTypeSeq # base types, etc.
n*: PNode # node for types:
# for range types a nkRange node
# for record types a nkRecord node
@@ -1031,6 +1040,8 @@ proc comment*(n: PNode): string =
if nfHasComment in n.flags and not gconfig.useIc:
# IC doesn't track comments, see `packed_ast`, so this could fail
result = gconfig.comments[n.nodeId]
else:
result = ""
proc `comment=`*(n: PNode, a: string) =
let id = n.nodeId
@@ -1121,11 +1132,10 @@ const
proc getPIdent*(a: PNode): PIdent {.inline.} =
## Returns underlying `PIdent` for `{nkSym, nkIdent}`, or `nil`.
# xxx consider whether also returning the 1st ident for {nkOpenSymChoice, nkClosedSymChoice}
# which may simplify code.
case a.kind
of nkSym: a.sym.name
of nkIdent: a.ident
of nkOpenSymChoice, nkClosedSymChoice: a.sons[0].sym.name
else: nil
const
@@ -1141,13 +1151,17 @@ type
symId*: int32
typeId*: int32
sealed*: bool
disambTable*: CountTable[PIdent]
const
PackageModuleId* = -3'i32
proc idGeneratorFromModule*(m: PSym): IdGenerator =
assert m.kind == skModule
result = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0)
result = IdGenerator(module: m.itemId.module, symId: m.itemId.item, typeId: 0, disambTable: initCountTable[PIdent]())
proc idGeneratorForPackage*(nextIdWillBe: int32): IdGenerator =
result = IdGenerator(module: PackageModuleId, symId: nextIdWillBe - 1'i32, typeId: 0, disambTable: initCountTable[PIdent]())
proc nextSymId*(x: IdGenerator): ItemId {.inline.} =
assert(not x.sealed)
@@ -1214,6 +1228,7 @@ proc getDeclPragma*(n: PNode): PNode =
case n.kind
of routineDefs:
if n[pragmasPos].kind != nkEmpty: result = n[pragmasPos]
else: result = nil
of nkTypeDef:
#[
type F3*{.deprecated: "x3".} = int
@@ -1233,6 +1248,8 @@ proc getDeclPragma*(n: PNode): PNode =
]#
if n[0].kind == nkPragmaExpr:
result = n[0][1]
else:
result = nil
else:
# support as needed for `nkIdentDefs` etc.
result = nil
@@ -1248,6 +1265,12 @@ proc extractPragma*(s: PSym): PNode =
if s.ast[0].kind == nkPragmaExpr and s.ast[0].len > 1:
# s.ast = nkTypedef / nkPragmaExpr / [nkSym, nkPragma]
result = s.ast[0][1]
else:
result = nil
else:
result = nil
else:
result = nil
assert result == nil or result.kind == nkPragma
proc skipPragmaExpr*(n: PNode): PNode =
@@ -1339,11 +1362,15 @@ when false:
echo k
echo v
proc newSym*(symKind: TSymKind, name: PIdent, id: ItemId, owner: PSym,
proc newSym*(symKind: TSymKind, name: PIdent, idgen: IdGenerator; owner: PSym,
info: TLineInfo; options: TOptions = {}): PSym =
# generates a symbol and initializes the hash field too
assert not name.isNil
let id = nextSymId idgen
result = PSym(name: name, kind: symKind, flags: {}, info: info, itemId: id,
options: options, owner: owner, offset: defaultOffset)
options: options, owner: owner, offset: defaultOffset,
disamb: getOrDefault(idgen.disambTable, name).int32)
idgen.disambTable.inc name
when false:
if id.module == 48 and id.item == 39:
writeStackTrace()
@@ -1473,7 +1500,7 @@ proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode =
result = newNode(nkIntLit)
of tyStatic: # that's a pre-existing bug, will fix in another PR
result = newNode(nkIntLit)
else: doAssert false, $kind
else: raiseAssert $kind
result.intVal = intVal
result.typ = typ
@@ -1503,7 +1530,7 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
const
AttachedOpToStr*: array[TTypeAttachedOp, string] = [
"=wasMoved", "=destroy", "=copy", "=sink", "=trace", "=deepcopy"]
"=wasMoved", "=destroy", "=copy", "=dup", "=sink", "=trace", "=deepcopy"]
proc `$`*(s: PSym): string =
if s != nil:
@@ -1511,15 +1538,31 @@ proc `$`*(s: PSym): string =
else:
result = "<nil>"
proc newType*(kind: TTypeKind, id: ItemId; owner: PSym): PType =
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])
proc newType*(kind: TTypeKind, id: ItemId; owner: PSym, sons: seq[PType] = @[]): PType =
result = PType(kind: kind, owner: owner, size: defaultSize,
align: defaultAlignment, itemId: id,
uniqueId: id)
uniqueId: id, sons: sons)
when false:
if result.itemId.module == 55 and result.itemId.item == 2:
echo "KNID ", kind
writeStackTrace()
template newType*(kind: TTypeKind, id: ItemId; owner: PSym, parent: PType): PType =
newType(kind, id, owner, parent.sons)
proc newType*(prev: PType, sons: seq[PType]): PType =
result = prev
result.sons = sons
proc addSon*(father, son: PType) =
# todo fixme: in IC, `son` might be nil
father.sons.add(son)
proc mergeLoc(a: var TLoc, b: TLoc) =
if a.k == low(typeof(a.k)): a.k = b.k
@@ -1557,8 +1600,8 @@ proc copyType*(t: PType, id: ItemId, owner: PSym): PType =
proc exactReplica*(t: PType): PType =
result = copyType(t, t.itemId, t.owner)
proc copySym*(s: PSym; id: ItemId): PSym =
result = newSym(s.kind, s.name, id, s.owner, s.info, s.options)
proc copySym*(s: PSym; idgen: IdGenerator): PSym =
result = newSym(s.kind, s.name, idgen, s.owner, s.info, s.options)
#result.ast = nil # BUGFIX; was: s.ast which made problems
result.typ = s.typ
result.flags = s.flags
@@ -1573,9 +1616,9 @@ proc copySym*(s: PSym; id: ItemId): PSym =
result.bitsize = s.bitsize
result.alignment = s.alignment
proc createModuleAlias*(s: PSym, id: ItemId, newIdent: PIdent, info: TLineInfo;
proc createModuleAlias*(s: PSym, idgen: IdGenerator, newIdent: PIdent, info: TLineInfo;
options: TOptions): PSym =
result = newSym(s.kind, newIdent, id, s.owner, info, options)
result = newSym(s.kind, newIdent, idgen, s.owner, info, options)
# keep ID!
result.ast = s.ast
#result.id = s.id # XXX figure out what to do with the ID.
@@ -1585,19 +1628,13 @@ proc createModuleAlias*(s: PSym, id: ItemId, newIdent: PIdent, info: TLineInfo;
result.loc = s.loc
result.annex = s.annex
proc initStrTable*(x: var TStrTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc initStrTable*(): TStrTable =
result = TStrTable(counter: 0)
newSeq(result.data, StartSize)
proc newStrTable*: TStrTable =
initStrTable(result)
proc initIdTable*(x: var TIdTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc newIdTable*: TIdTable =
initIdTable(result)
proc initIdTable*(): TIdTable =
result = TIdTable(counter: 0)
newSeq(result.data, StartSize)
proc resetIdTable*(x: var TIdTable) =
x.counter = 0
@@ -1605,17 +1642,17 @@ proc resetIdTable*(x: var TIdTable) =
setLen(x.data, 0)
setLen(x.data, StartSize)
proc initObjectSet*(x: var TObjectSet) =
x.counter = 0
newSeq(x.data, StartSize)
proc initObjectSet*(): TObjectSet =
result = TObjectSet(counter: 0)
newSeq(result.data, StartSize)
proc initIdNodeTable*(x: var TIdNodeTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc initIdNodeTable*(): TIdNodeTable =
result = TIdNodeTable(counter: 0)
newSeq(result.data, StartSize)
proc initNodeTable*(x: var TNodeTable) =
x.counter = 0
newSeq(x.data, StartSize)
proc initNodeTable*(): TNodeTable =
result = TNodeTable(counter: 0)
newSeq(result.data, StartSize)
proc skipTypes*(t: PType, kinds: TTypeKinds; maxIters: int): PType =
result = t
@@ -1799,6 +1836,7 @@ proc hasNilSon*(n: PNode): bool =
result = false
proc containsNode*(n: PNode, kinds: TNodeKinds): bool =
result = false
if n == nil: return
case n.kind
of nkEmpty..nkNilLit: result = n.kind in kinds
@@ -1899,7 +1937,7 @@ 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 in skProcKinds and sfFromGeneric in s.flags and s.owner.kind != skModule:
s.owner.owner
else:
s.owner
@@ -1915,20 +1953,6 @@ proc isCompileTimeProc*(s: PSym): bool {.inline.} =
result = s.kind == skMacro or
s.kind in {skProc, skFunc} and sfCompileTime in s.flags
proc isRunnableExamples*(n: PNode): bool =
# Templates and generics don't perform symbol lookups.
result = n.kind == nkSym and n.sym.magic == mRunnableExamples or
n.kind == nkIdent and n.ident.s == "runnableExamples"
proc requiredParams*(s: PSym): int =
# Returns the number of required params (without default values)
# XXX: Perhaps we can store this in the `offset` field of the
# symbol instead?
for i in 1..<s.typ.len:
if s.typ.n[i].sym.ast != nil:
return i - 1
return s.typ.len - 1
proc hasPattern*(s: PSym): bool {.inline.} =
result = isRoutine(s) and s.ast[patternPos].kind != nkEmpty
@@ -2002,7 +2026,7 @@ proc toObjectFromRefPtrGeneric*(typ: PType): PType =
of tyRef, tyPtr, tyGenericInst, tyGenericInvocation, tyAlias: result = result[0]
# automatic dereferencing is deep, refs #18298.
else: break
assert result.sym != nil
# result does not have to be object type
proc isImportedException*(t: PType; conf: ConfigRef): bool =
assert t != nil
@@ -2014,6 +2038,8 @@ proc isImportedException*(t: PType; conf: ConfigRef): bool =
if base.sym != nil and {sfCompileToCpp, sfImportc} * base.sym.flags != {}:
result = true
else:
result = false
proc isInfixAs*(n: PNode): bool =
return n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "as"
@@ -2024,10 +2050,12 @@ proc skipColon*(n: PNode): PNode =
result = n[1]
proc findUnresolvedStatic*(n: PNode): PNode =
# n.typ == nil: see issue #14802
if n.kind == nkSym and n.typ != nil and n.typ.kind == tyStatic and n.typ.n == nil:
return n
if n.typ != nil and n.typ.kind == tyTypeDesc:
let t = skipTypes(n.typ, {tyTypeDesc})
if t.kind == tyGenericParam and t.len == 0:
return n
for son in n:
let n = son.findUnresolvedStatic
if n != nil: return n
@@ -2065,6 +2093,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)
@@ -2139,3 +2173,7 @@ const
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
nkTypeOfExpr, nkMixinStmt, nkBindStmt}
proc isTrue*(n: PNode): bool =
n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
n.kind == nkIntLit and n.intVal != 0

View File

@@ -109,7 +109,7 @@ type
data*: TIIPairSeq
proc initIiTable*(x: var TIITable)
proc initIITable*(x: var TIITable)
proc iiTableGet*(t: TIITable, key: int): int
proc iiTablePut*(t: var TIITable, key, val: int)
@@ -197,6 +197,7 @@ proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym =
result = nil
proc sameIgnoreBacktickGensymInfo(a, b: string): bool =
result = false
if a[0] != b[0]: return false
var alen = a.len - 1
while alen > 0 and a[alen] != '`': dec(alen)
@@ -226,10 +227,11 @@ proc getNamedParamFromList*(list: PNode, ident: PIdent): PSym =
## Named parameters are special because a named parameter can be
## gensym'ed and then they have '\`<number>' suffix that we need to
## ignore, see compiler / evaltempl.nim, snippet:
## ```
## ```nim
## result.add newIdentNode(getIdent(c.ic, x.name.s & "\`gensym" & $x.id),
## if c.instLines: actual.info else: templ.info)
## ```
result = nil
for i in 1..<list.len:
let it = list[i].sym
if it.name.id == ident.id or
@@ -327,8 +329,10 @@ proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
maxRecDepth: int): Rope =
var sonsRope: Rope
if n == nil:
result = ""
sonsRope = rope("null")
elif containsOrIncl(marker, n.id):
result = ""
sonsRope = "\"$1 @$2\"" % [rope($n.kind), rope(
strutils.toHex(cast[int](n), sizeof(n) * 2))]
else:
@@ -1063,6 +1067,7 @@ proc isAddrNode*(n: PNode): bool =
else: false
proc listSymbolNames*(symbols: openArray[PSym]): string =
result = ""
for sym in symbols:
if result.len > 0:
result.add ", "

View File

@@ -87,5 +87,6 @@ const populationCount: array[uint8, uint8] = block:
arr
proc bitSetCard*(x: TBitSet): BiggestInt =
result = 0
for it in x:
result.inc int(populationCount[it])

View File

@@ -38,6 +38,7 @@ template less(a, b): bool = cmp(a, b) < 0
template eq(a, b): bool = cmp(a, b) == 0
proc getOrDefault*[Key, Val](b: BTree[Key, Val], key: Key): Val =
result = default(Val)
var x = b.root
while x.isInternal:
for j in 0..<x.entries:
@@ -68,7 +69,7 @@ proc copyHalf[Key, Val](h, result: Node[Key, Val]) =
result.links[j] = h.links[Mhalf + j]
else:
for j in 0..<Mhalf:
when defined(gcArc) or defined(gcOrc):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
result.vals[j] = move h.vals[Mhalf + j]
else:
shallowCopy(result.vals[j], h.vals[Mhalf + j])
@@ -91,7 +92,7 @@ proc insert[Key, Val](h: Node[Key, Val], key: Key, val: Val): Node[Key, Val] =
if less(key, h.keys[j]): break
inc j
for i in countdown(h.entries, j+1):
when defined(gcArc) or defined(gcOrc):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
h.vals[i] = move h.vals[i-1]
else:
shallowCopy(h.vals[i], h.vals[i-1])

View File

@@ -24,6 +24,7 @@ proc canRaiseDisp(p: BProc; n: PNode): bool =
proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
proc locationEscapes(p: BProc; le: PNode; inTryStmt: bool): bool =
result = false
var n = le
while true:
# do NOT follow nkHiddenDeref here!
@@ -46,6 +47,7 @@ proc preventNrvo(p: BProc; dest, le, ri: PNode): bool =
# cannot analyse the location; assume the worst
return true
result = false
if le != nil:
for i in 1..<ri.len:
let r = ri[i]
@@ -87,7 +89,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
# beware of 'result = p(result)'. We may need to allocate a temporary:
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
# Great, we can use 'd':
if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
if d.k == locNone: d = getTemp(p, typ[0], needsInit=true)
elif d.k notin {locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var:
discard "resetLoc(p, d)"
@@ -95,8 +97,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
pl.add(");\n")
line(p, cpsStmts, pl)
else:
var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true)
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
pl.add(addrLoc(p.config, tmp))
pl.add(");\n")
line(p, cpsStmts, pl)
@@ -114,28 +115,24 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
excl d.flags, lfSingleUse
else:
if d.k == locNone and p.splitDecls == 0:
getTempCpp(p, typ[0], d, pl)
d = getTempCpp(p, typ[0], pl)
else:
if d.k == locNone: getTemp(p, typ[0], d)
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
if d.k == locNone: d = getTemp(p, typ[0])
var list = initLoc(locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
elif isHarmlessStore(p, canRaise, d):
if d.k == locNone: getTemp(p, typ[0], d)
if d.k == locNone: d = getTemp(p, typ[0])
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
var list = initLoc(locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
else:
var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true)
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
var list = initLoc(locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, tmp, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
@@ -157,10 +154,9 @@ proc reifiedOpenArray(n: PNode): bool {.inline.} =
result = true
proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareForMutation = false): (Rope, Rope) =
var a, b, c: TLoc
initLocExpr(p, q[1], a)
initLocExpr(p, q[2], b)
initLocExpr(p, q[3], c)
var a = initLocExpr(p, q[1])
var b = initLocExpr(p, q[2])
var c = initLocExpr(p, q[3])
# but first produce the required index checks:
if optBoundsCheck in p.options:
genBoundsCheck(p, a, b, c)
@@ -205,6 +201,7 @@ proc genOpenArraySlice(p: BProc; q: PNode; formalType, destType: PType; prepareF
[rdLoc(a), rdLoc(b), dataField(p), dest, dataFieldAccessor(p, rdLoc(a))],
lengthExpr)
else:
result = ("", "")
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
@@ -224,8 +221,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode; result: var Rope) =
let (x, y) = genOpenArraySlice(p, q, formalType, n.typ[0])
result.add x & ", " & y
else:
var a: TLoc
initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n, a)
var a: TLoc = initLocExpr(p, if n.kind == nkHiddenStdConv: n[1] else: n)
case skipTypes(a.t, abstractVar+{tyStatic}).kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(n):
@@ -269,20 +265,19 @@ proc withTmpIfNeeded(p: BProc, a: TLoc, needsTmp: bool): TLoc =
# Bug https://github.com/status-im/nimbus-eth2/issues/1549
# Aliasing is preferred over stack overflows.
# Also don't regress for non ARC-builds, too risky.
if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcOrc} and
if needsTmp and a.lode.typ != nil and p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
getSize(p.config, a.lode.typ) < 1024:
getTemp(p, a.lode.typ, result, needsInit=false)
result = getTemp(p, a.lode.typ, needsInit=false)
genAssignment(p, result, a, {})
else:
result = a
proc literalsNeedsTmp(p: BProc, a: TLoc): TLoc =
getTemp(p, a.lode.typ, result, needsInit=false)
result = getTemp(p, a.lode.typ, needsInit=false)
genAssignment(p, result, a, {})
proc genArgStringToCString(p: BProc, n: PNode; result: var Rope; needsTmp: bool) {.inline.} =
var a: TLoc
initLocExpr(p, n[0], a)
var a: TLoc = initLocExpr(p, n[0])
appcg(p.module, result, "#nimToCStringConv($1)", [withTmpIfNeeded(p, a, needsTmp).rdLoc])
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; needsTmp = false) =
@@ -292,15 +287,16 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
elif skipTypes(param.typ, abstractVar).kind in {tyOpenArray, tyVarargs}:
var n = if n.kind != nkHiddenAddr: n else: n[0]
openArrayLoc(p, param.typ, n, result)
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]):
initLocExpr(p, n, a)
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]) and
(optByRef notin param.options or not p.module.compileToCpp):
a = initLocExpr(p, n)
if n.kind in {nkCharLit..nkNilLit}:
addAddrLoc(p.config, literalsNeedsTmp(p, a), result)
else:
addAddrLoc(p.config, withTmpIfNeeded(p, a, needsTmp), result)
elif p.module.compileToCpp and param.typ.kind in {tyVar} and
n.kind == nkHiddenAddr:
initLocExprSingleUse(p, n[0], a)
a = initLocExprSingleUse(p, n[0])
# 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]
@@ -311,7 +307,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode; result: var Rope; need
else:
addRdLoc(a, result)
else:
initLocExprSingleUse(p, n, a)
a = initLocExprSingleUse(p, n)
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
#assert result != nil
@@ -320,12 +316,13 @@ proc genArgNoParam(p: BProc, n: PNode; result: var Rope; needsTmp = false) =
if n.kind == nkStringToCString:
genArgStringToCString(p, n, result, needsTmp)
else:
initLocExprSingleUse(p, n, a)
a = initLocExprSingleUse(p, n)
addRdLoc(withTmpIfNeeded(p, a, needsTmp), result)
import aliasanalysis
proc potentialAlias(n: PNode, potentialWrites: seq[PNode]): bool =
result = false
for p in potentialWrites:
if p.aliases(n) != no or n.aliases(p) != no:
return true
@@ -381,13 +378,13 @@ proc genParams(p: BProc, ri: PNode, typ: PType; result: var Rope) =
# We must generate temporaries in cases like #14396
# to keep the strict Left-To-Right evaluation
var needTmp = newSeq[bool](ri.len - 1)
var potentialWrites: seq[PNode]
var potentialWrites: seq[PNode] = @[]
for i in countdown(ri.len - 1, 1):
if ri[i].skipTrivialIndirections.kind == nkSym:
needTmp[i - 1] = potentialAlias(ri[i], potentialWrites)
else:
#if not ri[i].typ.isCompileTimeOnly:
var potentialReads: seq[PNode]
var potentialReads: seq[PNode] = @[]
getPotentialReads(ri[i], potentialReads)
for n in potentialReads:
if not needTmp[i - 1]:
@@ -419,9 +416,8 @@ proc addActualSuffixForHCR(res: var Rope, module: PSym, sym: PSym) =
res = res & "_actual".rope
proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op: TLoc
# this is a hotspot in the compiler
initLocExpr(p, ri[0], op)
var op: TLoc = initLocExpr(p, ri[0])
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInstOwned)
assert(typ.kind == tyProc)
@@ -443,8 +439,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
const PatProc = "$1.ClE_0? $1.ClP_0($3$1.ClE_0):(($4)($1.ClP_0))($2)"
const PatIter = "$1.ClP_0($3$1.ClE_0)" # we know the env exists
var op: TLoc
initLocExpr(p, ri[0], op)
var op: TLoc = initLocExpr(p, ri[0])
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInstOwned)
@@ -469,7 +464,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
if d.k in {locTemp, locNone} or not preventNrvo(p, d.lode, le, ri):
# Great, we can use 'd':
if d.k == locNone:
getTemp(p, typ[0], d, needsInit=true)
d = getTemp(p, typ[0], needsInit=true)
elif d.k notin {locTemp} and not hasNoInit(ri):
# reset before pass as 'result' var:
discard "resetLoc(p, d)"
@@ -477,17 +472,15 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
genCallPattern()
if canRaise: raiseExit(p)
else:
var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true)
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
pl.add(addrLoc(p.config, tmp))
genCallPattern()
if canRaise: raiseExit(p)
genAssignment(p, d, tmp, {}) # no need for deep copying
elif isHarmlessStore(p, canRaise, d):
if d.k == locNone: getTemp(p, typ[0], d)
if d.k == locNone: d = getTemp(p, typ[0])
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
if tfIterator in typ.flags:
list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
else:
@@ -495,11 +488,9 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
genAssignment(p, d, list, {}) # no need for deep copying
if canRaise: raiseExit(p)
else:
var tmp: TLoc
getTemp(p, typ[0], tmp)
var tmp: TLoc = getTemp(p, typ[0])
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
if tfIterator in typ.flags:
list.r = PatIter % [rdLoc(op), pl, pl.addComma, rawProc]
else:
@@ -667,7 +658,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro
inc j
inc i
of '\'':
var idx, stars: int
var idx, stars: int = 0
if scanCppGenericSlot(pat, i, idx, stars):
var t = resolveStarsInCppType(typ, idx, stars)
if t == nil: result.add("void")
@@ -681,8 +672,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType; result: var Ro
result.add(substr(pat, start, i - 1))
proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
var op: TLoc
initLocExpr(p, ri[0], op)
var op: TLoc = initLocExpr(p, ri[0])
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
assert(typ.kind == tyProc)
@@ -704,10 +694,9 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
d.r = pl
excl d.flags, lfSingleUse
else:
if d.k == locNone: getTemp(p, typ[0], d)
if d.k == locNone: d = getTemp(p, typ[0])
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, d.lode, OnUnknown)
var list: TLoc = initLoc(locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:
@@ -727,8 +716,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
# generates a crappy ObjC call
var op: TLoc
initLocExpr(p, ri[0], op)
var op: TLoc = initLocExpr(p, ri[0])
var pl = "["
# getUniqueType() is too expensive here:
var typ = skipTypes(ri[0].typ, abstractInst)
@@ -770,24 +758,22 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
# beware of 'result = p(result)'. We always allocate a temporary:
if d.k in {locTemp, locNone}:
# We already got a temp. Great, special case it:
if d.k == locNone: getTemp(p, typ[0], d, needsInit=true)
if d.k == locNone: d = getTemp(p, typ[0], needsInit=true)
pl.add("Result: ")
pl.add(addrLoc(p.config, d))
pl.add("];\n")
line(p, cpsStmts, pl)
else:
var tmp: TLoc
getTemp(p, typ[0], tmp, needsInit=true)
var tmp: TLoc = getTemp(p, typ[0], needsInit=true)
pl.add(addrLoc(p.config, tmp))
pl.add("];\n")
line(p, cpsStmts, pl)
genAssignment(p, d, tmp, {}) # no need for deep copying
else:
pl.add("]")
if d.k == locNone: getTemp(p, typ[0], d)
if d.k == locNone: d = getTemp(p, typ[0])
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, ri, OnUnknown)
var list: TLoc = initLoc(locCall, ri, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -35,7 +35,9 @@ proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
if n.kind == nkEmpty:
result = false
elif n.kind in nkCallKinds and n[0] != nil and n[0].typ != nil and n[0].typ.skipTypes(abstractInst).kind == tyProc:
if isInvalidReturnType(conf, n[0].typ, true):
if n[0].kind == nkSym and sfConstructor in n[0].sym.flags:
result = true
elif isInvalidReturnType(conf, n[0].typ, true):
# var v = f()
# is transformed into: var v; f(addr v)
# where 'f' **does not** initialize the result!
@@ -48,6 +50,7 @@ proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
result = true
proc inExceptBlockLen(p: BProc): int =
result = 0
for x in p.nestedTryStmts:
if x.inExcept: result.inc
@@ -69,7 +72,6 @@ template startBlock(p: BProc, start: FormatStr = "{$n",
proc endBlock(p: BProc)
proc genVarTuple(p: BProc, n: PNode) =
var tup, field: TLoc
if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple")
# if we have a something that's been captured, use the lowering instead:
@@ -81,7 +83,7 @@ proc genVarTuple(p: BProc, n: PNode) =
# check only the first son
var forHcr = treatGlobalDifferentlyForHCR(p.module, n[0].sym)
let hcrCond = if forHcr: getTempName(p.module) else: ""
var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]]
var hcrGlobals: seq[tuple[loc: TLoc, tp: Rope]] = @[]
# determine if the tuple is constructed at top-level scope or inside of a block (if/while/block)
let isGlobalInBlock = forHcr and p.blocks.len > 2
# do not close and reopen blocks if this is a 'global' but inside of a block (if/while/block)
@@ -93,7 +95,7 @@ proc genVarTuple(p: BProc, n: PNode) =
startBlock(p)
genLineDir(p, n)
initLocExpr(p, n[^1], tup)
var tup = initLocExpr(p, n[^1])
var t = tup.t.skipTypes(abstractInst)
for i in 0..<n.len-2:
let vn = n[i]
@@ -106,7 +108,7 @@ proc genVarTuple(p: BProc, n: PNode) =
else:
assignLocalVar(p, vn)
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[^1]))
initLoc(field, locExpr, vn, tup.storage)
var field = initLoc(locExpr, vn, tup.storage)
if t.kind == tyTuple:
field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
else:
@@ -167,7 +169,7 @@ proc endBlock(p: BProc, blockEnd: Rope) =
proc endBlock(p: BProc) =
let topBlock = p.blocks.len - 1
let frameLen = p.blocks[topBlock].frameLen
var blockEnd: Rope
var blockEnd: Rope = ""
if frameLen > 0:
blockEnd.addf("FR_.len-=$1;$n", [frameLen.rope])
if p.blocks[topBlock].label.len != 0:
@@ -242,8 +244,7 @@ proc genGotoState(p: BProc, n: PNode) =
# switch (x.state) {
# case 0: goto STATE0;
# ...
var a: TLoc
initLocExpr(p, n[0], a)
var a: TLoc = initLocExpr(p, n[0])
lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
p.flags.incl beforeRetNeeded
lineF(p, cpsStmts, "case -1:$n", [])
@@ -262,13 +263,13 @@ proc genGotoState(p: BProc, n: PNode) =
proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc
initLoc(d, locExpr, n, OnUnknown)
d = initLoc(locExpr, n, OnUnknown)
if n[0].kind == nkClosure:
initLocExpr(p, n[0][1], a)
a = initLocExpr(p, n[0][1])
d.r = "(((NI*) $1)[1] < 0)" % [rdLoc(a)]
else:
initLocExpr(p, n[0], a)
a = initLocExpr(p, n[0])
# the environment is guaranteed to contain the 'state' field at offset 1:
d.r = "((((NI*) $1.ClE_0)[1]) < 0)" % [rdLoc(a)]
@@ -288,11 +289,28 @@ proc potentialValueInit(p: BProc; v: PSym; value: PNode; result: var Rope) =
#echo "New code produced for ", v.name.s, " ", p.config $ value.info
genBracedInit(p, value, isConst = false, v.typ, result)
proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope) =
var params = newRopeAppender()
var argsCounter = 0
let typ = skipTypes(value[0].typ, abstractInst)
assert(typ.kind == tyProc)
for i in 1..<value.len:
assert(typ.len == typ.n.len)
genOtherArg(p, value, i, typ, params, argsCounter)
if params.len == 0:
decl = runtimeFormat("$#;\n", [decl])
else:
decl = runtimeFormat("$#($#);\n", [decl, params])
proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
if sfGoto in v.flags:
# translate 'var state {.goto.} = X' into 'goto LX':
genGotoVar(p, value)
return
let imm = isAssignedImmediately(p.config, value)
let isCppCtorCall = p.module.compileToCpp and imm and
value.kind in nkCallKinds and value[0].kind == nkSym and
v.typ.kind != tyPtr and sfConstructor in value[0].sym.flags
var targetProc = p
var valueAsRope = ""
potentialValueInit(p, v, value, valueAsRope)
@@ -304,7 +322,11 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
if sfPure in v.flags:
# v.owner.kind != skModule:
targetProc = p.module.preInitProc
assignGlobalVar(targetProc, vn, valueAsRope)
if isCppCtorCall and not containsHiddenPointer(v.typ):
callGlobalVarCppCtor(targetProc, v, vn, value)
else:
assignGlobalVar(targetProc, vn, valueAsRope)
# XXX: be careful here.
# Global variables should not be zeromem-ed within loops
# (see bug #20).
@@ -313,13 +335,12 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
# global variables will be initialized to zero.
if valueAsRope.len == 0:
var loc = v.loc
# When the native TLS is unavailable, a global thread-local variable needs
# one more layer of indirection in order to access the TLS block.
# Only do this for complex types that may need a call to `objectInit`
if sfThread in v.flags and emulatedThreadVars(p.config) and
isComplexValueType(v.typ):
initLocExprSingleUse(p.module.preInitProc, vn, loc)
loc = initLocExprSingleUse(p.module.preInitProc, vn)
genObjectInit(p.module.preInitProc, cpsInit, v.typ, loc, constructObj)
# Alternative construction using default constructor (which may zeromem):
# if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
@@ -327,31 +348,21 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
genVarPrototype(p.module.g.generatedHeader, vn)
registerTraverseProc(p, v)
else:
let imm = isAssignedImmediately(p.config, value)
if imm and p.module.compileToCpp and p.splitDecls == 0 and
not containsHiddenPointer(v.typ):
not containsHiddenPointer(v.typ) and
nimErrorFlagAccessed notin p.flags:
# C++ really doesn't like things like 'Foo f; f = x' as that invokes a
# parameterless constructor followed by an assignment operator. So we
# generate better code here: 'Foo f = x;'
genLineDir(p, vn)
let decl = localVarDecl(p, vn)
var decl = localVarDecl(p, vn)
var tmp: TLoc
if value.kind in nkCallKinds and value[0].kind == nkSym and
sfConstructor in value[0].sym.flags:
var params = newRopeAppender()
var argsCounter = 0
let typ = skipTypes(value[0].typ, abstractInst)
assert(typ.kind == tyProc)
for i in 1..<value.len:
assert(typ.len == typ.n.len)
genOtherArg(p, value, i, typ, params, argsCounter)
if params.len == 0:
lineF(p, cpsStmts, "$#;$n", [decl])
else:
lineF(p, cpsStmts, "$#($#);$n", [decl, params])
if isCppCtorCall:
genCppVarForCtor(p, v, vn, value, decl)
line(p, cpsStmts, decl)
else:
initLocExprSingleUse(p, value, tmp)
lineF(p, cpsStmts, "$# = $#;$n", [decl, tmp.rdLoc])
tmp = initLocExprSingleUse(p, value)
lineF(p, cpsStmts, "$# = $#;\n", [decl, tmp.rdLoc])
return
assignLocalVar(p, vn)
initLocalVar(p, v, imm)
@@ -378,7 +389,8 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
startBlock(targetProc)
if value.kind != nkEmpty and valueAsRope.len == 0:
genLineDir(targetProc, vn)
loadInto(targetProc, vn, value, v.loc)
if not isCppCtorCall:
loadInto(targetProc, vn, value, v.loc)
if forHcr:
endBlock(targetProc)
@@ -395,8 +407,7 @@ proc genSingleVar(p: BProc, a: PNode) =
proc genClosureVar(p: BProc, a: PNode) =
var immediateAsgn = a[2].kind != nkEmpty
var v: TLoc
initLocExpr(p, a[0], v)
var v: TLoc = initLocExpr(p, a[0])
genLineDir(p, a)
if immediateAsgn:
loadInto(p, a[0], a[2], v)
@@ -431,7 +442,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
a: TLoc
lelse: TLabel
if not isEmptyType(n.typ) and d.k == locNone:
getTemp(p, n.typ, d)
d = getTemp(p, n.typ)
genLineDir(p, n)
let lend = getLabel(p)
for it in n.sons:
@@ -439,7 +450,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
if d.k == locTemp and isEmptyType(n.typ): d.k = locNone
if it.len == 2:
startBlock(p)
initLocExprSingleUse(p, it[0], a)
a = initLocExprSingleUse(p, it[0])
lelse = getLabel(p)
inc(p.labels)
lineF(p, cpsStmts, "if (!$1) goto $2;$n",
@@ -507,7 +518,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
# wrapped inside stmt lists by inject destructors won't be recognised
let n = n.flattenStmts()
var casePos = -1
var arraySize: int
var arraySize: int = 0
for i in 0..<n.len:
let it = n[i]
if it.kind == nkCaseStmt:
@@ -541,8 +552,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
genStmts(p, n[j])
let caseStmt = n[casePos]
var a: TLoc
initLocExpr(p, caseStmt[0], a)
var a: TLoc = initLocExpr(p, caseStmt[0])
# first goto:
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
@@ -580,8 +590,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
else:
genStmts(p, it)
var a: TLoc
initLocExpr(p, caseStmt[0], a)
var a: TLoc = initLocExpr(p, caseStmt[0])
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
endBlock(p)
@@ -609,11 +618,11 @@ proc genWhileStmt(p: BProc, t: PNode) =
else:
p.breakIdx = startBlock(p, "while (1) {$n")
p.blocks[p.breakIdx].isLoop = true
initLocExpr(p, t[0], a)
a = initLocExpr(p, t[0])
if (t[0].kind != nkIntLit) or (t[0].intVal == 0):
lineF(p, cpsStmts, "if (!$1) goto ", [rdLoc(a)])
assignLabel(p.blocks[p.breakIdx], p.s(cpsStmts))
lineF(p, cpsStmts, ";$n", [])
appcg(p, cpsStmts, ";$n", [])
genStmts(p, loopBody)
if optProfiler in p.options:
@@ -628,7 +637,7 @@ proc genBlock(p: BProc, n: PNode, d: var TLoc) =
# bug #4505: allocate the temp in the outer scope
# so that it can escape the generated {}:
if d.k == locNone:
getTemp(p, n.typ, d)
d = getTemp(p, n.typ)
d.flags.incl(lfEnforceDeref)
preserveBreakIdx:
p.breakIdx = startBlock(p)
@@ -648,14 +657,13 @@ proc genParForStmt(p: BProc, t: PNode) =
preserveBreakIdx:
let forLoopVar = t[0].sym
var rangeA, rangeB: TLoc
assignLocalVar(p, t[0])
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
#discard mangleName(forLoopVar)
let call = t[1]
assert(call.len in {4, 5})
initLocExpr(p, call[1], rangeA)
initLocExpr(p, call[2], rangeB)
assert(call.len == 4 or call.len == 5)
var rangeA = initLocExpr(p, call[1])
var rangeB = initLocExpr(p, call[2])
# $n at the beginning because of #9710
if call.len == 4: # procName(a, b, annotation)
@@ -672,8 +680,7 @@ proc genParForStmt(p: BProc, t: PNode) =
rangeA.rdLoc, rangeB.rdLoc,
call[3].getStr.rope])
else: # `||`(a, b, step, annotation)
var step: TLoc
initLocExpr(p, call[3], step)
var step: TLoc = initLocExpr(p, call[3])
lineF(p, cpsStmts, "$n#pragma omp $5$n" &
"for ($1 = $2; $1 <= $3; $1 += $4)",
[forLoopVar.loc.rdLoc,
@@ -743,8 +750,7 @@ proc raiseInstr(p: BProc; result: var Rope) =
proc genRaiseStmt(p: BProc, t: PNode) =
if t[0].kind != nkEmpty:
var a: TLoc
initLocExprSingleUse(p, t[0], a)
var a: TLoc = initLocExprSingleUse(p, t[0])
finallyActions(p)
var e = rdLoc(a)
discard getTypeDesc(p.module, t[0].typ)
@@ -766,11 +772,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
else:
finallyActions(p)
genLineDir(p, t)
# reraise the last exception:
if p.config.exc == excCpp:
line(p, cpsStmts, "throw;\n")
else:
linefmt(p, cpsStmts, "#reraiseException();$n", [])
linefmt(p, cpsStmts, "#reraiseException();$n", [])
raiseInstr(p, p.s(cpsStmts))
template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
@@ -778,12 +780,12 @@ template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
var x, y: TLoc
for i in 0..<b.len - 1:
if b[i].kind == nkRange:
initLocExpr(p, b[i][0], x)
initLocExpr(p, b[i][1], y)
x = initLocExpr(p, b[i][0])
y = initLocExpr(p, b[i][1])
lineCg(p, cpsStmts, rangeFormat,
[rdCharLoc(e), rdCharLoc(x), rdCharLoc(y), labl])
else:
initLocExpr(p, b[i], x)
x = initLocExpr(p, b[i])
lineCg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl])
proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
@@ -825,8 +827,7 @@ template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
template genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
rangeFormat, eqFormat: FormatStr) =
var a: TLoc
initLocExpr(p, t[0], a)
var a: TLoc = initLocExpr(p, t[0])
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, t.len-1, a)
fixLabel(p, lend)
@@ -836,8 +837,8 @@ proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
var x: TLoc
for i in 0..<b.len - 1:
assert(b[i].kind != nkRange)
initLocExpr(p, b[i], x)
var j: int
x = initLocExpr(p, b[i])
var j: int = 0
case b[i].kind
of nkStrLit..nkTripleStrLit:
j = int(hashString(p.config, b[i].strVal) and high(branches))
@@ -860,8 +861,7 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
var bitMask = math.nextPowerOfTwo(strings) - 1
var branches: seq[Rope]
newSeq(branches, bitMask + 1)
var a: TLoc
initLocExpr(p, t[0], a) # fist pass: generate ifs+goto:
var a: TLoc = initLocExpr(p, t[0]) # first pass: generate ifs+goto:
var labId = p.labels
for i in 1..<t.len:
inc(p.labels)
@@ -897,6 +897,7 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
genCaseGeneric(p, t, d, "", "if (#eqStrings($1, $2)) goto $3;$n")
proc branchHasTooBigRange(b: PNode): bool =
result = false
for it in b:
# last son is block
if (it.kind == nkRange) and
@@ -904,6 +905,7 @@ proc branchHasTooBigRange(b: PNode): bool =
return true
proc ifSwitchSplitPoint(p: BProc, n: PNode): int =
result = 0
for i in 1..<n.len:
var branch = n[i]
var stmtBlock = lastSon(branch)
@@ -939,8 +941,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
var splitPoint = ifSwitchSplitPoint(p, n)
# generate if part (might be empty):
var a: TLoc
initLocExpr(p, n[0], a)
var a: TLoc = initLocExpr(p, n[0])
var lend = if splitPoint > 0: genIfForCaseUntil(p, n, d,
rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
eqFormat = "if ($1 == $2) goto $3;$n",
@@ -970,7 +971,7 @@ proc genOrdinalCase(p: BProc, n: PNode, d: var TLoc) =
proc genCase(p: BProc, t: PNode, d: var TLoc) =
genLineDir(p, t)
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
d = getTemp(p, t.typ)
case skipTypes(t[0].typ, abstractVarRange).kind
of tyString:
genStringCase(p, t, tyString, d)
@@ -996,7 +997,7 @@ proc genRestoreFrameAfterException(p: BProc) =
proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
#[ code to generate:
std::exception_ptr error = nullptr;
std::exception_ptr error;
try {
body;
} catch (Exception e) {
@@ -1021,13 +1022,13 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
p.module.includeHeader("<exception>")
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
d = getTemp(p, t.typ)
genLineDir(p, t)
inc(p.labels, 2)
let etmp = p.labels
p.procSec(cpsInit).add(ropecg(p.module, "\tstd::exception_ptr T$1_ = nullptr;", [etmp]))
lineCg(p, cpsStmts, "std::exception_ptr T$1_;$n", [etmp])
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
p.nestedTryStmts.add((fin, false, 0.Natural))
@@ -1061,7 +1062,6 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
if hasIf: lineF(p, cpsStmts, "else ", [])
startBlock(p)
# we handled the error:
linefmt(p, cpsStmts, "T$1_ = nullptr;$n", [etmp])
expr(p, t[i][0], d)
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
endBlock(p)
@@ -1124,7 +1124,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
if t[i].len == 1:
# general except section:
startBlock(p, "catch (...) {", [])
startBlock(p, "catch (...) {$n", [])
genExceptBranchBody(t[i][0])
endBlock(p)
catchAllPresent = true
@@ -1150,7 +1150,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
# general finally block:
if t.len > 0 and t[^1].kind == nkFinally:
if not catchAllPresent:
startBlock(p, "catch (...) {", [])
startBlock(p, "catch (...) {$n", [])
genRestoreFrameAfterException(p)
linefmt(p, cpsStmts, "T$1_ = std::current_exception();$n", [etmp])
endBlock(p)
@@ -1187,7 +1187,7 @@ proc genTryCppOld(p: BProc, t: PNode, d: var TLoc) =
expr(p, body, d)
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
d = getTemp(p, t.typ)
genLineDir(p, t)
cgsym(p.module, "popCurrentExceptionEx")
let fin = if t[^1].kind == nkFinally: t[^1] else: nil
@@ -1265,7 +1265,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
p.flags.incl nimErrorFlagAccessed
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
d = getTemp(p, t.typ)
expr(p, t[0], d)
@@ -1300,7 +1300,8 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
if optTinyRtti in p.config.globalOptions:
let checkFor = $getObjDepth(t[i][j].typ)
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)",
[memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
else:
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
@@ -1371,7 +1372,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
# propagateCurrentException();
#
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
d = getTemp(p, t.typ)
let quirkyExceptions = p.config.exc == excQuirky or
(t.kind == nkHiddenTryStmt and sfSystemModule in p.module.module.flags)
if not quirkyExceptions:
@@ -1380,7 +1381,7 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
p.flags.incl noSafePoints
genLineDir(p, t)
cgsym(p.module, "Exception")
var safePoint: Rope
var safePoint: Rope = ""
if not quirkyExceptions:
safePoint = getTempName(p.module)
linefmt(p, cpsLocals, "#TSafePoint $1;$n", [safePoint])
@@ -1445,7 +1446,8 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
if optTinyRtti in p.config.globalOptions:
let checkFor = $getObjDepth(t[i][j].typ)
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)", [memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)",
[memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
else:
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
@@ -1483,8 +1485,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
of nkSym:
var sym = it.sym
if sym.kind in {skProc, skFunc, skIterator, skMethod}:
var a: TLoc
initLocExpr(p, it, a)
var a: TLoc = initLocExpr(p, it)
res.add($rdLoc(a))
elif sym.kind == skType:
res.add($getTypeDesc(p.module, sym.typ))
@@ -1496,8 +1497,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
res.add($getTypeDesc(p.module, it.typ))
else:
discard getTypeDesc(p.module, skipTypes(it.typ, abstractPtrs))
var a: TLoc
initLocExpr(p, it, a)
var a: TLoc = initLocExpr(p, it)
res.add($a.rdLoc)
if isAsmStmt and hasGnuAsm in CC[p.config.cCompiler].props:
@@ -1599,11 +1599,10 @@ when false:
expr(p, call, d)
proc asgnFieldDiscriminant(p: BProc, e: PNode) =
var a, tmp: TLoc
var dotExpr = e[0]
if dotExpr.kind == nkCheckedFieldExpr: dotExpr = dotExpr[0]
initLocExpr(p, e[0], a)
getTemp(p, a.t, tmp)
var a = initLocExpr(p, e[0])
var tmp: TLoc = getTemp(p, a.t)
expr(p, e[1], tmp)
if p.inUncheckedAssignSection == 0:
let field = dotExpr[1].sym
@@ -1621,9 +1620,8 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
else:
let le = e[0]
let ri = e[1]
var a: TLoc
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), skVar)
initLoc(a, locNone, le, OnUnknown)
var a: TLoc = initLoc(locNone, le, OnUnknown)
discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs), dkVar)
a.flags.incl(lfEnforceDeref)
a.flags.incl(lfPrepareForMutation)
genLineDir(p, le) # it can be a nkBracketExpr, which may raise
@@ -1635,7 +1633,7 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
loadInto(p, le, ri, a)
proc genStmts(p: BProc, t: PNode) =
var a: TLoc
var a: TLoc = default(TLoc)
let isPush = p.config.hasHint(hintExtendedContext)
if isPush: pushInfoContext(p.config, t.info)

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -19,13 +19,16 @@ when defined(nimPreviewSlimSystem):
proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
case n.kind
of nkStmtList:
result = nil
for i in 0..<n.len:
result = getPragmaStmt(n[i], w)
if result != nil: break
of nkPragma:
result = nil
for i in 0..<n.len:
if whichPragma(n[i]) == w: return n[i]
else: discard
else:
result = nil
proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
result = getPragmaStmt(n, w) != nil
@@ -121,8 +124,11 @@ 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
if tfByRef in pt.flags: return true
#note precedence: params override types
if optByRef in s.options: return true
elif sfByCopy in s.flags: return false
elif tfByRef in pt.flags: return true
elif tfByCopy in pt.flags: return false
case pt.kind
of tyObject:

View File

@@ -17,6 +17,8 @@ import
lowerings, tables, sets, ndi, lineinfos, pathutils, transf,
injectdestructors, astmsgs, modulepaths, backendpragmas
import nir/ast2ir
import pipelineutils
when defined(nimPreviewSlimSystem):
@@ -61,12 +63,10 @@ proc findPendingModule(m: BModule, s: PSym): BModule =
var ms = getModule(s)
result = m.g.modules[ms.position]
proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc) =
result.k = k
result.storage = s
result.lode = lode
result.r = ""
result.flags = {}
proc initLoc(k: TLocKind, lode: PNode, s: TStorageLoc, flags: TLocFlags = {}): TLoc =
result = TLoc(k: k, storage: s, lode: lode,
r: "", flags: flags
)
proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, r: Rope, s: TStorageLoc) {.inline.} =
# fills the loc if it is not already initialized
@@ -216,13 +216,9 @@ macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
elif frmt[i] == '#' and frmt[i+1] == '#':
inc(i, 2)
strLit.add("#")
var start = i
while i < frmt.len:
if frmt[i] != '$' and frmt[i] != '#': inc(i)
else: break
if i - 1 >= start:
strLit.add(substr(frmt, start, i - 1))
else:
strLit.add(frmt[i])
inc(i)
flushStrLit()
result.add newCall(ident"rope", resVar)
@@ -273,7 +269,16 @@ proc safeLineNm(info: TLineInfo): int =
proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
assert line >= 0
if optLineDir in conf.options and line > 0:
r.addf("$N#line $2 $1$N",
r.addf("\n#line $2 $1\n",
[rope(makeSingleLineCString(filename)), rope(line)])
proc genCLineDir(r: var Rope, filename: string, 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)])
else:
r.addf("\n#line $2 $1\n",
[rope(makeSingleLineCString(filename)), rope(line)])
proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
@@ -286,17 +291,33 @@ proc freshLineInfo(p: BProc; info: TLineInfo): bool =
p.lastLineInfo.line = info.line
p.lastLineInfo.fileIndex = info.fileIndex
result = true
else:
result = false
proc genCLineDir(r: var Rope, p: BProc, info: TLineInfo; conf: ConfigRef) =
if optLineDir in conf.options:
let lastFileIndex = p.lastLineInfo.fileIndex
if freshLineInfo(p, info):
genCLineDir(r, toFullPath(conf, info), info.safeLineNm, p, info, lastFileIndex)
proc genLineDir(p: BProc, t: PNode) =
if p == p.module.preInitProc: return
let line = t.info.safeLineNm
if optEmbedOrigSrc in p.config.globalOptions:
p.s(cpsStmts).add("//" & sourceLine(p.config, t.info) & "\L")
genCLineDir(p.s(cpsStmts), t.info, p.config)
let lastFileIndex = p.lastLineInfo.fileIndex
let freshLine = freshLineInfo(p, t.info)
if freshLine:
genCLineDir(p.s(cpsStmts), toFullPath(p.config, t.info), line, p, t.info, lastFileIndex)
if ({optLineTrace, optStackTrace} * p.options == {optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx:
if freshLineInfo(p, t.info):
linefmt(p, cpsStmts, "nimln_($1, $2);$n",
if freshLine:
if lastFileIndex == t.info.fileIndex:
linefmt(p, cpsStmts, "nimln_($1);",
[line])
else:
linefmt(p, cpsStmts, "nimlf_($1, $2);",
[line, quotedFilename(p.config, t.info)])
proc accessThreadLocalVar(p: BProc, s: PSym)
@@ -356,19 +377,19 @@ template mapTypeChooser(n: PNode): TSymKind =
template mapTypeChooser(a: TLoc): TSymKind = mapTypeChooser(a.lode)
proc addAddrLoc(conf: ConfigRef; a: TLoc; result: var Rope) =
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a)) != ctArray:
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a) == skParam) != ctArray:
result.add "(&" & a.r & ")"
else:
result.add a.r
proc addrLoc(conf: ConfigRef; a: TLoc): Rope =
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a)) != ctArray:
if lfIndirect notin a.flags and mapType(conf, a.t, mapTypeChooser(a) == skParam) != ctArray:
result = "(&" & a.r & ")"
else:
result = a.r
proc byRefLoc(p: BProc; a: TLoc): Rope =
if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a)) != ctArray and not
if lfIndirect notin a.flags and mapType(p.config, a.t, mapTypeChooser(a) == skParam) != ctArray and not
p.module.compileToCpp:
result = "(&" & a.r & ")"
else:
@@ -414,13 +435,13 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: var TLoc,
linefmt(p, section, "$1.m_type = $2;$n", [r, genTypeInfoV1(p.module, t, a.lode.info)])
of frEmbedded:
if optTinyRtti in p.config.globalOptions:
var tmp: TLoc
var tmp: TLoc = default(TLoc)
if mode == constructRefObj:
let objType = t.skipTypes(abstractInst+{tyRef})
rawConstExpr(p, newNodeIT(nkType, a.lode.info, objType), tmp)
linefmt(p, cpsStmts,
"#nimCopyMem((void*)$1, (NIM_CONST void*)&$2, sizeof($3));$n",
[rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType, mapTypeChooser(a))])
[rdLoc(a), rdLoc(tmp), getTypeDesc(p.module, objType, descKindFromSymKind mapTypeChooser(a))])
else:
rawConstExpr(p, newNodeIT(nkType, a.lode.info, t), tmp)
genAssignment(p, a, tmp, {})
@@ -462,8 +483,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
elif not isComplexValueType(typ):
if containsGcRef:
var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.lode, OnStack)
var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack)
nilLoc.r = rope("NIM_NIL")
genRefAssign(p, loc, nilLoc)
else:
@@ -480,36 +500,40 @@ proc resetLoc(p: BProc, loc: var TLoc) =
else:
# array passed as argument decayed into pointer, bug #7332
# so we use getTypeDesc here rather than rdLoc(loc)
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
[addrLoc(p.config, loc),
getTypeDesc(p.module, loc.t, mapTypeChooser(loc))])
let tyDesc = getTypeDesc(p.module, loc.t, descKindFromSymKind mapTypeChooser(loc))
if p.module.compileToCpp and isOrHasImportedCppType(typ):
if lfIndirect in loc.flags:
#C++ cant be just zeroed. We need to call the ctors
var tmp = getTemp(p, loc.t)
linefmt(p, cpsStmts,"#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
[addrLoc(p.config, loc), addrLoc(p.config, tmp), tyDesc])
else:
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
[addrLoc(p.config, loc), tyDesc])
# XXX: We can be extra clever here and call memset only
# on the bytes following the m_type field?
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
proc isOrHasImportedCppType(typ: PType): bool =
searchTypeFor(typ.skipTypes({tyRef}), isImportedCppType)
proc constructLoc(p: BProc, loc: var TLoc, isTemp = false) =
let typ = loc.t
if optSeqDestructors in p.config.globalOptions and skipTypes(typ, abstractInst + {tyStatic}).kind in {tyString, tySequence}:
linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", [rdLoc(loc)])
elif not isComplexValueType(typ):
if containsGarbageCollectedRef(loc.t):
var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.lode, OnStack)
var nilLoc: TLoc = initLoc(locTemp, loc.lode, OnStack)
nilLoc.r = rope("NIM_NIL")
genRefAssign(p, loc, nilLoc)
else:
linefmt(p, cpsStmts, "$1 = ($2)0;$n", [rdLoc(loc),
getTypeDesc(p.module, typ, mapTypeChooser(loc))])
getTypeDesc(p.module, typ, descKindFromSymKind mapTypeChooser(loc))])
else:
if not isTemp or containsGarbageCollectedRef(loc.t):
# don't use nimZeroMem for temporary values for performance if we can
# avoid it:
if not isOrHasImportedCppType(typ):
linefmt(p, cpsStmts, "#nimZeroMem((void*)$1, sizeof($2));$n",
[addrLoc(p.config, loc), getTypeDesc(p.module, typ, mapTypeChooser(loc))])
[addrLoc(p.config, loc), getTypeDesc(p.module, typ, descKindFromSymKind mapTypeChooser(loc))])
genObjectInit(p, cpsStmts, loc.t, loc, constructObj)
proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
@@ -524,17 +548,14 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
if not immediateAsgn:
constructLoc(p, v.loc)
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
proc getTemp(p: BProc, t: PType, needsInit=false): TLoc =
inc(p.labels)
result.r = "T" & rope(p.labels) & "_"
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
storage: OnStack, flags: {})
if p.module.compileToCpp and isOrHasImportedCppType(t):
linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, skVar), result.r])
linefmt(p, cpsLocals, "$1 $2{};$n", [getTypeDesc(p.module, t, dkVar), result.r])
else:
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, skVar), result.r])
result.k = locTemp
result.lode = lodeTyp t
result.storage = OnStack
result.flags = {}
linefmt(p, cpsLocals, "$1 $2;$n", [getTypeDesc(p.module, t, dkVar), result.r])
constructLoc(p, result, not needsInit)
when false:
# XXX Introduce a compiler switch in order to detect these easily.
@@ -545,25 +566,21 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
echo "ENORMOUS TEMPORARY! ", p.config $ p.lastLineInfo
writeStackTrace()
proc getTempCpp(p: BProc, t: PType, result: var TLoc; value: Rope) =
proc getTempCpp(p: BProc, t: PType, value: Rope): TLoc =
inc(p.labels)
result.r = "T" & rope(p.labels) & "_"
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, skVar), result.r, value])
result.k = locTemp
result.lode = lodeTyp t
result.storage = OnStack
result.flags = {}
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp, lode: lodeTyp t,
storage: OnStack, flags: {})
linefmt(p, cpsStmts, "$1 $2 = $3;$n", [getTypeDesc(p.module, t, dkVar), result.r, value])
proc getIntTemp(p: BProc, result: var TLoc) =
proc getIntTemp(p: BProc): TLoc =
inc(p.labels)
result.r = "T" & rope(p.labels) & "_"
result = TLoc(r: "T" & rope(p.labels) & "_", k: locTemp,
storage: OnStack, lode: lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt),
flags: {})
linefmt(p, cpsLocals, "NI $1;$n", [result.r])
result.k = locTemp
result.storage = OnStack
result.lode = lodeTyp getSysType(p.module.g.graph, unknownLineInfo, tyInt)
result.flags = {}
proc localVarDecl(p: BProc; n: PNode): Rope =
result = ""
let s = n.sym
if s.loc.k == locNone:
fillLocalName(p, s)
@@ -572,10 +589,10 @@ proc localVarDecl(p: BProc; n: PNode): Rope =
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
result.addf("NIM_ALIGN($1) ", [rope(s.alignment)])
genCLineDir(result, n.info, p.config)
genCLineDir(result, p, n.info, p.config)
result.add getTypeDesc(p.module, s.typ, skVar)
if s.constraint.isNil:
result.add getTypeDesc(p.module, s.typ, dkVar)
if sfCodegenDecl notin s.flags:
if sfRegister in s.flags: result.add(" register")
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
# decl.add(" GC_GUARD")
@@ -590,7 +607,7 @@ proc assignLocalVar(p: BProc, n: PNode) =
#assert(s.loc.k == locNone) # not yet assigned
# this need not be fulfilled for inline procs; they are regenerated
# for each module that uses them!
let nl = if optLineDir in p.config.options: "" else: "\L"
let nl = if optLineDir in p.config.options: "" else: "\n"
let decl = localVarDecl(p, n) & (if p.module.compileToCpp and isOrHasImportedCppType(n.typ): "{};" else: ";") & nl
line(p, cpsLocals, decl)
@@ -604,6 +621,40 @@ proc treatGlobalDifferentlyForHCR(m: BModule, s: PSym): bool =
# and s.owner.kind == skModule # owner isn't always a module (global pragma on local var)
# and s.loc.k == locGlobalVar # loc isn't always initialized when this proc is used
proc genGlobalVarDecl(p: BProc, n: PNode; td, value: Rope; decl: var Rope) =
let s = n.sym
if sfCodegenDecl notin s.flags:
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)]
if p.hcrOn: decl.add("static ")
elif sfImportc in s.flags: decl.add("extern ")
elif lfExportLib in s.loc.flags: decl.add("N_LIB_EXPORT_VAR ")
else: decl.add("N_LIB_PRIVATE ")
if s.kind == skLet and value != "": decl.add("NIM_CONST ")
decl.add(td)
if p.hcrOn: decl.add("*")
if sfRegister in s.flags: decl.add(" register")
if sfVolatile in s.flags: decl.add(" volatile")
if sfNoalias in s.flags: decl.add(" NIM_NOALIAS")
else:
if value != "":
decl = runtimeFormat(s.cgDeclFrmt & " = $#;$n", [td, s.loc.r, value])
else:
decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r])
proc genCppVarForCtor(p: BProc, v: PSym; vn, value: PNode; decl: var Rope)
proc callGlobalVarCppCtor(p: BProc; v: PSym; vn, value: PNode) =
let s = vn.sym
fillBackendName(p.module, s)
fillLoc(s.loc, locGlobalVar, vn, OnHeap)
var decl: Rope = ""
let td = getTypeDesc(p.module, vn.sym.typ, dkVar)
genGlobalVarDecl(p, vn, td, "", decl)
decl.add " " & $s.loc.r
genCppVarForCtor(p, v, vn, value, decl)
p.module.s[cfsVars].add decl
proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
let s = n.sym
if s.loc.k == locNone:
@@ -629,29 +680,30 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) =
internalError(p.config, n.info, ".threadvar variables cannot have a value")
else:
var decl: Rope = ""
var td = getTypeDesc(p.module, s.loc.t, skVar)
let td = getTypeDesc(p.module, s.loc.t, dkVar)
genGlobalVarDecl(p, n, td, value, decl)
if s.constraint.isNil:
if s.kind in {skLet, skVar, skField, skForVar} and s.alignment > 0:
decl.addf "NIM_ALIGN($1) ", [rope(s.alignment)]
if p.hcrOn: decl.add("static ")
elif sfImportc in s.flags: decl.add("extern ")
elif lfExportLib in s.loc.flags: decl.add("N_LIB_EXPORT_VAR ")
else: decl.add("N_LIB_PRIVATE ")
if s.kind == skLet and value != "": decl.add("NIM_CONST ")
decl.add(td)
if p.hcrOn: decl.add("*")
if sfRegister in s.flags: decl.add(" register")
if sfVolatile in s.flags: decl.add(" volatile")
if sfNoalias in s.flags: decl.add(" NIM_NOALIAS")
if value != "":
decl.addf(" $1 = $2;$n", [s.loc.r, value])
if p.module.compileToCpp and value.startsWith "{{}":
# TODO: taking this branch, re"\{\{\}(,\s\{\})*\}" might be emitted, resulting in
# either warnings (GCC 12.2+) or errors (Clang 15, MSVC 19.3+) of C++11+ compilers **when
# explicit constructors are around** due to overload resolution rules in place [^0][^1][^2]
# *Workaround* here: have C++'s static initialization mechanism do the default init work,
# for us lacking a deeper knowledge of an imported object's constructors' ex-/implicitness
# (so far) *and yet* trying to achieve default initialization.
# Still, generating {}s in genConstObjConstr() just to omit them here is faaaar from ideal;
# need to figure out a better way, possibly by keeping around more data about the
# imported objects' contructors?
#
# [^0]: https://en.cppreference.com/w/cpp/language/aggregate_initialization
# [^1]: https://cplusplus.github.io/CWG/issues/1518.html
# [^2]: https://eel.is/c++draft/over.match.ctor
decl.addf(" $1;$n", [s.loc.r])
else:
decl.addf(" $1 = $2;$n", [s.loc.r, value])
else:
decl.addf(" $1;$n", [s.loc.r])
else:
if value != "":
decl = runtimeFormat(s.cgDeclFrmt & " = $#;$n", [td, s.loc.r, value])
else:
decl = runtimeFormat(s.cgDeclFrmt & ";$n", [td, s.loc.r])
p.module.s[cfsVars].add(decl)
if p.withinLoop > 0 and value == "":
# fixes tests/run/tzeroarray:
@@ -672,7 +724,7 @@ proc getLabel(p: BProc): TLabel =
result = "LA" & rope(p.labels) & "_"
proc fixLabel(p: BProc, labl: TLabel) =
lineF(p, cpsStmts, "$1: ;$n", [labl])
p.s(cpsStmts).add("$1: ;$n" % [labl])
proc genVarPrototype(m: BModule, n: PNode)
proc requestConstImpl(p: BProc, sym: PSym)
@@ -685,12 +737,12 @@ proc genLiteral(p: BProc, n: PNode; result: var Rope)
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; argsCounter: var int)
proc raiseExit(p: BProc)
proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
initLoc(result, locNone, e, OnUnknown)
proc initLocExpr(p: BProc, e: PNode, flags: TLocFlags = {}): TLoc =
result = initLoc(locNone, e, OnUnknown, flags)
expr(p, e, result)
proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
initLoc(result, locNone, e, OnUnknown)
proc initLocExprSingleUse(p: BProc, e: PNode): TLoc =
result = initLoc(locNone, e, OnUnknown)
if e.kind in nkCallKinds and (e[0].kind != nkSym or e[0].sym.magic == mNone):
# We cannot check for tfNoSideEffect here because of mutable parameters.
discard "bug #8202; enforce evaluation order for nested calls for C++ too"
@@ -714,8 +766,12 @@ $1define nimfr_(proc, file) \
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename;NI len;VarSlot s[slots];} FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = length; #nimFrame((TFrame*)&FR_);
$1define nimln_(n, file) \
$1define nimln_(n) \
FR_.line = n;
$1define nimlf_(n, file) \
FR_.line = n; FR_.filename = file;
"""
if p.module.s[cfsFrameDefines].len == 0:
appcg(p.module, p.module.s[cfsFrameDefines], frameDefines, ["#"])
@@ -777,11 +833,10 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
var p = newProc(nil, m)
p.options.excl optStackTrace
p.flags.incl nimErrorFlagDisabled
var dest: TLoc
initLoc(dest, locTemp, lib.path, OnStack)
var dest: TLoc = initLoc(locTemp, lib.path, OnStack)
dest.r = getTempName(m)
appcg(m, m.s[cfsDynLibInit],"$1 $2;$n",
[getTypeDesc(m, lib.path.typ, skVar), rdLoc(dest)])
[getTypeDesc(m, lib.path.typ, dkVar), rdLoc(dest)])
expr(p, lib.path, dest)
m.s[cfsVars].add(p.s(cpsLocals))
@@ -813,15 +868,14 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
inc(m.labels, 2)
if isCall:
let n = lib.path
var a: TLoc
initLocExpr(m.initProc, n[0], a)
var a: TLoc = initLocExpr(m.initProc, n[0])
var params = rdLoc(a) & "("
for i in 1..<n.len-1:
initLocExpr(m.initProc, n[i], a)
a = initLocExpr(m.initProc, n[i])
params.add(rdLoc(a))
params.add(", ")
let load = "\t$1 = ($2) ($3$4));$n" %
[tmp, getTypeDesc(m, sym.typ, skVar), params, makeCString($extname)]
[tmp, getTypeDesc(m, sym.typ, dkVar), params, makeCString($extname)]
var last = lastSon(n)
if last.kind == nkHiddenStdConv: last = last[1]
internalAssert(m.config, last.kind == nkStrLit)
@@ -835,8 +889,8 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
else:
appcg(m, m.s[cfsDynLibInit],
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)])
m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)])
[tmp, getTypeDesc(m, sym.typ, dkVar), lib.name, makeCString($extname)])
m.s[cfsVars].addf("$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t, dkVar)])
proc varInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex
@@ -848,9 +902,9 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
inc(m.labels, 2)
appcg(m, m.s[cfsDynLibInit],
"$1 = ($2*) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ, skVar), lib.name, makeCString($extname)])
[tmp, getTypeDesc(m, sym.typ, dkVar), lib.name, makeCString($extname)])
m.s[cfsVars].addf("$2* $1;$n",
[sym.loc.r, getTypeDesc(m, sym.loc.t, skVar)])
[sym.loc.r, getTypeDesc(m, sym.loc.t, dkVar)])
proc symInDynamicLibPartial(m: BModule, sym: PSym) =
sym.loc.r = mangleDynLibProc(sym)
@@ -881,7 +935,9 @@ proc cgsymValue(m: BModule, name: string): Rope =
result.addActualSuffixForHCR(m.module, sym)
proc generateHeaders(m: BModule) =
m.s[cfsHeaders].add("\L#include \"nimbase.h\"\L")
var nimbase = m.config.nimbasePattern
if nimbase == "": nimbase = "nimbase.h"
m.s[cfsHeaders].addf("\L#include \"$1\"\L", [nimbase])
for it in m.headerFiles:
if it[0] == '#':
@@ -930,11 +986,19 @@ proc closureSetup(p: BProc, prc: PSym) =
linefmt(p, cpsStmts, "$1 = ($2) ClE_0;$n",
[rdLoc(env.loc), getTypeDesc(p.module, env.typ)])
const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef,
nkMacroDef, nkMixinStmt, nkBindStmt, nkFormalParams} +
declarativeDefs
proc containsResult(n: PNode): bool =
result = false
case n.kind
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkFormalParams:
of succ(nkEmpty)..pred(nkSym), succ(nkSym)..nkNilLit, harmless:
discard
of nkReturnStmt:
for i in 0..<n.len:
if containsResult(n[i]): return true
result = n.len > 0 and n[0].kind == nkEmpty
of nkSym:
if n.sym.kind == skResult:
result = true
@@ -942,11 +1006,8 @@ 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 =
result = nil
case n.kind
of nkStmtList, nkStmtListExpr:
var i = 0
@@ -1071,14 +1132,14 @@ proc allPathsAsgnResult(n: PNode): InitResultEnum =
proc getProcTypeCast(m: BModule, prc: PSym): Rope =
result = getTypeDesc(m, prc.loc.t)
if prc.typ.callConv == ccClosure:
var rettype, params: Rope
var rettype, params: Rope = ""
var check = initIntSet()
genProcParams(m, prc.typ, rettype, params, check)
result = "$1(*)$2" % [rettype, params]
proc genProcBody(p: BProc; procBody: PNode) =
genStmts(p, procBody) # modifies p.locals, p.init, etc.
if {nimErrorFlagAccessed, nimErrorFlagDeclared} * p.flags == {nimErrorFlagAccessed}:
if {nimErrorFlagAccessed, nimErrorFlagDeclared, nimErrorFlagDisabled} * p.flags == {nimErrorFlagAccessed}:
p.flags.incl nimErrorFlagDeclared
p.blocks[0].sections[cpsLocals].add(ropecg(p.module, "NIM_BOOL* nimErr_;$n", []))
p.blocks[0].sections[cpsInit].add(ropecg(p.module, "nimErr_ = #nimErrorFlag();$n", []))
@@ -1086,10 +1147,14 @@ proc genProcBody(p: BProc; procBody: PNode) =
proc isNoReturn(m: BModule; s: PSym): bool {.inline.} =
sfNoReturn in s.flags and m.config.exc != excGoto
proc genProcAux(m: BModule, prc: PSym) =
proc genProcAux*(m: BModule, prc: PSym) =
var p = newProc(prc, m)
var header = newRopeAppender()
genProcHeader(m, prc, header)
let isCppMember = m.config.backend == backendCpp and sfCppMember * prc.flags != {}
if isCppMember:
genMemberProcHeader(m, prc, header)
else:
genProcHeader(m, prc, header)
var returnStmt: Rope = ""
assert(prc.ast != nil)
@@ -1097,24 +1162,39 @@ proc genProcAux(m: BModule, prc: PSym) =
if sfInjectDestructors in prc.flags:
procBody = injectDestructorCalls(m.g.graph, m.idgen, prc, procBody)
let tmpInfo = prc.info
discard freshLineInfo(p, prc.info)
if sfPure notin prc.flags and prc.typ[0] != nil:
if resultPos >= prc.ast.len:
internalError(m.config, prc.info, "proc has no result symbol")
let resNode = prc.ast[resultPos]
let res = resNode.sym # get result symbol
if not isInvalidReturnType(m.config, prc.typ):
if not isInvalidReturnType(m.config, prc.typ) and sfConstructor notin prc.flags:
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(procBody); val != nil):
var decl = localVarDecl(p, resNode)
var a: TLoc
initLocExprSingleUse(p, val, a)
var a: TLoc = initLocExprSingleUse(p, val)
linefmt(p, cpsStmts, "$1 = $2;$n", [decl, rdLoc(a)])
else:
# 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(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)
let ty = resNode.sym.typ[0] #generate nim's ctor
for i in 1..<resNode.sym.ast.len:
let field = resNode.sym.ast[i]
genFieldObjConstr(p, ty, useTemp = false, isRef = false,
field[0], field[1], check = nil, resNode.sym.loc, "(*this)", tmpInfo)
else:
fillResult(p.config, resNode, prc.typ)
assignParam(p, res, prc.typ[0])
@@ -1139,13 +1219,15 @@ proc genProcAux(m: BModule, prc: PSym) =
closureSetup(p, prc)
genProcBody(p, procBody)
var generatedProc: Rope
prc.info = tmpInfo
var generatedProc: Rope = ""
generatedProc.genCLineDir prc.info, m.config
if isNoReturn(p.module, prc):
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember:
header = "__declspec(noreturn) " & header
if sfPure in prc.flags:
if hasDeclspec in extccomp.CC[p.config.cCompiler].props:
if hasDeclspec in extccomp.CC[p.config.cCompiler].props and not isCppMember:
header = "__declspec(naked) " & header
generatedProc.add ropecg(p.module, "$1 {$n$2$3$4}$N$N",
[header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts)])
@@ -1190,7 +1272,7 @@ proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
proc genProcPrototype(m: BModule, sym: PSym) =
useHeader(m, sym)
if lfNoDecl in sym.loc.flags: return
if lfNoDecl in sym.loc.flags or sfCppMember * sym.flags != {}: return
if lfDynamicLib in sym.loc.flags:
if sym.itemId.module != m.module.position and
not containsOrIncl(m.declaredThings, sym.id):
@@ -1226,6 +1308,20 @@ proc genProcNoForward(m: BModule, prc: PSym) =
if lfNoDecl in prc.loc.flags:
fillProcLoc(m, prc.ast[namePos])
genProcPrototype(m, prc)
elif lfDynamicLib in prc.loc.flags:
var q = findPendingModule(m, prc)
fillProcLoc(q, prc.ast[namePos])
genProcPrototype(m, prc)
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
symInDynamicLib(q, prc)
# register the procedure even though it is in a different dynamic library and will not be
# reloadable (and has no _actual suffix) - other modules will need to be able to get it through
# the hcr dynlib (also put it in the DynLibInit section - right after it gets loaded)
if isReloadable(q, prc):
q.s[cfsDynLibInit].addf("\t$1 = ($2) hcrRegisterProc($3, \"$1\", (void*)$1);$n",
[prc.loc.r, getTypeDesc(q, prc.loc.t), getModuleDllPath(m, q.module)])
else:
symInDynamicLibPartial(m, prc)
elif prc.typ.callConv == ccInline:
# We add inline procs to the calling module to enable C based inlining.
# This also means that a check with ``q.declaredThings`` is wrong, we need
@@ -1244,20 +1340,6 @@ proc genProcNoForward(m: BModule, prc: PSym) =
# prc.loc.r = mangleName(m, prc)
genProcPrototype(m, prc)
genProcAux(m, prc)
elif lfDynamicLib in prc.loc.flags:
var q = findPendingModule(m, prc)
fillProcLoc(q, prc.ast[namePos])
genProcPrototype(m, prc)
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
symInDynamicLib(q, prc)
# register the procedure even though it is in a different dynamic library and will not be
# reloadable (and has no _actual suffix) - other modules will need to be able to get it through
# the hcr dynlib (also put it in the DynLibInit section - right after it gets loaded)
if isReloadable(q, prc):
q.s[cfsDynLibInit].addf("\t$1 = ($2) hcrRegisterProc($3, \"$1\", (void*)$1);$n",
[prc.loc.r, getTypeDesc(q, prc.loc.t), getModuleDllPath(m, q.module)])
else:
symInDynamicLibPartial(m, prc)
elif sfImportc notin prc.flags:
var q = findPendingModule(m, prc)
fillProcLoc(q, prc.ast[namePos])
@@ -1321,14 +1403,14 @@ proc genVarPrototype(m: BModule, n: PNode) =
if sym.owner.id != m.module.id:
# else we already have the symbol generated!
assert(sym.loc.r != "")
incl(m.declaredThings, sym.id)
if sfThread in sym.flags:
declareThreadVar(m, sym, true)
else:
incl(m.declaredThings, sym.id)
if sym.kind in {skLet, skVar, skField, skForVar} and sym.alignment > 0:
m.s[cfsVars].addf "NIM_ALIGN($1) ", [rope(sym.alignment)]
m.s[cfsVars].add(if m.hcrOn: "static " else: "extern ")
m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, skVar))
m.s[cfsVars].add(getTypeDesc(m, sym.loc.t, dkVar))
if m.hcrOn: m.s[cfsVars].add("*")
if lfDynamicLib in sym.loc.flags: m.s[cfsVars].add("*")
if sfRegister in sym.flags: m.s[cfsVars].add(" register")
@@ -1337,7 +1419,7 @@ proc genVarPrototype(m: BModule, n: PNode) =
m.s[cfsVars].addf(" $1;$n", [sym.loc.r])
if m.hcrOn: m.initProc.procSec(cpsLocals).addf(
"\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r,
getTypeDesc(m, sym.loc.t, skVar), getModuleDllPath(m, sym)])
getTypeDesc(m, sym.loc.t, dkVar), getModuleDllPath(m, sym)])
proc addNimDefines(result: var Rope; conf: ConfigRef) {.inline.} =
result.addf("#define NIM_INTBITS $1\L", [
@@ -1369,17 +1451,21 @@ proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
proc getSomeNameForModule(conf: ConfigRef, filename: AbsoluteFile): Rope =
## Returns a mangled module name.
result = ""
result.add mangleModuleName(conf, filename).mangle
proc getSomeNameForModule(m: BModule): Rope =
## Returns a mangled module name.
assert m.module.kind == skModule
assert m.module.owner.kind == skPackage
result = ""
result.add mangleModuleName(m.g.config, m.filename).mangle
proc getSomeInitName(m: BModule, suffix: string): Rope =
if not m.hcrOn:
result = getSomeNameForModule(m)
else:
result = ""
result.add suffix
proc getInitName(m: BModule): Rope =
@@ -1398,10 +1484,10 @@ proc genMainProc(m: BModule) =
## this function is called in cgenWriteModules after all modules are closed,
## it means raising dependency on the symbols is too late as it will not propagate
## into other modules, only simple rope manipulations are allowed
var preMainCode: Rope
var preMainCode: Rope = ""
if m.hcrOn:
proc loadLib(handle: string, name: string): Rope =
result = ""
let prc = magicsys.getCompilerProc(m.g.graph, name)
assert prc != nil
let n = newStrNode(nkStrLit, prc.annex.path.strVal)
@@ -1413,20 +1499,23 @@ proc genMainProc(m: BModule) =
[handle, strLit])
preMainCode.add(loadLib("hcr_handle", "hcrGetProc"))
preMainCode.add("\tvoid* rtl_handle;\L")
preMainCode.add(loadLib("rtl_handle", "nimGC_setStackBottom"))
preMainCode.add(hcrGetProcLoadCode(m, "nimGC_setStackBottom", "nimrtl_", "rtl_handle", "nimGetProcAddr"))
preMainCode.add("\tinner = PreMain;\L")
preMainCode.add("\tinitStackBottomWith_actual((void *)&inner);\L")
preMainCode.add("\t(*inner)();\L")
if m.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
preMainCode.add("\t$1PreMain();\L" % [rope m.config.nimMainPrefix])
else:
preMainCode.add("\tvoid* rtl_handle;\L")
preMainCode.add(loadLib("rtl_handle", "nimGC_setStackBottom"))
preMainCode.add(hcrGetProcLoadCode(m, "nimGC_setStackBottom", "nimrtl_", "rtl_handle", "nimGetProcAddr"))
preMainCode.add("\tinner = $1PreMain;\L" % [rope m.config.nimMainPrefix])
preMainCode.add("\tinitStackBottomWith_actual((void *)&inner);\L")
preMainCode.add("\t(*inner)();\L")
else:
preMainCode.add("\t$1PreMain();\L" % [rope m.config.nimMainPrefix])
var posixCmdLine: Rope
var posixCmdLine: Rope = ""
if optNoMain notin m.config.globalOptions:
posixCmdLine.add "\tN_LIB_PRIVATE int cmdCount;\L"
posixCmdLine.add "\tN_LIB_PRIVATE char** cmdLine;\L"
posixCmdLine.add "\tN_LIB_PRIVATE char** gEnv;\L"
posixCmdLine.add "N_LIB_PRIVATE int cmdCount;\L"
posixCmdLine.add "N_LIB_PRIVATE char** cmdLine;\L"
posixCmdLine.add "N_LIB_PRIVATE char** gEnv;\L"
const
# The use of a volatile function pointer to call Pre/NimMainInner
@@ -1439,15 +1528,15 @@ proc genMainProc(m: BModule) =
"}$N$N" &
"$4" &
"N_LIB_PRIVATE void $3PreMain(void) {$N" &
"\t##if $5$N" & # 1 for volatile call, 0 for non-volatile
"##if $5$N" & # 1 for volatile call, 0 for non-volatile
"\tvoid (*volatile inner)(void);$N" &
"\tinner = $3PreMainInner;$N" &
"$1" &
"\t(*inner)();$N" &
"\t##else$N" &
"##else$N" &
"$1" &
"\t$3PreMainInner();$N" &
"\t##endif$N" &
"##endif$N" &
"}$N$N"
MainProcs =
@@ -1462,17 +1551,17 @@ proc genMainProc(m: BModule) =
NimMainProc =
"N_CDECL(void, $5NimMain)(void) {$N" &
"\t##if $6$N" & # 1 for volatile call, 0 for non-volatile
"##if $6$N" & # 1 for volatile call, 0 for non-volatile
"\tvoid (*volatile inner)(void);$N" &
"$4" &
"\tinner = $5NimMainInner;$N" &
"$2" &
"\t(*inner)();$N" &
"\t##else$N" &
"##else$N" &
"$4" &
"$2" &
"\t$5NimMainInner();$N" &
"\t##endif$N" &
"##endif$N" &
"}$N$N"
NimMainBody = NimMainInner & NimMainProc
@@ -1503,7 +1592,7 @@ proc genMainProc(m: BModule) =
WinCDllMain =
"BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $N" &
" LPVOID lpvReserved) {$N" &
"\tif(fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "}$N" &
"\tif (fwdreason == DLL_PROCESS_ATTACH) {$N" & MainProcs & "\t}$N" &
"\treturn 1;$N}$N$N"
PosixNimDllMain = WinNimDllMain
@@ -1537,11 +1626,11 @@ proc genMainProc(m: BModule) =
m.includeHeader("<libc/component.h>")
let initStackBottomCall =
if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcOrc}: "".rope
if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcAtomicArc, gcOrc}: "".rope
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", [])
inc(m.labels)
let isVolatile = if m.config.selectedGC notin {gcNone, gcArc, gcOrc}: "1" else: "0"
let isVolatile = if m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}: "1" else: "0"
appcg(m, m.s[cfsProcs], PreMainBody, [m.g.mainDatInit, m.g.otherModsInit, m.config.nimMainPrefix, posixCmdLine, isVolatile])
if m.config.target.targetOS == osWindows and
@@ -1681,7 +1770,7 @@ proc registerModuleToMain(g: BModuleList; m: BModule) =
if sfSystemModule in m.module.flags:
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
g.mainDatInit.add(ropecg(m, "\t#initThreadVarsEmulation();$N", []))
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}:
g.mainDatInit.add(ropecg(m, "\t#initStackBottomWith((void *)&inner);$N", []))
if m.s[cfsInitProc].len > 0:
@@ -1732,10 +1821,10 @@ proc hcrGetProcLoadCode(m: BModule, sym, prefix, handle, getProcFunc: string): R
prc.typ.sym = nil
if not containsOrIncl(m.declaredThings, prc.id):
m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, skVar)])
m.s[cfsVars].addf("static $2 $1;$n", [prc.loc.r, getTypeDesc(m, prc.loc.t, dkVar)])
result = "\t$1 = ($2) $3($4, $5);$n" %
[tmp, getTypeDesc(m, prc.typ, skVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
[tmp, getTypeDesc(m, prc.typ, dkVar), getProcFunc.rope, handle.rope, makeCString(prefix & sym)]
proc genInitCode(m: BModule) =
## this function is called in cgenWriteModules after all modules are closed,
@@ -1811,13 +1900,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", [])
@@ -1874,8 +1963,6 @@ proc genModule(m: BModule, cfile: Cfile): Rope =
openNamespaceNim(m.config.cppCustomNamespace, result)
if m.s[cfsFrameDefines].len > 0:
result.add(m.s[cfsFrameDefines])
else:
result.add("#define nimfr_(x, y)\n#define nimln_(x, y)\n")
for i in cfsForwardTypes..cfsProcs:
if m.s[i].len > 0:
@@ -1919,7 +2006,7 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
result.preInitProc = newProc(nil, result)
result.preInitProc.flags.incl nimErrorFlagDisabled
result.preInitProc.labels = 100_000 # little hack so that unique temporaries are generated
initNodeTable(result.dataCache)
result.dataCache = initNodeTable()
result.typeStack = @[]
result.typeNodesName = getTempName(result)
result.nimTypesName = getTempName(result)
@@ -2024,6 +2111,11 @@ proc genTopLevelStmt*(m: BModule; n: PNode) =
if sfInjectDestructors in m.module.flags:
transformedN = injectDestructorCalls(m.g.graph, m.idgen, m.module, transformedN)
if sfMainModule in m.module.flags:
let moduleCon = initModuleCon(m.g.graph, m.config, m.module)
var procCon = initProcCon(moduleCon, nil)
genCode(procCon, transformedN)
if m.hcrOn:
addHcrInitGuards(m.initProc, transformedN, m.inHcrInitGuard)
else:
@@ -2094,8 +2186,9 @@ proc updateCachedModule(m: BModule) =
cf.flags = {CfileFlag.Cached}
addFileToCompile(m.config, cf)
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode): PNode =
## Also called from IC.
result = nil
if sfMainModule in m.module.flags:
# phase ordering problem here: We need to announce this
# dependency to 'nimTestErrorFlag' before system.c has been written to disk.
@@ -2116,7 +2209,10 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
if m.hcrOn:
# make sure this is pulled in (meaning hcrGetGlobal() is called for it during init)
cgsym(m, "programResult")
let sym = magicsys.getCompilerProc(m.g.graph, "programResult")
# ignore when not available, could be a module imported early in `system`
if sym != nil:
cgsymImpl m, sym
if m.inHcrInitGuard:
endBlock(m.initProc)
@@ -2133,15 +2229,14 @@ proc finalCodegenActions*(graph: ModuleGraph; m: BModule; n: PNode) =
cgsym(m, "rawWrite")
# raise dependencies on behalf of genMainProc
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcOrc}:
if m.config.target.targetOS != osStandalone and m.config.selectedGC notin {gcNone, gcArc, gcAtomicArc, gcOrc}:
cgsym(m, "initStackBottomWith")
if emulatedThreadVars(m.config) and m.config.target.targetOS != osStandalone:
cgsym(m, "initThreadVarsEmulation")
if m.g.forwardedProcs.len == 0:
incl m.flags, objHasKidsValid
let disp = generateMethodDispatchers(graph)
for x in disp: genProcAux(m, x.sym)
result = generateMethodDispatchers(graph, m.idgen)
let mm = m
m.g.modulesClosed.add mm

View File

@@ -193,15 +193,17 @@ proc initBlock*(): TBlock =
result.sections[i] = newRopeAppender()
proc newProc*(prc: PSym, module: BModule): BProc =
new(result)
result.prc = prc
result.module = module
result.options = if prc != nil: prc.options
else: module.config.options
result.blocks = @[initBlock()]
result.nestedTryStmts = @[]
result.finallySafePoints = @[]
result.sigConflicts = initCountTable[string]()
result = BProc(
prc: prc,
module: module,
optionsStack: if module.initProc != nil: module.initProc.optionsStack
else: @[],
options: if prc != nil: prc.options
else: module.config.options,
blocks: @[initBlock()],
sigConflicts: initCountTable[string]())
if optQuirky in result.options:
result.flags = {nimErrorFlagDisabled}
proc newModuleList*(g: ModuleGraph): BModuleList =
BModuleList(typeInfoMarker: initTable[SigHash, tuple[str: Rope, owner: int32]](),

View File

@@ -44,6 +44,8 @@ proc getDispatcher*(s: PSym): PSym =
if dispatcherPos < s.ast.len:
result = s.ast[dispatcherPos].sym
doAssert sfDispatcher in result.flags
else:
result = nil
proc methodCall*(n: PNode; conf: ConfigRef): PNode =
result = n
@@ -62,6 +64,7 @@ type
MethodResult = enum No, Invalid, Yes
proc sameMethodBucket(a, b: PSym; multiMethods: bool): MethodResult =
result = No
if a.name.id != b.name.id: return
if a.typ.len != b.typ.len:
return
@@ -113,7 +116,7 @@ proc attachDispatcher(s: PSym, dispatcher: PNode) =
s.ast[dispatcherPos] = dispatcher
proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
var disp = copySym(s, nextSymId(idgen))
var disp = copySym(s, idgen)
incl(disp.flags, sfDispatcher)
excl(disp.flags, sfExported)
let old = disp.typ
@@ -127,7 +130,7 @@ proc createDispatcher(s: PSym; g: ModuleGraph; idgen: IdGenerator): PSym =
disp.loc.r = ""
if s.typ[0] != nil:
if disp.ast.len > resultPos:
disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, nextSymId(idgen))
disp.ast[resultPos].sym = copySym(s.ast[resultPos].sym, idgen)
else:
# We've encountered a method prototype without a filled-in
# resultPos slot. We put a placeholder in there that will
@@ -149,7 +152,7 @@ proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
disp.ast[resultPos] = copyTree(meth.ast[resultPos])
proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
var witness: PSym
var witness: PSym = nil
for i in 0..<g.methods.len:
let disp = g.methods[i].dispatcher
case sameMethodBucket(disp, s, multimethods = optMultiMethods in g.config.globalOptions)
@@ -178,6 +181,7 @@ proc methodDef*(g: ModuleGraph; idgen: IdGenerator; s: PSym) =
proc relevantCol(methods: seq[PSym], col: int): bool =
# returns true iff the position is relevant
result = false
var t = methods[0].typ[col].skipTypes(skipPtrs)
if t.kind == tyObject:
for i in 1..high(methods):
@@ -186,6 +190,7 @@ proc relevantCol(methods: seq[PSym], col: int): bool =
return true
proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
result = 0
for col in 1..<a.typ.len:
if contains(relevantCols, col):
var aa = skipTypes(a.typ[col], skipPtrs)
@@ -213,7 +218,7 @@ proc sortBucket(a: var seq[PSym], relevantCols: IntSet) =
a[j] = v
if h == 1: break
proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet): PSym =
proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet; idgen: IdGenerator): PSym =
var base = methods[0].ast[dispatcherPos].sym
result = base
var paramLen = base.typ.len
@@ -272,7 +277,7 @@ proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet): PS
nilchecks.flags.incl nfTransf # should not be further transformed
result.ast[bodyPos] = nilchecks
proc generateMethodDispatchers*(g: ModuleGraph): PNode =
proc generateMethodDispatchers*(g: ModuleGraph, idgen: IdGenerator): PNode =
result = newNode(nkStmtList)
for bucket in 0..<g.methods.len:
var relevantCols = initIntSet()
@@ -282,4 +287,4 @@ proc generateMethodDispatchers*(g: ModuleGraph): PNode =
# if multi-methods are not enabled, we are interested only in the first field
break
sortBucket(g.methods[bucket].methods, relevantCols)
result.add newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols))
result.add newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols, idgen))

View File

@@ -183,7 +183,7 @@ proc newStateAssgn(ctx: var Ctx, stateNo: int = -2): PNode =
ctx.newStateAssgn(newIntTypeNode(stateNo, ctx.g.getSysType(TLineInfo(), tyInt)))
proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym =
result = newSym(skVar, getIdent(ctx.g.cache, name), nextSymId(ctx.idgen), ctx.fn, ctx.fn.info)
result = newSym(skVar, getIdent(ctx.g.cache, name), ctx.idgen, ctx.fn, ctx.fn.info)
result.typ = typ
assert(not typ.isNil)
@@ -258,8 +258,9 @@ proc hasYields(n: PNode): bool =
of nkYieldStmt:
result = true
of nkSkip:
discard
result = false
else:
result = false
for c in n:
if c.hasYields:
result = true
@@ -325,7 +326,7 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} =
var ifBranch: PNode
if c.len > 1:
var cond: PNode
var cond: PNode = nil
for i in 0..<c.len - 1:
assert(c[i].kind == nkType)
let nextCond = newTree(nkCall,
@@ -388,19 +389,22 @@ proc getFinallyNode(ctx: var Ctx, n: PNode): PNode =
proc hasYieldsInExpressions(n: PNode): bool =
case n.kind
of nkSkip:
discard
result = false
of nkStmtListExpr:
if isEmptyType(n.typ):
result = false
for c in n:
if c.hasYieldsInExpressions:
return true
else:
result = n.hasYields
of nkCast:
result = false
for i in 1..<n.len:
if n[i].hasYieldsInExpressions:
return true
else:
result = false
for c in n:
if c.hasYieldsInExpressions:
return true
@@ -495,7 +499,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
if ns:
needsSplit = true
var tmp: PSym
var tmp: PSym = nil
let isExpr = not isEmptyType(n.typ)
if isExpr:
tmp = ctx.newTempVar(n.typ)
@@ -855,7 +859,9 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
case n.kind
of nkReturnStmt:
# We're somewhere in try, transform to finally unrolling
assert(ctx.nearestFinally != 0)
if ctx.nearestFinally == 0:
# return is within the finally
return
result = newNodeI(nkStmtList, n.info)
@@ -1348,7 +1354,7 @@ proc freshVars(n: PNode; c: var FreshVarsContext): PNode =
let idefs = copyNode(it)
for v in 0..it.len-3:
if it[v].kind == nkSym:
let x = copySym(it[v].sym, nextSymId(c.idgen))
let x = copySym(it[v].sym, c.idgen)
c.tab[it[v].sym.id] = x
idefs.add newSymNode(x)
else:
@@ -1359,6 +1365,7 @@ proc freshVars(n: PNode; c: var FreshVarsContext): PNode =
else:
result.add it
of nkRaiseStmt:
result = nil
localError(c.config, c.info, "unsupported control flow: 'finally: ... raise' duplicated because of 'break'")
else:
result = n
@@ -1389,7 +1396,7 @@ proc preprocess(c: var PreprocessContext; n: PNode): PNode =
discard c.finallys.pop()
of nkWhileStmt, nkBlockStmt:
if n.hasYields == false: return n
if not n.hasYields: return n
c.blocks.add((n, c.finallys.len))
for i in 0 ..< n.len:
result[i] = preprocess(c, n[i])
@@ -1431,9 +1438,9 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
# Lambda lifting was not done yet. Use temporary :state sym, which will
# be handled specially by lambda lifting. Local temp vars (if needed)
# should follow the same logic.
ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), nextSymId(idgen), fn, fn.info)
ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), idgen, fn, fn.info)
ctx.stateVarSym.typ = g.createClosureIterStateType(fn, idgen)
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), nextSymId(idgen), fn, fn.info)
ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), idgen, fn, fn.info)
var pc = PreprocessContext(finallys: @[], config: g.config, idgen: idgen)
var n = preprocess(pc, n.toStmtList)
#echo "transformed into ", n
@@ -1466,9 +1473,10 @@ proc transformClosureIterator*(g: ModuleGraph; idgen: IdGenerator; fn: PSym, n:
result = ctx.transformStateAssignments(result)
result = ctx.wrapIntoStateLoop(result)
# echo "TRANSFORM TO STATES: "
# echo renderTree(result)
when false:
echo "TRANSFORM TO STATES: "
echo renderTree(result)
# echo "exception table:"
# for i, e in ctx.exceptionTable:
# echo i, " -> ", e
echo "exception table:"
for i, e in ctx.exceptionTable:
echo i, " -> ", e

View File

@@ -7,7 +7,7 @@
# distribution, for details about the copyright.
#
## Helpers for binaries that use compiler passes, e.g.: nim, nimsuggest, nimfix
## Helpers for binaries that use compiler passes, e.g.: nim, nimsuggest
import
options, idents, nimconf, extccomp, commands, msgs,

View File

@@ -184,7 +184,7 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
info: TLineInfo; orig: string; conf: ConfigRef) =
var id = "" # arg = key or [key] or key:val or [key]:val; with val=on|off
var i = 0
var notes: set[TMsgKind]
var notes: set[TMsgKind] = {}
var isBracket = false
if i < arg.len and arg[i] == '[':
isBracket = true
@@ -238,9 +238,9 @@ proc processCompile(conf: ConfigRef; filename: string) =
extccomp.addExternalFileToCompile(conf, found)
const
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found"
errNoneBoehmRefcExpectedButXFound = "'arc', 'orc', 'atomicArc', 'markAndSweep', 'boehm', 'go', 'none', 'regions', or 'refc' expected, but '$1' found"
errNoneSpeedOrSizeExpectedButXFound = "'none', 'speed' or 'size' expected, but '$1' found"
errGuiConsoleOrLibExpectedButXFound = "'gui', 'console' or 'lib' expected, but '$1' found"
errGuiConsoleOrLibExpectedButXFound = "'gui', 'console', 'lib' or 'staticlib' expected, but '$1' found"
errInvalidExceptionSystem = "'goto', 'setjmp', 'cpp' or 'quirky' expected, but '$1' found"
template warningOptionNoop(switch: string) =
@@ -262,13 +262,18 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
of "go": result = conf.selectedGC == gcGo
of "none": result = conf.selectedGC == gcNone
of "stack", "regions": result = conf.selectedGC == gcRegions
else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
of "atomicarc": result = conf.selectedGC == gcAtomicArc
else:
result = false
localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg)
of "opt":
case arg.normalize
of "speed": result = contains(conf.options, optOptimizeSpeed)
of "size": result = contains(conf.options, optOptimizeSize)
of "none": result = conf.options * {optOptimizeSpeed, optOptimizeSize} == {}
else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
else:
result = false
localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg)
of "verbosity": result = $conf.verbosity == arg
of "app":
case arg.normalize
@@ -278,7 +283,9 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
not contains(conf.globalOptions, optGenGuiApp)
of "staticlib": result = contains(conf.globalOptions, optGenStaticLib) and
not contains(conf.globalOptions, optGenGuiApp)
else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
else:
result = false
localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg)
of "dynliboverride":
result = isDynlibOverride(conf, arg)
of "exceptions":
@@ -287,8 +294,12 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo
of "setjmp": result = conf.exc == excSetjmp
of "quirky": result = conf.exc == excQuirky
of "goto": result = conf.exc == excGoto
else: localError(conf, info, errInvalidExceptionSystem % arg)
else: invalidCmdLineOption(conf, passCmd1, switch, info)
else:
result = false
localError(conf, info, errInvalidExceptionSystem % arg)
else:
result = false
invalidCmdLineOption(conf, passCmd1, switch, info)
proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool =
case switch.normalize
@@ -334,9 +345,14 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
if switch.normalize == "patterns": deprecatedAlias(switch, "trmacros")
result = contains(conf.options, optTrMacros)
of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace)
of "nilseqs", "nilchecks", "taintmode": warningOptionNoop(switch)
of "nilseqs", "nilchecks", "taintmode":
warningOptionNoop(switch)
result = false
of "panics": result = contains(conf.globalOptions, optPanics)
else: invalidCmdLineOption(conf, passCmd1, switch, info)
of "jsbigint64": result = contains(conf.globalOptions, optJsBigInt64)
else:
result = false
invalidCmdLineOption(conf, passCmd1, switch, info)
proc processPath(conf: ConfigRef; path: string, info: TLineInfo,
notRelativeToProj = false): AbsoluteDir =
@@ -378,7 +394,8 @@ proc makeAbsolute(s: string): AbsoluteFile =
proc setTrackingInfo(conf: ConfigRef; dirty, file, line, column: string,
info: TLineInfo) =
## set tracking info, common code for track, trackDirty, & ideTrack
var ln, col: int
var ln: int = 0
var col: int = 0
if parseUtils.parseInt(line, ln) <= 0:
localError(conf, info, errInvalidNumber % line)
if parseUtils.parseInt(column, col) <= 0:
@@ -515,14 +532,7 @@ proc initOrcDefines*(conf: ConfigRef) =
if conf.exc == excNone and conf.backend != backendCpp:
conf.exc = excGoto
proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef, isOrc: bool) =
if isOrc:
conf.selectedGC = gcOrc
defineSymbol(conf.symbols, "gcorc")
else:
conf.selectedGC = gcArc
defineSymbol(conf.symbols, "gcarc")
proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef) =
defineSymbol(conf.symbols, "gcdestructors")
incl conf.globalOptions, optSeqDestructors
incl conf.globalOptions, optTinyRtti
@@ -532,10 +542,11 @@ proc registerArcOrc(pass: TCmdLinePass, conf: ConfigRef, isOrc: bool) =
if conf.exc == excNone and conf.backend != backendCpp:
conf.exc = excGoto
proc unregisterArcOrc(conf: ConfigRef) =
proc unregisterArcOrc*(conf: ConfigRef) =
undefSymbol(conf.symbols, "gcdestructors")
undefSymbol(conf.symbols, "gcarc")
undefSymbol(conf.symbols, "gcorc")
undefSymbol(conf.symbols, "gcatomicarc")
undefSymbol(conf.symbols, "nimSeqsV2")
undefSymbol(conf.symbols, "nimV2")
excl conf.globalOptions, optSeqDestructors
@@ -561,9 +572,17 @@ proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass,
conf.selectedGC = gcMarkAndSweep
defineSymbol(conf.symbols, "gcmarkandsweep")
of "destructors", "arc":
registerArcOrc(pass, conf, false)
conf.selectedGC = gcArc
defineSymbol(conf.symbols, "gcarc")
registerArcOrc(pass, conf)
of "orc":
registerArcOrc(pass, conf, true)
conf.selectedGC = gcOrc
defineSymbol(conf.symbols, "gcorc")
registerArcOrc(pass, conf)
of "atomicarc":
conf.selectedGC = gcAtomicArc
defineSymbol(conf.symbols, "gcatomicarc")
registerArcOrc(pass, conf)
of "hooks":
conf.selectedGC = gcHooks
defineSymbol(conf.symbols, "gchooks")
@@ -587,8 +606,8 @@ proc processMemoryManagementOption(switch, arg: string, pass: TCmdLinePass,
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
conf: ConfigRef) =
var
key, val: string
var key = ""
var val = ""
case switch.normalize
of "eval":
expectArg(conf, switch, arg, pass, info)
@@ -603,17 +622,17 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
for path in nimbleSubs(conf, arg):
addPath(conf, if pass == passPP: processCfgPath(conf, path, info)
else: processPath(conf, path, info), info)
of "nimblepath", "babelpath":
if switch.normalize == "babelpath": deprecatedAlias(switch, "nimblepath")
of "nimblepath":
if pass in {passCmd2, passPP} and optNoNimblePath notin conf.globalOptions:
expectArg(conf, switch, arg, pass, info)
var path = processPath(conf, arg, info, notRelativeToProj=true)
let nimbleDir = AbsoluteDir getEnv("NIMBLE_DIR")
if not nimbleDir.isEmpty and pass == passPP:
path = nimbleDir / RelativeDir"pkgs2"
nimblePath(conf, path, info)
path = nimbleDir / RelativeDir"pkgs"
nimblePath(conf, path, info)
of "nonimblepath", "nobabelpath":
if switch.normalize == "nobabelpath": deprecatedAlias(switch, "nonimblepath")
of "nonimblepath":
expectNoArg(conf, switch, arg, pass, info)
disableNimblePath(conf)
of "clearnimblepath":
@@ -651,6 +670,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
if backend == TBackend.default: localError(conf, info, "invalid backend: '$1'" % arg)
if backend == backendJs: # bug #21209
conf.globalOptions.excl {optThreadAnalysis, optThreads}
if optRun in conf.globalOptions:
# for now, -r uses nodejs, so define nodejs
defineSymbol(conf.symbols, "nodejs")
conf.backend = backend
of "doccmd": conf.docCmd = arg
of "define", "d":
@@ -761,7 +783,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
if conf.backend == backendJs or conf.cmd == cmdNimscript: discard
else: processOnOffSwitchG(conf, {optThreads}, arg, pass, info)
#if optThreads in conf.globalOptions: conf.setNote(warnGcUnsafe)
of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info)
of "tlsemulation":
processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info)
if optTlsEmulation in conf.globalOptions:
conf.legacyFeatures.incl emitGenerics
of "implicitstatic":
processOnOffSwitch(conf, {optImplicitStatic}, arg, pass, info)
of "patterns", "trmacros":
@@ -798,6 +823,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
defineSymbol(conf.symbols, "dll")
of "staticlib":
incl(conf.globalOptions, optGenStaticLib)
incl(conf.globalOptions, optNoMain)
excl(conf.globalOptions, optGenGuiApp)
defineSymbol(conf.symbols, "library")
defineSymbol(conf.symbols, "staticlib")
@@ -821,6 +847,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "header":
if conf != nil: conf.headerFile = arg
incl(conf.globalOptions, optGenIndex)
of "nimbasepattern":
if conf != nil: conf.nimbasePattern = arg
of "index":
case arg.normalize
of "", "on": conf.globalOptions.incl {optGenIndex}
@@ -861,21 +889,28 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
setTarget(conf.target, conf.target.targetOS, cpu)
of "run", "r":
processOnOffSwitchG(conf, {optRun}, arg, pass, info)
if conf.backend == backendJs:
# for now, -r uses nodejs, so define nodejs
defineSymbol(conf.symbols, "nodejs")
of "maxloopiterationsvm":
expectArg(conf, switch, arg, pass, info)
conf.maxLoopIterationsVM = parseInt(arg)
var value: int = 10_000_000
discard parseSaturatedNatural(arg, value)
if not value > 0: localError(conf, info, "maxLoopIterationsVM must be a positive integer greater than zero")
conf.maxLoopIterationsVM = value
of "errormax":
expectArg(conf, switch, arg, pass, info)
# Note: `nim check` (etc) can overwrite this.
# `0` is meaningless, give it a useful meaning as in clang's -ferror-limit
# If user doesn't set this flag and the code doesn't either, it'd
# have the same effect as errorMax = 1
let ret = parseInt(arg)
conf.errorMax = if ret == 0: high(int) else: ret
var value: int = 0
discard parseSaturatedNatural(arg, value)
conf.errorMax = if value == 0: high(int) else: value
of "verbosity":
expectArg(conf, switch, arg, pass, info)
let verbosity = parseInt(arg)
if verbosity notin {0..3}:
if verbosity notin 0..3:
localError(conf, info, "invalid verbosity level: '$1'" % arg)
conf.verbosity = verbosity
var verb = NotesVerbosity[conf.verbosity]
@@ -885,7 +920,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
conf.mainPackageNotes = conf.notes
of "parallelbuild":
expectArg(conf, switch, arg, pass, info)
conf.numberOfProcessors = parseInt(arg)
var value: int = 0
discard parseSaturatedNatural(arg, value)
conf.numberOfProcessors = value
of "version", "v":
expectNoArg(conf, switch, arg, pass, info)
writeVersionInfo(conf, pass)
@@ -1065,29 +1102,6 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
of "expandarc":
expectArg(conf, switch, arg, pass, info)
conf.arcToExpand[arg] = "T"
of "useversion":
expectArg(conf, switch, arg, pass, info)
case arg
of "1.0":
defineSymbol(conf.symbols, "NimMajor", "1")
defineSymbol(conf.symbols, "NimMinor", "0")
# old behaviors go here:
defineSymbol(conf.symbols, "nimOldRelativePathBehavior")
undefSymbol(conf.symbols, "nimDoesntTrackDefects")
ast.eqTypeFlags.excl {tfGcSafe, tfNoSideEffect}
conf.globalOptions.incl optNimV1Emulation
of "1.2":
defineSymbol(conf.symbols, "NimMajor", "1")
defineSymbol(conf.symbols, "NimMinor", "2")
conf.globalOptions.incl optNimV12Emulation
of "1.6":
defineSymbol(conf.symbols, "NimMajor", "1")
defineSymbol(conf.symbols, "NimMinor", "6")
conf.globalOptions.incl optNimV16Emulation
else:
localError(conf, info, "unknown Nim version; currently supported values are: `1.0`, `1.2`")
# always be compatible with 1.x.100:
defineSymbol(conf.symbols, "NimPatch", "100")
of "benchmarkvm":
processOnOffSwitchG(conf, {optBenchmarkVM}, arg, pass, info)
of "profilevm":
@@ -1101,6 +1115,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
processOnOffSwitchG(conf, {optPanics}, arg, pass, info)
if optPanics in conf.globalOptions:
defineSymbol(conf.symbols, "nimPanics")
of "jsbigint64":
processOnOffSwitchG(conf, {optJsBigInt64}, arg, pass, info)
of "sourcemap": # xxx document in --fullhelp
conf.globalOptions.incl optSourcemap
conf.options.incl optLineDir
@@ -1115,7 +1131,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
else: invalidCmdLineOption(conf, pass, switch, info)
proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) =
var cmd, arg: string
var cmd = ""
var arg = ""
splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo)
processSwitch(cmd, arg, pass, gCmdLineInfo, config)
@@ -1142,7 +1159,10 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
config.projectName = unixToNativePath(p.key)
config.arguments = cmdLineRest(p)
result = true
elif pass != passCmd2: setCommandEarly(config, p.key)
elif pass != passCmd2:
setCommandEarly(config, p.key)
result = false
else: result = false
else:
if pass == passCmd1: config.commandArgs.add p.key
if argsCount == 1:
@@ -1153,4 +1173,6 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
config.projectName = unixToNativePath(p.key)
config.arguments = cmdLineRest(p)
result = true
else:
result = false
inc argsCount

28
compiler/compiler.nimble Normal file
View File

@@ -0,0 +1,28 @@
include "../lib/system/compilation.nim"
version = $NimMajor & "." & $NimMinor & "." & $NimPatch
author = "Andreas Rumpf"
description = "Compiler package providing the compiler sources as a library."
license = "MIT"
skipDirs = @["."]
installDirs = @["compiler"]
import os
var compilerDir = ""
before install:
rmDir("compiler")
let
files = listFiles(".")
dirs = listDirs(".")
mkDir("compiler")
for f in files:
cpFile(f, "compiler" / f)
for d in dirs:
cpDir(d, "compiler" / d)
requires "nim"

View File

@@ -13,8 +13,6 @@
import ast, astalgo, semdata, lookups, lineinfos, idents, msgs, renderer, types, intsets
from magicsys import addSonSkipIntLit
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -27,24 +25,12 @@ const
proc declareSelf(c: PContext; info: TLineInfo) =
## Adds the magical 'Self' symbols to the current scope.
let ow = getCurrOwner(c)
let s = newSym(skType, getIdent(c.cache, "Self"), nextSymId(c.idgen), ow, info)
let s = newSym(skType, getIdent(c.cache, "Self"), c.idgen, ow, info)
s.typ = newType(tyTypeDesc, nextTypeId(c.idgen), ow)
s.typ.flags.incl {tfUnresolved, tfPacked}
s.typ.add newType(tyEmpty, nextTypeId(c.idgen), ow)
addDecl(c, s, info)
proc isSelf*(t: PType): bool {.inline.} =
## Is this the magical 'Self' type?
t.kind == tyTypeDesc and tfPacked in t.flags
proc makeTypeDesc*(c: PContext, typ: PType): PType =
if typ.kind == tyTypeDesc and not isSelf(typ):
result = typ
else:
result = newTypeS(tyTypeDesc, c)
incl result.flags, tfCheckedForDestructor
result.addSonSkipIntLit(typ, c.idgen)
proc semConceptDecl(c: PContext; n: PNode): PNode =
## Recursive helper for semantic checking for the concept declaration.
## Currently we only support (possibly empty) lists of statements
@@ -62,7 +48,7 @@ proc semConceptDecl(c: PContext; n: PNode): PNode =
result[i] = n[i]
result[^1] = semConceptDecl(c, n[^1])
of nkCommentStmt:
discard
result = n
else:
localError(c.config, n.info, "unexpected construct in the new-styled concept: " & renderTree(n))
result = n
@@ -121,8 +107,11 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
for i in 0..<a.len:
if not matchType(c, f[i], a[i], m): return false
return true
else:
result = false
of tyGenericInvocation:
result = false
if a.kind == tyGenericInst and a[0].kind == tyGenericBody:
if sameType(f[0], a[0]) and f.len == a.len-1:
for i in 1 ..< f.len:
@@ -156,15 +145,17 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
result = matchType(c, old, ak, m)
if m.magic == mArrPut and ak.kind == tyGenericParam:
result = true
else:
result = false
#echo "B for ", result, " to ", typeToString(a), " to ", typeToString(m.potentialImplementation)
of tyVar, tySink, tyLent, tyOwned:
# modifiers in the concept must be there in the actual implementation
# too but not vice versa.
if a.kind == f.kind:
result = matchType(c, f.sons[0], a.sons[0], m)
result = matchType(c, f[0], a[0], m)
elif m.magic == mArrPut:
result = matchType(c, f.sons[0], a, m)
result = matchType(c, f[0], a, m)
else:
result = false
of tyEnum, tyObject, tyDistinct:
@@ -185,6 +176,7 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
m.inferred.setLen oldLen
of tyArray, tyTuple, tyVarargs, tyOpenArray, tyRange, tySequence, tyRef, tyPtr,
tyGenericInst:
result = false
let ak = a.skipTypes(ignorableForArgType - {f.kind})
if ak.kind == f.kind and f.len == ak.len:
for i in 0..<ak.len:
@@ -209,6 +201,7 @@ proc matchType(c: PContext; f, a: PType; m: var MatchCon): bool =
if not result:
m.inferred.setLen oldLen
else:
result = false
for i in 0..<f.len:
result = matchType(c, f[i], a, m)
if result: break # and remember the binding!
@@ -257,7 +250,7 @@ proc matchSym(c: PContext; candidate: PSym, n: PNode; m: var MatchCon): bool =
m.inferred.setLen oldLen
return false
if not matchReturnType(c, n[0].sym.typ.sons[0], candidate.typ.sons[0], m):
if not matchReturnType(c, n[0].sym.typ[0], candidate.typ[0], m):
m.inferred.setLen oldLen
return false
@@ -306,6 +299,8 @@ proc conceptMatchNode(c: PContext; n: PNode; m: var MatchCon): bool =
result = matchSyms(c, n, {skMethod}, m)
of nkIteratorDef:
result = matchSyms(c, n, {skIterator}, m)
of nkCommentStmt:
result = true
else:
# error was reported earlier.
result = false

View File

@@ -45,10 +45,8 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimNewTypedesc") # deadcode
defineSymbol("nimrequiresnimframe") # deadcode
defineSymbol("nimparsebiggestfloatmagic") # deadcode
defineSymbol("nimalias") # deadcode
defineSymbol("nimlocks") # deadcode
defineSymbol("nimnode") # deadcode pending `nimnode` reference in opengl package
# refs https://github.com/nim-lang/opengl/pull/79
defineSymbol("nimnode") # deadcode
defineSymbol("nimvarargstyped") # deadcode
defineSymbol("nimtypedescfixed") # deadcode
defineSymbol("nimKnowsNimvm") # deadcode
@@ -147,10 +145,19 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasCallsitePragma")
defineSymbol("nimHasAmbiguousEnumHint")
defineSymbol("nimHasWarnCastSizes")
defineSymbol("nimHasWarnCastSizes") # deadcode
defineSymbol("nimHasOutParams")
defineSymbol("nimHasSystemRaisesDefect")
defineSymbol("nimHasWarnUnnamedBreak")
defineSymbol("nimHasGenericDefine")
defineSymbol("nimHasDefineAliases")
defineSymbol("nimHasWarnBareExcept")
defineSymbol("nimHasDup")
defineSymbol("nimHasChecksums")
defineSymbol("nimHasSendable")
defineSymbol("nimAllowNonVarDestructor")
defineSymbol("nimHasQuirky")
defineSymbol("nimHasEnsureMove")
defineSymbol("nimUseStrictDefs")
defineSymbol("nimHasNolineTooLong")

View File

@@ -42,7 +42,7 @@ proc toNimblePath(s: string, isStdlib: bool): string =
let sub = "lib/"
var start = s.find(sub)
if start < 0:
doAssert false
raiseAssert "unreachable"
else:
start += sub.len
let base = s[start..^1]
@@ -63,12 +63,16 @@ proc toNimblePath(s: string, isStdlib: bool): string =
sub.add "/pkgs/"
var start = s.find(sub)
if start < 0:
result = s
else:
start += sub.len
start += skipUntil(s, '/', start)
start += 1
result = pkgPrefix & s[start..^1]
sub[^1] = '2'
sub.add '/'
start = s.find(sub) # /pkgs2
if start < 0:
return s
start += sub.len
start += skipUntil(s, '/', start)
start += 1
result = pkgPrefix & s[start..^1]
proc addDependency(c: PPassContext, g: PGen, b: Backend, n: PNode) =
doAssert n.kind == nkSym, $n.kind
@@ -101,11 +105,6 @@ proc generateDot*(graph: ModuleGraph; project: AbsoluteFile) =
changeFileExt(project, "dot"))
proc setupDependPass*(graph: ModuleGraph; module: PSym; idgen: IdGenerator): PPassContext =
var g: PGen
new(g)
g.module = module
g.config = graph.config
g.graph = graph
result = PGen(module: module, config: graph.config, graph: graph)
if graph.backend == nil:
graph.backend = Backend(dotGraph: "")
result = g

View File

@@ -60,6 +60,7 @@ type
proc codeListing(c: ControlFlowGraph, start = 0; last = -1): string =
# for debugging purposes
# first iteration: compute all necessary labels:
result = ""
var jumpTargets = initIntSet()
let last = if last < 0: c.len-1 else: min(last, c.len-1)
for i in start..last:
@@ -111,7 +112,7 @@ proc patch(c: var Con, p: TPosition) =
proc gen(c: var Con; n: PNode)
proc popBlock(c: var Con; oldLen: int) =
var exits: seq[TPosition]
var exits: seq[TPosition] = @[]
exits.add c.gotoI()
for f in c.blocks[oldLen].breakFixups:
c.patch(f[0])
@@ -128,10 +129,6 @@ template withBlock(labl: PSym; body: untyped) =
body
popBlock(c, oldLen)
proc isTrue(n: PNode): bool =
n.kind == nkSym and n.sym.kind == skEnumField and n.sym.position != 0 or
n.kind == nkIntLit and n.intVal != 0
template forkT(body) =
let lab1 = c.forkI()
body
@@ -263,8 +260,9 @@ proc genBreakOrRaiseAux(c: var Con, i: int, n: PNode) =
if c.blocks[i].isTryBlock:
c.blocks[i].raiseFixups.add lab1
else:
var trailingFinales: seq[PNode]
if c.inTryStmt > 0: #Ok, we are in a try, lets see which (if any) try's we break out from:
var trailingFinales: seq[PNode] = @[]
if c.inTryStmt > 0:
# Ok, we are in a try, lets see which (if any) try's we break out from:
for b in countdown(c.blocks.high, i):
if c.blocks[b].isTryBlock:
trailingFinales.add c.blocks[b].finale
@@ -385,7 +383,8 @@ proc genCall(c: var Con; n: PNode) =
# Pass by 'out' is a 'must def'. Good enough for a move optimizer.
genDef(c, n[i])
# every call can potentially raise:
if false: # c.inTryStmt > 0 and canRaiseConservative(n[0]):
if c.inTryStmt > 0 and canRaiseConservative(n[0]):
inc c.interestingInstructions
# we generate the instruction sequence:
# fork lab1
# goto exceptionHandler (except or finally)
@@ -467,7 +466,7 @@ proc gen(c: var Con; n: PNode) =
of nkConv, nkExprColonExpr, nkExprEqExpr, nkCast, PathKinds1:
gen(c, n[1])
of nkVarSection, nkLetSection: genVarSection(c, n)
of nkDefer: doAssert false, "dfa construction pass requires the elimination of 'defer'"
of nkDefer: raiseAssert "dfa construction pass requires the elimination of 'defer'"
else: discard
when false:
@@ -493,7 +492,7 @@ proc constructCfg*(s: PSym; body: PNode; root: PSym): ControlFlowGraph =
gen(c, body)
if root.kind == skResult:
genImplicitReturn(c)
when defined(gcArc) or defined(gcOrc):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
result = c.code # will move
else:
shallowCopy(result, c.code)

View File

@@ -112,13 +112,16 @@ type
proc add(dest: var ItemPre, rst: PRstNode) = dest.add ItemFragment(isRst: true, rst: rst)
proc add(dest: var ItemPre, str: string) = dest.add ItemFragment(isRst: false, str: str)
proc addRstFileIndex(d: PDoc, info: lineinfos.TLineInfo): rstast.FileIndex =
proc addRstFileIndex(d: PDoc, fileIndex: lineinfos.FileIndex): rstast.FileIndex =
let invalid = rstast.FileIndex(-1)
result = d.nimToRstFid.getOrDefault(info.fileIndex, default = invalid)
result = d.nimToRstFid.getOrDefault(fileIndex, default = invalid)
if result == invalid:
let fname = toFullPath(d.conf, info)
let fname = toFullPath(d.conf, fileIndex)
result = addFilename(d.sharedState, fname)
d.nimToRstFid[info.fileIndex] = result
d.nimToRstFid[fileIndex] = result
proc addRstFileIndex(d: PDoc, info: lineinfos.TLineInfo): rstast.FileIndex =
addRstFileIndex(d, info.fileIndex)
proc cmpDecimalsIgnoreCase(a, b: string): int =
## For sorting with correct handling of cases like 'uint8' and 'uint16'.
@@ -167,6 +170,7 @@ proc cmpDecimalsIgnoreCase(a, b: string): int =
proc prettyString(a: object): string =
# xxx pending std/prettyprint refs https://github.com/nim-lang/RFCs/issues/203#issuecomment-602534906
result = ""
for k, v in fieldPairs(a):
result.add k & ": " & $v & "\n"
@@ -212,12 +216,16 @@ proc whichType(d: PDoc; n: PNode): PSym =
if n.kind == nkSym:
if d.types.strTableContains(n.sym):
result = n.sym
else:
result = nil
else:
result = nil
for i in 0..<n.safeLen:
let x = whichType(d, n[i])
if x != nil: return x
proc attachToType(d: PDoc; p: PSym): PSym =
result = nil
let params = p.ast[paramsPos]
template check(i) =
result = whichType(d, params[i])
@@ -256,7 +264,16 @@ template declareClosures(currentFilename: AbsoluteFile, destFile: string) =
of mwUnusedImportdoc: k = warnRstUnusedImportdoc
of mwRstStyle: k = warnRstStyle
{.gcsafe.}:
globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg)
let errorsAsWarnings = (roPreferMarkdown in d.sharedState.options) and
not d.standaloneDoc # not tolerate errors in .rst/.md files
if whichMsgClass(msgKind) == mcError and errorsAsWarnings:
liMessage(conf, newLineInfo(conf, AbsoluteFile filename, line, col),
k, arg, doNothing, instLoc(), ignoreError=true)
# when our Markdown parser fails, we currently can only terminate the
# parsing (and then we will return monospaced text instead of markup):
raiseRecoverableError("")
else:
globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg)
proc docgenFindFile(s: string): string {.gcsafe.} =
result = options.findFile(conf, s).string
@@ -308,8 +325,9 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
standaloneDoc = false, preferMarkdown = true,
hasToc = true): PDoc =
let destFile = getOutFile2(conf, presentationPath(conf, filename), outExt, false).string
declareClosures(currentFilename = filename, destFile = destFile)
new(result)
let d = result # pass `d` to `declareClosures`:
declareClosures(currentFilename = filename, destFile = destFile)
result.module = module
result.conf = conf
result.cache = cache
@@ -330,7 +348,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
if conf.configVars.hasKey("doc.googleAnalytics") and
conf.configVars.hasKey("doc.plausibleAnalytics"):
doAssert false, "Either use googleAnalytics or plausibleAnalytics"
raiseAssert "Either use googleAnalytics or plausibleAnalytics"
if conf.configVars.hasKey("doc.googleAnalytics"):
result.analytics = """
@@ -355,7 +373,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
result.seenSymbols = newStringTable(modeCaseInsensitive)
result.id = 100
result.jEntriesFinal = newJArray()
initStrTable result.types
result.types = initStrTable()
result.onTestSnippet =
proc (gen: var RstGenerator; filename, cmd: string; status: int; content: string) {.gcsafe.} =
if conf.docCmd == docCmdSkip: return
@@ -415,16 +433,21 @@ proc getVarIdx(varnames: openArray[string], id: string): int =
proc genComment(d: PDoc, n: PNode): PRstNode =
if n.comment.len > 0:
d.sharedState.currFileIdx = addRstFileIndex(d, n.info)
result = parseRst(n.comment,
toLinenumber(n.info),
toColumn(n.info) + DocColOffset,
d.conf, d.sharedState)
try:
result = parseRst(n.comment,
toLinenumber(n.info),
toColumn(n.info) + DocColOffset,
d.conf, d.sharedState)
except ERecoverableError:
result = newRstNode(rnLiteralBlock, @[newRstLeaf(n.comment)])
else:
result = nil
proc genRecCommentAux(d: PDoc, n: PNode): PRstNode =
if n == nil: return nil
result = genComment(d, n)
if result == nil:
if n.kind in {nkStmtList, nkStmtListExpr, nkTypeDef, nkConstDef,
if n.kind in {nkStmtList, nkStmtListExpr, nkTypeDef, nkConstDef, nkTypeClassTy,
nkObjectTy, nkRefTy, nkPtrTy, nkAsgn, nkFastAsgn, nkSinkAsgn, nkHiddenStdConv}:
# notin {nkEmpty..nkNilLit, nkEnumTy, nkTupleTy}:
for i in 0..<n.len:
@@ -453,6 +476,7 @@ proc getPlainDocstring(n: PNode): string =
elif startsWith(n.comment, "##"):
result = n.comment
else:
result = ""
for i in 0..<n.safeLen:
result = getPlainDocstring(n[i])
if result.len > 0: return
@@ -468,9 +492,8 @@ proc externalDep(d: PDoc; module: PSym): string =
proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var string;
renderFlags: TRenderFlags = {};
procLink: string) =
var r: TSrcGen
var r: TSrcGen = initTokRender(n, renderFlags)
var literal = ""
initTokRender(r, n, renderFlags)
var kind = tkEof
var tokenPos = 0
var procTokenPos = 0
@@ -562,10 +585,13 @@ proc runAllExamples(d: PDoc) =
# most useful semantics is that `docCmd` comes after `rdoccmd`, so that we can (temporarily) override
# via command line
# D20210224T221756:here
let cmd = "$nim $backend -r --lib:$libpath --warning:UnusedImport:off --path:$path --nimcache:$nimcache $rdoccmd $docCmd $file" % [
var pathArgs = "--path:$path" % [ "path", quoteShell(d.conf.projectPath) ]
for p in d.conf.searchPaths:
pathArgs = "$args --path:$path" % [ "args", pathArgs, "path", quoteShell(p) ]
let cmd = "$nim $backend -r --lib:$libpath --warning:UnusedImport:off $pathArgs --nimcache:$nimcache $rdoccmd $docCmd $file" % [
"nim", quoteShell(os.getAppFilename()),
"backend", $d.conf.backend,
"path", quoteShell(d.conf.projectPath),
"pathArgs", pathArgs,
"libpath", quoteShell(d.conf.libpath),
"nimcache", quoteShell(outputDir),
"file", quoteShell(outp),
@@ -581,7 +607,9 @@ proc runAllExamples(d: PDoc) =
rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string])
# removeFile(outp.changeFileExt(ExeExt)) # it's in nimcache, no need to remove
proc quoted(a: string): string = result.addQuoted(a)
proc quoted(a: string): string =
result = ""
result.addQuoted(a)
proc toInstantiationInfo(conf: ConfigRef, info: TLineInfo): (string, int, int) =
# xxx expose in compiler/lineinfos.nim
@@ -600,7 +628,6 @@ proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, c
let useRenderModule = false
let loc = d.conf.toFileLineCol(n.info)
let code = extractRunnableExamplesSource(d.conf, n)
let codeIndent = extractRunnableExamplesSource(d.conf, n, indent = 2)
if d.conf.errorCounter > 0:
return (rdoccmd, code)
@@ -616,6 +643,7 @@ proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, c
docComment.comment = comment
var runnableExamples = newTree(nkStmtList,
docComment,
newTree(nkImportStmt, newStrNode(nkStrLit, "std/assertions")),
newTree(nkImportStmt, newStrNode(nkStrLit, d.filename)))
runnableExamples.info = n.info
for a in n.lastSon: runnableExamples.add a
@@ -629,6 +657,7 @@ proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, c
else:
var code2 = code
if code.len > 0 and "codeReordering" notin code:
let codeIndent = extractRunnableExamplesSource(d.conf, n, indent = 2)
# hacky but simplest solution, until we devise a way to make `{.line.}`
# work without introducing a scope
code2 = """
@@ -639,6 +668,7 @@ $#
#[
$#
]#
import std/assertions
import $#
$#
""" % [comment, d.filename.quoted, code2]
@@ -705,7 +735,7 @@ proc getAllRunnableExamplesImpl(d: PDoc; n: PNode, dest: var ItemPre,
let (rdoccmd, code) = prepareExample(d, n, topLevel)
var msg = "Example:"
if rdoccmd.len > 0: msg.add " cmd: " & rdoccmd
var s: string
var s: string = ""
dispA(d.conf, s, "\n<p><strong class=\"examples_text\">$1</strong></p>\n",
"\n\n\\textbf{$1}\n", [msg])
dest.add s
@@ -921,14 +951,17 @@ proc genDeprecationMsg(d: PDoc, n: PNode): string =
if n[1].kind in {nkStrLit..nkTripleStrLit}:
result = getConfigVar(d.conf, "doc.deprecationmsg") % [
"label", "Deprecated:", "message", xmltree.escape(n[1].strVal)]
else:
result = ""
else:
doAssert false
raiseAssert "unreachable"
type DocFlags = enum
kDefault
kForceExport
proc genSeeSrc(d: PDoc, path: string, line: int): string =
result = ""
let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc")
if docItemSeeSrc.len > 0:
let path = relativeTo(AbsoluteFile path, AbsoluteDir getCurrentDir(), '/')
@@ -970,7 +1003,7 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
result.symKind = k.toHumanStr
if k in routineKinds:
var
paramTypes: seq[string]
paramTypes: seq[string] = @[]
renderParamTypes(paramTypes, n[paramsPos], toNormalize=true)
let paramNames = renderParamNames(n[paramsPos], toNormalize=true)
# In some rare cases (system.typeof) parameter type is not set for default:
@@ -995,8 +1028,7 @@ proc toLangSymbol(k: TSymKind, n: PNode, baseName: string): LangSymbol =
genNode = n[miscPos][1] # FIXME: what is index 1?
if genNode != nil:
var literal = ""
var r: TSrcGen
initTokRender(r, genNode, {renderNoBody, renderNoComments,
var r: TSrcGen = initTokRender(genNode, {renderNoBody, renderNoComments,
renderNoPragmas, renderNoProcDefs, renderExpandUsing})
var kind = tkEof
while true:
@@ -1017,15 +1049,14 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
var result = ""
var literal, plainName = ""
var kind = tkEof
var comm: ItemPre
var comm: ItemPre = default(ItemPre)
if n.kind in routineDefs:
getAllRunnableExamples(d, n, comm)
else:
comm.add genRecComment(d, n)
var r: TSrcGen
# Obtain the plain rendered string for hyperlink titles.
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments,
var r: TSrcGen = initTokRender(n, {renderNoBody, renderNoComments, renderDocComments,
renderNoPragmas, renderNoProcDefs, renderExpandUsing})
while true:
getNextTok(r, kind, literal)
@@ -1060,7 +1091,8 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
fileIndex: addRstFileIndex(d, nameNode.info))
addAnchorNim(d.sharedState, external = false, refn = symbolOrId,
tooltip = detailedName, langSym = rstLangSymbol,
priority = symbolPriority(k), info = lineinfo)
priority = symbolPriority(k), info = lineinfo,
module = addRstFileIndex(d, FileIndex d.module.position))
let renderFlags =
if nonExports: {renderNoBody, renderNoComments, renderDocComments, renderSyms,
@@ -1123,13 +1155,16 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonEx
if k == skType and nameNode.kind == nkSym:
d.types.strTableAdd nameNode.sym
proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonItem =
proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind, nonExports = false): JsonItem =
if not isVisible(d, nameNode): return
var
name = getNameEsc(d, nameNode)
comm = genRecComment(d, n)
r: TSrcGen
initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing})
renderFlags = {renderNoBody, renderNoComments, renderDocComments, renderExpandUsing}
if nonExports:
renderFlags.incl renderNonExportedFields
r = initTokRender(n, renderFlags)
result.json = %{ "name": %name, "type": %($k), "line": %n.info.line.int,
"col": %n.info.col}
if comm != nil:
@@ -1161,9 +1196,9 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonItem =
result.json["signature"]["genericParams"] = newJArray()
for genericParam in n[genericParamsPos]:
var param = %{"name": %($genericParam)}
if genericParam.sym.typ.sons.len > 0:
if genericParam.sym.typ.len > 0:
param["types"] = newJArray()
for kind in genericParam.sym.typ.sons:
for kind in genericParam.sym.typ:
param["types"].add %($kind)
result.json["signature"]["genericParams"].add param
if optGenIndex in d.conf.globalOptions:
@@ -1258,6 +1293,8 @@ proc documentNewEffect(cache: IdentCache; n: PNode): PNode =
let s = n[namePos].sym
if tfReturnsNew in s.typ.flags:
result = newIdentNode(getIdent(cache, "new"), n.info)
else:
result = nil
proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, idx: int): PNode =
let spec = effectSpec(x, effectType)
@@ -1280,6 +1317,8 @@ proc documentEffect(cache: IdentCache; n, x: PNode, effectType: TSpecialWord, id
result = newTreeI(nkExprColonExpr, n.info,
newIdentNode(getIdent(cache, $effectType), n.info), effects)
else:
result = nil
proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName: string): PNode =
let s = n[namePos].sym
@@ -1293,6 +1332,8 @@ proc documentWriteEffect(cache: IdentCache; n: PNode; flag: TSymFlag; pragmaName
if effects.len > 0:
result = newTreeI(nkExprColonExpr, n.info,
newIdentNode(getIdent(cache, pragmaName), n.info), effects)
else:
result = nil
proc documentRaises*(cache: IdentCache; n: PNode) =
if n[namePos].kind != nkSym: return
@@ -1366,7 +1407,7 @@ proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags
of nkExportExceptStmt: discard "transformed into nkExportStmt by semExportExcept"
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n[0])
of nkCallKinds:
var comm: ItemPre
var comm: ItemPre = default(ItemPre)
getAllRunnableExamples(d, n, comm)
if comm.len != 0: d.modDescPre.add(comm)
else: discard
@@ -1451,7 +1492,8 @@ proc finishGenerateDoc*(d: var PDoc) =
isGroup: true),
priority = symbolPriority(k),
# select index `0` just to have any meaningful warning:
info = overloadChoices[0].info)
info = overloadChoices[0].info,
module = addRstFileIndex(d, FileIndex d.module.position))
if optGenIndexOnly in d.conf.globalOptions:
return
@@ -1474,7 +1516,7 @@ proc finishGenerateDoc*(d: var PDoc) =
overloadChoices.sort(cmp)
var nameContent = ""
for item in overloadChoices:
var itemDesc: string
var itemDesc: string = ""
renderItemPre(d, item.descRst, itemDesc)
nameContent.add(
getConfigVar(d.conf, "doc.item") % (
@@ -1500,7 +1542,7 @@ proc finishGenerateDoc*(d: var PDoc) =
for i, entry in d.jEntriesPre:
if entry.rst != nil:
let resolved = resolveSubs(d.sharedState, entry.rst)
var str: string
var str: string = ""
renderRstToOut(d[], resolved, str)
entry.json[entry.rstField] = %str
d.jEntriesPre[i].rst = nil
@@ -1513,7 +1555,7 @@ proc finishGenerateDoc*(d: var PDoc) =
proc add(d: PDoc; j: JsonItem) =
if j.json != nil or j.rst != nil: d.jEntriesPre.add j
proc generateJson*(d: PDoc, n: PNode, includeComments: bool = true) =
proc generateJson*(d: PDoc, n: PNode, config: ConfigRef, includeComments: bool = true) =
case n.kind
of nkPragma:
let doctypeNode = findPragma(n, wDoctype)
@@ -1545,14 +1587,14 @@ proc generateJson*(d: PDoc, n: PNode, includeComments: bool = true) =
if n[i].kind != nkCommentStmt:
# order is always 'type var let const':
d.add genJsonItem(d, n[i], n[i][0],
succ(skType, ord(n.kind)-ord(nkTypeSection)))
succ(skType, ord(n.kind)-ord(nkTypeSection)), optShowNonExportedFields in config.globalOptions)
of nkStmtList:
for i in 0..<n.len:
generateJson(d, n[i], includeComments)
generateJson(d, n[i], config, includeComments)
of nkWhenStmt:
# generate documentation for the first branch only:
if not checkForFalse(n[0][0]):
generateJson(d, lastSon(n[0]), includeComments)
generateJson(d, lastSon(n[0]), config, includeComments)
else: discard
proc genTagsItem(d: PDoc, n, nameNode: PNode, k: TSymKind): string =
@@ -1615,7 +1657,7 @@ proc genSection(d: PDoc, kind: TSymKind, groupedToc = false) =
for plainName in overloadableNames.sorted(cmpDecimalsIgnoreCase):
var overloadChoices = d.tocTable[kind][plainName]
overloadChoices.sort(cmp)
var content: string
var content: string = ""
for item in overloadChoices:
content.add item.content
d.toc2[kind].add getConfigVar(d.conf, "doc.section.toc2") % [
@@ -1646,7 +1688,7 @@ proc relLink(outDir: AbsoluteDir, destFile: AbsoluteFile, linkto: RelativeFile):
proc genOutFile(d: PDoc, groupedToc = false): string =
var
code, content: string
code, content: string = ""
title = ""
var j = 0
var toc = ""
@@ -1697,7 +1739,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
@@ -1755,7 +1797,7 @@ proc writeOutput*(d: PDoc, useWarning = false, groupedToc = false) =
proc writeOutputJson*(d: PDoc, useWarning = false) =
runAllExamples(d)
var modDesc: string
var modDesc: string = ""
for desc in d.modDescFinal:
modDesc &= desc
let content = %*{"orig": d.filename,
@@ -1767,7 +1809,7 @@ proc writeOutputJson*(d: PDoc, useWarning = false) =
else:
let dir = d.destFile.splitFile.dir
createDir(dir)
var f: File
var f: File = default(File)
if open(f, d.destFile, fmWrite):
write(f, $content)
close(f)
@@ -1801,13 +1843,16 @@ proc commandRstAux(cache: IdentCache, conf: ConfigRef;
var filen = addFileExt(filename, "txt")
var d = newDocumentor(filen, cache, conf, outExt, standaloneDoc = true,
preferMarkdown = preferMarkdown, hasToc = false)
let rst = parseRst(readFile(filen.string),
line=LineRstInit, column=ColRstInit,
conf, d.sharedState)
d.modDescPre = @[ItemFragment(isRst: true, rst: rst)]
finishGenerateDoc(d)
writeOutput(d)
generateIndex(d)
try:
let rst = parseRst(readFile(filen.string),
line=LineRstInit, column=ColRstInit,
conf, d.sharedState)
d.modDescPre = @[ItemFragment(isRst: true, rst: rst)]
finishGenerateDoc(d)
writeOutput(d)
generateIndex(d)
except ERecoverableError:
discard "already reported the error"
proc commandRst2Html*(cache: IdentCache, conf: ConfigRef,
preferMarkdown=false) =
@@ -1826,7 +1871,7 @@ proc commandJson*(cache: IdentCache, conf: ConfigRef) =
status: int; content: string) {.gcsafe.} =
localError(conf, newLineInfo(conf, AbsoluteFile d.filename, -1, -1),
warnUser, "the ':test:' attribute is not supported by this backend")
generateJson(d, ast)
generateJson(d, ast, conf)
finishGenerateDoc(d)
let json = d.jEntriesFinal
let content = pretty(json)
@@ -1878,7 +1923,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

@@ -39,10 +39,12 @@ template closeImpl(body: untyped) {.dirty.} =
discard
proc closeDoc*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
result = nil
closeImpl:
writeOutput(g.doc, useWarning, groupedToc)
proc closeJson*(graph: ModuleGraph; p: PPassContext, n: PNode): PNode =
result = nil
closeImpl:
writeOutputJson(g.doc, useWarning)
@@ -56,7 +58,7 @@ proc processNodeJson*(c: PPassContext, n: PNode): PNode =
result = n
var g = PGen(c)
if shouldProcess(g):
generateJson(g.doc, n, false)
generateJson(g.doc, n, g.config, false)
template myOpenImpl(ext: untyped) {.dirty.} =
var g: PGen

View File

@@ -6,12 +6,12 @@ when defined(nimPreviewSlimSystem):
proc genEnumToStrProc*(t: PType; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym =
result = newSym(skProc, getIdent(g.cache, "$"), nextSymId idgen, t.owner, info)
result = newSym(skProc, getIdent(g.cache, "$"), idgen, t.owner, info)
let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info)
let dest = newSym(skParam, getIdent(g.cache, "e"), idgen, result, info)
dest.typ = t
let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info)
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
res.typ = getSysType(g, info, tyString)
result.typ = newType(tyProc, nextTypeId idgen, t.owner)
@@ -56,6 +56,7 @@ proc searchObjCaseImpl(obj: PNode; field: PSym): PNode =
if obj.kind == nkRecCase and obj[0].kind == nkSym and obj[0].sym == field:
result = obj
else:
result = nil
for x in obj:
result = searchObjCaseImpl(x, field)
if result != nil: break
@@ -67,12 +68,12 @@ proc searchObjCase(t: PType; field: PSym): PNode =
doAssert result != nil
proc genCaseObjDiscMapping*(t: PType; field: PSym; info: TLineInfo; g: ModuleGraph; idgen: IdGenerator): PSym =
result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), nextSymId idgen, t.owner, info)
result = newSym(skProc, getIdent(g.cache, "objDiscMapping"), idgen, t.owner, info)
let dest = newSym(skParam, getIdent(g.cache, "e"), nextSymId idgen, result, info)
let dest = newSym(skParam, getIdent(g.cache, "e"), idgen, result, info)
dest.typ = field.typ
let res = newSym(skResult, getIdent(g.cache, "result"), nextSymId idgen, result, info)
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
res.typ = getSysType(g, info, tyUInt8)
result.typ = newType(tyProc, nextTypeId idgen, t.owner)

View File

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

View File

@@ -10,7 +10,7 @@
## Template evaluation engine. Now hygienic.
import
strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents
strutils, options, ast, astalgo, msgs, renderer, lineinfos, idents, trees
type
TemplCtx = object
@@ -49,7 +49,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
internalAssert c.config, sfGenSym in s.flags or s.kind == skType
var x = PSym(idTableGet(c.mapping, s))
if x == nil:
x = copySym(s, nextSymId(c.idgen))
x = copySym(s, c.idgen)
# sem'check needs to set the owner properly later, see bug #9476
x.owner = nil # c.genSymOwner
#if x.kind == skParam and x.owner.kind == skModule:
@@ -187,7 +187,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
ctx.genSymOwner = genSymOwner
ctx.config = conf
ctx.ic = ic
initIdTable(ctx.mapping)
ctx.mapping = initIdTable()
ctx.instID = instID[]
ctx.idgen = idgen

View File

@@ -14,13 +14,15 @@
import ropes, platform, condsyms, options, msgs, lineinfos, pathutils, modulepaths
import std/[os, osproc, sha1, streams, sequtils, times, strtabs, json, jsonutils, sugar, parseutils]
import std/[os, osproc, streams, sequtils, times, strtabs, json, jsonutils, sugar, parseutils]
import std / strutils except addf
when defined(nimPreviewSlimSystem):
import std/syncio
import ../dist/checksums/src/checksums/sha1
type
TInfoCCProp* = enum # properties of the C compiler:
hasSwitchRange, # CC allows ranges in switch statements (GNU C)
@@ -484,6 +486,10 @@ proc vccplatform(conf: ConfigRef): string =
of cpuArm: " --platform:arm"
of cpuAmd64: " --platform:amd64"
else: ""
else:
result = ""
else:
result = ""
proc getLinkOptions(conf: ConfigRef): string =
result = conf.linkOptions & " " & conf.linkOptionsCmd & " "
@@ -532,7 +538,7 @@ proc ccHasSaneOverflow*(conf: ConfigRef): bool =
# NOTE: should we need the full version, use -dumpfullversion
let (s, exitCode) = try: execCmdEx(exe & " -dumpversion") except IOError, OSError, ValueError: ("", 1)
if exitCode == 0:
var major: int
var major: int = 0
discard parseInt(s, major)
result = major >= 5
else:
@@ -578,7 +584,7 @@ proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile,
compilePattern = joinPath(conf.cCompilerPath, exe)
else:
compilePattern = getCompilerExe(conf, c, isCpp)
compilePattern = exe
includeCmd.add(join([CC[c].includeCmd, quoteShell(conf.projectPath.string)]))
@@ -642,7 +648,7 @@ proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
let hashFile = toGeneratedFile(conf, conf.mangleModuleName(cfile.cname).AbsoluteFile, "sha1")
let currentHash = footprint(conf, cfile)
var f: File
var f: File = default(File)
if open(f, hashFile.string, fmRead):
let oldHash = parseSecureHash(f.readLine())
close(f)
@@ -777,6 +783,7 @@ template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body
raise
proc getExtraCmds(conf: ConfigRef; output: AbsoluteFile): seq[string] =
result = @[]
when defined(macosx):
if optCDebug in conf.globalOptions and optGenStaticLib notin conf.globalOptions:
# if needed, add an option to skip or override location
@@ -832,7 +839,10 @@ proc linkViaResponseFile(conf: ConfigRef; cmd: string) =
else:
writeFile(linkerArgs, args)
try:
execLinkCmd(conf, cmd.substr(0, last) & " @" & linkerArgs)
when defined(macosx):
execLinkCmd(conf, "xargs " & cmd.substr(0, last) & " < " & linkerArgs)
else:
execLinkCmd(conf, cmd.substr(0, last) & " @" & linkerArgs)
finally:
removeFile(linkerArgs)
@@ -856,6 +866,7 @@ proc hcrLinkTargetName(conf: ConfigRef, objFile: string, isMain = false): Absolu
result = conf.getNimcacheDir / RelativeFile(targetName)
proc displayProgressCC(conf: ConfigRef, path, compileCmd: string): string =
result = ""
if conf.hasHint(hintCC):
if optListCmd in conf.globalOptions or conf.verbosity > 1:
result = MsgKindToStr[hintCC] % (demangleModuleName(path.splitFile.name) & ": " & compileCmd)
@@ -878,15 +889,15 @@ proc preventLinkCmdMaxCmdLen(conf: ConfigRef, linkCmd: string) =
proc callCCompiler*(conf: ConfigRef) =
var
linkCmd: string
linkCmd: string = ""
extraCmds: seq[string]
if conf.globalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
return # speed up that call if only compiling and no script shall be
# generated
#var c = cCompiler
var script: Rope = ""
var cmds: TStringSeq
var prettyCmds: TStringSeq
var cmds: TStringSeq = default(TStringSeq)
var prettyCmds: TStringSeq = default(TStringSeq)
let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx])
for idx, it in conf.toCompile:
@@ -1017,8 +1028,9 @@ proc writeJsonBuildInstructions*(conf: ConfigRef) =
conf.jsonBuildFile.string.writeFile(bcache.toJson.pretty)
proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile): bool =
result = false
if not fileExists(jsonFile) or not fileExists(conf.absOutFile): return true
var bcache: BuildCache
var bcache: BuildCache = default(BuildCache)
try: bcache.fromJson(jsonFile.string.parseFile)
except IOError, OSError, ValueError:
stderr.write "Warning: JSON processing failed for: $#\n" % jsonFile.string
@@ -1034,7 +1046,7 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: Absolute
if $secureHashFile(file) != hash: return true
proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
var bcache: BuildCache
var bcache: BuildCache = default(BuildCache)
try: bcache.fromJson(jsonFile.string.parseFile)
except ValueError, KeyError, JsonKindError:
let e = getCurrentException()
@@ -1047,7 +1059,8 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
globalError(conf, gCmdLineInfo,
"jsonscript command outputFile '$1' must match '$2' which was specified during --compileOnly, see \"outputFile\" entry in '$3' " %
[outputCurrent, output, jsonFile.string])
var cmds, prettyCmds: TStringSeq
var cmds: TStringSeq = default(TStringSeq)
var prettyCmds: TStringSeq= default(TStringSeq)
let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx])
for (name, cmd) in bcache.compile:
cmds.add cmd
@@ -1057,6 +1070,7 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
for cmd in bcache.extraCmds: execExternalProgram(conf, cmd, hintExecuting)
proc genMappingFiles(conf: ConfigRef; list: CfileList): Rope =
result = ""
for it in list:
result.addf("--file:r\"$1\"$N", [rope(it.cname.string)])

View File

@@ -201,17 +201,15 @@ proc parseLine(p: var TTmplParser) =
proc filterTmpl*(conf: ConfigRef, stdin: PLLStream, filename: AbsoluteFile,
call: PNode): PLLStream =
var p: TTmplParser
p.config = conf
p.info = newLineInfo(conf, filename, 0, 0)
p.outp = llStreamOpen("")
p.inp = stdin
p.subsChar = charArg(conf, call, "subschar", 1, '$')
p.nimDirective = charArg(conf, call, "metachar", 2, '#')
p.emit = strArg(conf, call, "emit", 3, "result.add")
p.conc = strArg(conf, call, "conc", 4, " & ")
p.toStr = strArg(conf, call, "tostring", 5, "$")
p.x = newStringOfCap(120)
var p = TTmplParser(config: conf, info: newLineInfo(conf, filename, 0, 0),
outp: llStreamOpen(""), inp: stdin,
subsChar: charArg(conf, call, "subschar", 1, '$'),
nimDirective: charArg(conf, call, "metachar", 2, '#'),
emit: strArg(conf, call, "emit", 3, "result.add"),
conc: strArg(conf, call, "conc", 4, " & "),
toStr: strArg(conf, call, "tostring", 5, "$"),
x: newStringOfCap(120)
)
# do not process the first line which contains the directive:
if llStreamReadLine(p.inp, p.x):
inc p.info.line

View File

@@ -29,23 +29,30 @@ proc getArg(conf: ConfigRef; n: PNode, name: string, pos: int): PNode =
return n[i]
proc charArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: char): char =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind == nkCharLit: result = chr(int(x.intVal))
else: invalidPragma(conf, n)
else:
result = default(char)
invalidPragma(conf, n)
proc strArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: string): string =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind in {nkStrLit..nkTripleStrLit}: result = x.strVal
else: invalidPragma(conf, n)
else:
result = ""
invalidPragma(conf, n)
proc boolArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: bool): bool =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "true") == 0: result = true
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "false") == 0: result = false
else: invalidPragma(conf, n)
else:
result = false
invalidPragma(conf, n)
proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: AbsoluteFile, call: PNode): PLLStream =
var pattern = strArg(conf, call, "startswith", 1, "")

View File

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

View File

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

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

View File

@@ -13,6 +13,8 @@ type
vals: seq[T] # indexed by LitId
keys: seq[LitId] # indexed by hash(val)
proc initBiTable*[T](): BiTable[T] = BiTable[T](vals: @[], keys: @[])
proc nextTry(h, maxHash: Hash): Hash {.inline.} =
result = (h + 1) and maxHash

View File

@@ -50,7 +50,10 @@ proc generateCodeForModule(g: ModuleGraph; m: var LoadedModule; alive: var Alive
let n = unpackTree(g, m.module.position, m.fromDisk.topLevel, p)
cgen.genTopLevelStmt(bmod, n)
finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
let disps = finalCodegenActions(g, bmod, newNodeI(nkStmtList, m.module.info))
if disps != nil:
for disp in disps:
genProcAux(bmod, disp.sym)
m.fromDisk.backendFlags = cgen.whichInitProcs(bmod)
proc replayTypeInfo(g: ModuleGraph; m: var LoadedModule; origin: FileIndex) =
@@ -98,7 +101,7 @@ proc aliveSymsChanged(config: ConfigRef; position: int; alive: AliveSyms): bool
var f2 = rodfiles.open(asymFile.string)
f2.loadHeader()
f2.loadSection aliveSymsSection
var oldData: seq[int32]
var oldData: seq[int32] = @[]
f2.loadSeq(oldData)
f2.close
if f2.err == ok and oldData == s:

View File

@@ -40,10 +40,14 @@ proc isExportedToC(c: var AliveContext; g: PackedModuleGraph; symId: int32): boo
if ({sfExportc, sfCompilerProc} * flags != {}) or
(symPtr.kind == skMethod):
result = true
else:
result = false
# XXX: This used to be a condition to:
# (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
if sfCompilerProc in flags:
c.compilerProcs[g[c.thisModule].fromDisk.strings[symPtr.name]] = (c.thisModule, symId)
else:
result = false
template isNotGeneric(n: NodePos): bool = ithSon(tree, n, genericParamsPos).kind == nkEmpty

View File

@@ -7,13 +7,15 @@
# distribution, for details about the copyright.
#
import hashes, tables, intsets, std/sha1
import hashes, tables, intsets
import packed_ast, bitabs, rodfiles
import ".." / [ast, idents, lineinfos, msgs, ropes, options,
pathutils, condsyms, packages, modulepaths]
#import ".." / [renderer, astalgo]
from os import removeFile, isAbsolute
import ../../dist/checksums/src/checksums/sha1
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions, formatfloat]
@@ -357,7 +359,7 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI
paddingAtEnd: t.paddingAtEnd)
storeNode(p, t, n)
p.typeInst = t.typeInst.storeType(c, m)
for kid in items t.sons:
for kid in items t:
p.types.add kid.storeType(c, m)
c.addMissing t.sym
p.sym = t.sym.safeItemId(c, m)
@@ -372,7 +374,7 @@ proc toPackedLib(l: PLib; c: var PackedEncoder; m: var PackedModule): PackedLib
if l.isNil: return
result.kind = l.kind
result.generated = l.generated
result.isOverriden = l.isOverriden
result.isOverridden = l.isOverridden
result.name = toLitId($l.name, m)
storeNode(result, l, path)
@@ -390,7 +392,7 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
assert sfForward notin s.flags
var p = PackedSym(kind: s.kind, flags: s.flags, info: s.info.toPackedInfo(c, m), magic: s.magic,
position: s.position, offset: s.offset, options: s.options,
position: s.position, offset: s.offset, disamb: s.disamb, options: s.options,
name: s.name.s.toLitId(m))
storeNode(p, s, ast)
@@ -411,6 +413,7 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
p.annex = toPackedLib(s.annex, c, m)
when hasFFI:
p.cname = toLitId(s.cname, m)
p.instantiatedFrom = s.instantiatedFrom.safeItemId(c, m)
# fill the reserved slot, nothing else:
m.syms[s.itemId.item] = p
@@ -811,6 +814,7 @@ proc loadProcHeader(c: var PackedDecoder; g: var PackedModuleGraph; thisModule:
proc loadProcBody(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int;
tree: PackedTree; n: NodePos): PNode =
result = nil
var i = 0
for n0 in sonsReadonly(tree, n):
if i == bodyPos:
@@ -830,6 +834,7 @@ proc symHeaderFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
options: s.options,
position: if s.kind in {skForVar, skVar, skLet, skTemp}: 0 else: s.position,
offset: if s.kind in routineKinds: defaultOffset else: s.offset,
disamb: s.disamb,
name: getIdent(c.cache, g[si].fromDisk.strings[s.name])
)
@@ -847,7 +852,7 @@ proc loadLib(c: var PackedDecoder; g: var PackedModuleGraph;
if l.name.int == 0:
result = nil
else:
result = PLib(generated: l.generated, isOverriden: l.isOverriden,
result = PLib(generated: l.generated, isOverridden: l.isOverridden,
kind: l.kind, name: rope g[si].fromDisk.strings[l.name])
loadAstBody(l, path)
@@ -872,6 +877,7 @@ proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
if externalName != "":
result.loc.r = rope externalName
result.loc.flags = s.locFlags
result.instantiatedFrom = loadSym(c, g, si, s.instantiatedFrom)
proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym =
if s == nilItemId:
@@ -913,7 +919,7 @@ proc typeBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
result.attachedOps[op] = loadSym(c, g, si, item)
result.typeInst = loadType(c, g, si, t.typeInst)
for son in items t.types:
result.sons.add loadType(c, g, si, son)
result.addSon loadType(c, g, si, son)
loadAstBody(t, n)
when false:
for gen, id in items t.methods:
@@ -1144,6 +1150,8 @@ proc initRodIter*(it: var RodIter; config: ConfigRef, cache: IdentCache;
if it.i < it.values.len:
result = loadSym(it.decoder, g, int(module), it.values[it.i])
inc it.i
else:
result = nil
proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; module: FileIndex, importHidden: bool): PSym =
@@ -1161,11 +1169,15 @@ proc initRodIterAllSyms*(it: var RodIter; config: ConfigRef, cache: IdentCache;
if it.i < it.values.len:
result = loadSym(it.decoder, g, int(module), it.values[it.i])
inc it.i
else:
result = nil
proc nextRodIter*(it: var RodIter; g: var PackedModuleGraph): PSym =
if it.i < it.values.len:
result = loadSym(it.decoder, g, it.module, it.values[it.i])
inc it.i
else:
result = nil
iterator interfaceSymbols*(config: ConfigRef, cache: IdentCache;
g: var PackedModuleGraph; module: FileIndex;
@@ -1198,7 +1210,7 @@ proc searchForCompilerproc*(m: LoadedModule; name: string): int32 =
# ------------------------- .rod file viewer ---------------------------------
proc rodViewer*(rodfile: AbsoluteFile; config: ConfigRef, cache: IdentCache) =
var m: PackedModule
var m: PackedModule = PackedModule()
let err = loadRodFile(rodfile, m, config, ignoreConfig=true)
if err != ok:
config.quitOrRaise "Error: could not load: " & $rodfile.string & " reason: " & $err

View File

@@ -34,7 +34,11 @@ proc isTracked(current, trackPos: PackedLineInfo, tokenLen: int): bool =
if current.file == trackPos.file and current.line == trackPos.line:
let col = trackPos.col
if col >= current.col and col < current.col+tokenLen:
return true
result = true
else:
result = false
else:
result = false
proc searchLocalSym(c: var NavContext; s: PackedSym; info: PackedLineInfo): bool =
result = s.name != LitId(0) and

View File

@@ -45,7 +45,7 @@ type
PackedLib* = object
kind*: TLibKind
generated*: bool
isOverriden*: bool
isOverridden*: bool
name*: LitId
path*: NodeId
@@ -63,13 +63,15 @@ type
alignment*: int # for alignment
options*: TOptions
position*: int
offset*: int
offset*: int32
disamb*: int32
externalName*: LitId # instead of TLoc
locFlags*: TLocFlags
annex*: PackedLib
when hasFFI:
cname*: LitId
constraint*: NodeId
instantiatedFrom*: PackedItemId
PackedType* = object
kind*: TTypeKind
@@ -304,6 +306,7 @@ proc sons3*(tree: PackedTree; n: NodePos): (NodePos, NodePos, NodePos) =
result = (NodePos a, NodePos b, NodePos c)
proc ithSon*(tree: PackedTree; n: NodePos; i: int): NodePos =
result = default(NodePos)
if tree.nodes[n.int].kind > nkNilLit:
var count = 0
for child in sonsReadonly(tree, n):

View File

@@ -215,7 +215,7 @@ proc storeHeader*(f: var RodFile) =
proc loadHeader*(f: var RodFile) =
## Loads the header which is described by `cookie`.
if f.err != ok: return
var thisCookie: array[cookie.len, byte]
var thisCookie: array[cookie.len, byte] = default(array[cookie.len, byte])
if f.f.readBytes(thisCookie, 0, thisCookie.len) != thisCookie.len:
setError f, ioFailure
elif thisCookie != cookie:
@@ -231,13 +231,14 @@ proc storeSection*(f: var RodFile; s: RodSection) =
proc loadSection*(f: var RodFile; expected: RodSection) =
## read the bytes value of s, sets and error if the section is incorrect.
if f.err != ok: return
var s: RodSection
var s: RodSection = default(RodSection)
loadPrim(f, s)
if expected != s and f.err == ok:
setError f, wrongSection
proc create*(filename: string): RodFile =
## create the file and open it for writing
result = default(RodFile)
if not open(result.f, filename, fmWrite):
setError result, cannotOpen
@@ -245,5 +246,6 @@ proc close*(f: var RodFile) = close(f.f)
proc open*(filename: string): RodFile =
## open the file for reading
result = default(RodFile)
if not open(result.f, filename, fmRead):
setError result, cannotOpen

View File

@@ -113,6 +113,7 @@ proc rawImportSymbol(c: PContext, s, origin: PSym; importSet: var IntSet) =
proc splitPragmas(c: PContext, n: PNode): (PNode, seq[TSpecialWord]) =
template bail = globalError(c.config, n.info, "invalid pragma")
result = (nil, @[])
if n.kind == nkPragmaExpr:
if n.len == 2 and n[1].kind == nkPragma:
result[0] = n[0]
@@ -228,10 +229,15 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet; fromMod: PSym; im
for i in 0..n.safeLen-1:
importForwarded(c, n[i], exceptSet, fromMod, importSet)
proc addUnique[T](x: var seq[T], y: sink T) {.noSideEffect.} =
for i in 0..high(x):
if x[i] == y: return
x.add y
proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool): PSym =
result = realModule
template createModuleAliasImpl(ident): untyped =
createModuleAlias(realModule, nextSymId c.idgen, ident, n.info, c.config.options)
createModuleAlias(realModule, c.idgen, ident, n.info, c.config.options)
if n.kind != nkImportAs: discard
elif n.len != 2 or n[1].kind != nkIdent:
localError(c.config, n.info, "module alias must be an identifier")
@@ -245,6 +251,7 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool)
result.options.incl optImportHidden
c.unusedImports.add((result, n.info))
c.importModuleMap[result.id] = realModule.id
c.importModuleLookup.mgetOrPut(result.name.id, @[]).addUnique realModule.id
proc transformImportAs(c: PContext; n: PNode): tuple[node: PNode, importHidden: bool] =
var ret: typeof(result)
@@ -301,6 +308,8 @@ proc myImportModule(c: PContext, n: var PNode, importStmtResult: PNode): PSym =
suggestSym(c.graph, n.info, result, c.graph.usageSym, false)
importStmtResult.add newSymNode(result, n.info)
#newStrNode(toFullPath(c.config, f), n.info)
else:
result = nil
proc afterImport(c: PContext, m: PSym) =
# fixes bug #17510, for re-exported symbols
@@ -323,22 +332,24 @@ proc evalImport*(c: PContext, n: PNode): PNode =
result = newNodeI(nkImportStmt, n.info)
for i in 0..<n.len:
let it = n[i]
if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket:
let sep = it[0]
let dir = it[1]
var imp = newNodeI(nkInfix, it.info)
imp.add sep
imp.add dir
imp.add sep # dummy entry, replaced in the loop
for x in it[2]:
if it.kind in {nkInfix, nkPrefix} and it[^1].kind == nkBracket:
let lastPos = it.len - 1
var imp = copyNode(it)
newSons(imp, it.len)
for i in 0 ..< lastPos: imp[i] = it[i]
imp[lastPos] = imp[0] # dummy entry, replaced in the loop
for x in it[lastPos]:
# transform `a/b/[c as d]` to `/a/b/c as d`
if x.kind == nkInfix and x[0].ident.s == "as":
let impAs = copyTree(x)
imp[2] = x[1]
var impAs = copyNode(x)
newSons(impAs, 3)
impAs[0] = x[0]
imp[lastPos] = x[1]
impAs[1] = imp
impMod(c, imp, result)
impAs[2] = x[2]
impMod(c, impAs, result)
else:
imp[2] = x
imp[lastPos] = x
impMod(c, imp, result)
else:
impMod(c, it, result)

View File

@@ -36,6 +36,7 @@ type
body: PNode
otherUsage: TLineInfo
inUncheckedAssignSection: int
inEnsureMove: int
Scope = object # we do scope-based memory management.
# a scope is comparable to an nkStmtListExpr like
@@ -66,11 +67,11 @@ proc hasDestructor(c: Con; t: PType): bool {.inline.} =
result = ast.hasDestructor(t)
when toDebug.len > 0:
# for more effective debugging
if not result and c.graph.config.selectedGC in {gcArc, gcOrc}:
if not result and c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
assert(not containsGarbageCollectedRef(t))
proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), nextSymId c.idgen, c.owner, info)
let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.idgen, c.owner, info)
sym.typ = typ
s.vars.add(sym)
result = newSymNode(sym)
@@ -78,11 +79,11 @@ proc getTemp(c: var Con; s: var Scope; typ: PType; info: TLineInfo): PNode =
proc nestedScope(parent: var Scope; body: PNode): Scope =
Scope(vars: @[], locals: @[], wasMoved: @[], final: @[], body: body, needsTry: false, parent: addr(parent))
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}): PNode
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode
type
MoveOrCopyFlag = enum
IsDecl, IsExplicitSink
IsDecl, IsExplicitSink, IsReturn
proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope; flags: set[MoveOrCopyFlag] = {}): PNode
@@ -184,11 +185,16 @@ proc isCursor(n: PNode): bool =
template isUnpackedTuple(n: PNode): bool =
## we move out all elements of unpacked tuples,
## hence unpacked tuples themselves don't need to be destroyed
(n.kind == nkSym and n.sym.kind == skTemp and n.sym.typ.kind == tyTuple)
## except it's already a cursor
(n.kind == nkSym and n.sym.kind == skTemp and
n.sym.typ.kind == tyTuple and sfCursor notin n.sym.flags)
proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) =
proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string; inferredFromCopy = false) =
var m = "'" & opname & "' is not available for type <" & typeToString(t) & ">"
if (opname == "=" or opname == "=copy") and ri != nil:
if inferredFromCopy:
m.add ", which is inferred from unavailable '=copy'"
if (opname == "=" or opname == "=copy" or opname == "=dup") and ri != nil:
m.add "; requires a copy because it's not the last read of '"
m.add renderTree(ri)
m.add '\''
@@ -210,8 +216,12 @@ proc makePtrType(c: var Con, baseType: PType): PType =
addSonSkipIntLit(result, baseType, c.idgen)
proc genOp(c: var Con; op: PSym; dest: PNode): PNode =
let addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ))
addrExp.add(dest)
var addrExp: PNode
if op.typ != nil and op.typ.len > 1 and op.typ[1].kind != tyVar:
addrExp = dest
else:
addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ))
addrExp.add(dest)
result = newTree(nkCall, newSymNode(op), addrExp)
proc genOp(c: var Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode =
@@ -249,10 +259,20 @@ proc canBeMoved(c: Con; t: PType): bool {.inline.} =
proc isNoInit(dest: PNode): bool {.inline.} =
result = dest.kind == nkSym and sfNoInit in dest.sym.flags
proc genSink(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
proc deepAliases(dest, ri: PNode): bool =
case ri.kind
of nkCallKinds, nkStmtListExpr, nkBracket, nkTupleConstr, nkObjConstr,
nkCast, nkConv, nkObjUpConv, nkObjDownConv:
for r in ri:
if deepAliases(dest, r): return true
return false
else:
return aliases(dest, ri) != no
proc genSink(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
if (c.inLoopCond == 0 and (isUnpackedTuple(dest) or IsDecl in flags or
(isAnalysableFieldAccess(dest, c.owner) and isFirstWrite(dest, c)))) or
isNoInit(dest):
isNoInit(dest) or IsReturn in flags:
# optimize sink call into a bitwise memcopy
result = newTree(nkFastAsgn, dest, ri)
else:
@@ -263,7 +283,14 @@ proc genSink(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNod
else:
# the default is to use combination of `=destroy(dest)` and
# and copyMem(dest, source). This is efficient.
result = newTree(nkStmtList, c.genDestroy(dest), newTree(nkFastAsgn, dest, ri))
if deepAliases(dest, ri):
# consider: x = x + y, it is wrong to destroy the destination first!
# tmp to support self assignments
let tmp = c.getTemp(s, dest.typ, dest.info)
result = newTree(nkStmtList, newTree(nkFastAsgn, tmp, dest), newTree(nkFastAsgn, dest, ri),
c.genDestroy(tmp))
else:
result = newTree(nkStmtList, c.genDestroy(dest), newTree(nkFastAsgn, dest, ri))
proc isCriticalLink(dest: PNode): bool {.inline.} =
#[
@@ -288,13 +315,13 @@ proc isCriticalLink(dest: PNode): bool {.inline.} =
proc finishCopy(c: var Con; result, dest: PNode; isFromSink: bool) =
if c.graph.config.selectedGC == gcOrc:
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
if cyclicType(t):
if cyclicType(c.graph, t):
result.add boolLit(c.graph, result.info, isFromSink or isCriticalLink(dest))
proc genMarkCyclic(c: var Con; result, dest: PNode) =
if c.graph.config.selectedGC == gcOrc:
let t = dest.typ.skipTypes({tyGenericInst, tyAlias, tySink, tyDistinct})
if cyclicType(t):
if cyclicType(c.graph, t):
if t.kind == tyRef:
result.add callCodegenProc(c.graph, "nimMarkCyclic", dest.info, dest)
else:
@@ -308,6 +335,9 @@ proc genCopyNoCheck(c: var Con; dest, ri: PNode; a: TTypeAttachedOp): PNode =
assert ri.typ != nil
proc genCopy(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag]): PNode =
if c.inEnsureMove > 0:
localError(c.graph.config, ri.info, errFailedMove, "cannot move '" & $ri &
"', which introduces an implicit copy")
let t = dest.typ
if tfHasOwned in t.flags and ri.kind != nkNilLit:
# try to improve the error message here:
@@ -336,7 +366,7 @@ proc genDiscriminantAsgn(c: var Con; s: var Scope; n: PNode): PNode =
if hasDestructor(c, objType):
if getAttachedOp(c.graph, objType, attachedDestructor) != nil and
sfOverriden in getAttachedOp(c.graph, objType, attachedDestructor).flags:
sfOverridden in getAttachedOp(c.graph, objType, attachedDestructor).flags:
localError(c.graph.config, n.info, errGenerated, """Assignment to discriminant for objects with user defined destructor is not supported, object must have default destructor.
It is best to factor out piece of object that needs custom destructor into separate object or not use discriminator assignment""")
result.add newTree(nkFastAsgn, le, tmp)
@@ -364,7 +394,7 @@ proc genWasMoved(c: var Con, n: PNode): PNode =
result = genOp(c, op, n)
else:
result = newNodeI(nkCall, n.info)
result.add(newSymNode(createMagic(c.graph, c.idgen, "wasMoved", mWasMoved)))
result.add(newSymNode(createMagic(c.graph, c.idgen, "`=wasMoved`", mWasMoved)))
result.add copyTree(n) #mWasMoved does not take the address
#if n.kind != nkSym:
# message(c.graph.config, n.info, warnUser, "wasMoved(" & $n & ")")
@@ -376,13 +406,13 @@ 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):
if (not hasDestructor(c, n.typ)) and c.inEnsureMove == 0:
assert n.kind != nkSym or not hasDestructor(c, n.sym.typ)
result = copyTree(n)
else:
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), nextSymId c.idgen, c.owner, n.info)
var temp = newSym(skLet, getIdent(c.graph.cache, "blitTmp"), c.idgen, c.owner, n.info)
temp.typ = n.typ
var v = newNodeI(nkLetSection, n.info)
let tempAsNode = newSymNode(temp)
@@ -395,7 +425,8 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
result.add v
let nn = skipConv(n)
c.genMarkCyclic(result, nn)
if hasDestructor(c, n.typ):
c.genMarkCyclic(result, nn)
let wasMovedCall = c.genWasMoved(nn)
result.add wasMovedCall
result.add tempAsNode
@@ -403,22 +434,47 @@ proc destructiveMoveVar(n: PNode; c: var Con; s: var Scope): PNode =
proc isCapturedVar(n: PNode): bool =
let root = getRoot(n)
if root != nil: result = root.name.s[0] == ':'
else: result = false
proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let tmp = c.getTemp(s, n.typ, n.info)
if hasDestructor(c, n.typ):
result.add c.genWasMoved(tmp)
var m = c.genCopy(tmp, n, {})
m.add p(n, c, s, normal)
c.finishCopy(m, n, isFromSink = true)
result.add m
let typ = n.typ.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")
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)
let src = p(n, c, s, normal)
var newCall = newTreeIT(nkCall, src.info, src.typ,
newSymNode(op),
src)
c.finishCopy(newCall, n, isFromSink = true)
result.add newTreeI(nkFastAsgn,
src.info, tmp,
newCall
)
else:
result.add c.genWasMoved(tmp)
var m = c.genCopy(tmp, n, {})
m.add p(n, c, s, normal)
c.finishCopy(m, n, isFromSink = true)
result.add m
if isLValue(n) and not isCapturedVar(n) and n.typ.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0:
message(c.graph.config, n.info, hintPerformance,
("passing '$1' to a sink parameter introduces an implicit copy; " &
"if possible, rearrange your program's control flow to prevent it") % $n)
if c.inEnsureMove > 0:
localError(c.graph.config, n.info, errFailedMove,
("cannot move '$1', passing '$1' to a sink parameter introduces an implicit copy") % $n)
else:
if c.graph.config.selectedGC in {gcArc, gcOrc}:
if c.graph.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
assert(not containsManagedMemory(n.typ))
if n.typ.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")
@@ -454,14 +510,14 @@ proc ensureDestruction(arg, orig: PNode; c: var Con; s: var Scope): PNode =
# This was already done in the sink parameter handling logic.
result = newNodeIT(nkStmtListExpr, arg.info, arg.typ)
let tmp = c.getTemp(s, arg.typ, arg.info)
result.add c.genSink(tmp, arg, {IsDecl})
result.add c.genSink(s, tmp, arg, {IsDecl})
result.add tmp
s.final.add c.genDestroy(tmp)
else:
result = arg
proc cycleCheck(n: PNode; c: var Con) =
if c.graph.config.selectedGC != gcArc: return
if c.graph.config.selectedGC notin {gcArc, gcAtomicArc}: return
var value = n[1]
if value.kind == nkClosure:
value = value[1]
@@ -662,7 +718,27 @@ template handleNestedTempl(n, processCall: untyped, willProduceStmt = false,
of nkWhen: # This should be a "when nimvm" node.
result = copyTree(n)
result[1][0] = processCall(n[1][0], s)
else: assert(false)
of nkPragmaBlock:
var inUncheckedAssignSection = 0
let pragmaList = n[0]
for pi in pragmaList:
if whichPragma(pi) == wCast:
case whichPragma(pi[1])
of wUncheckedAssign:
inUncheckedAssignSection = 1
else:
discard
result = shallowCopy(n)
inc c.inUncheckedAssignSection, inUncheckedAssignSection
for i in 0 ..< n.len-1:
result[i] = p(n[i], c, s, normal)
result[^1] = maybeVoid(n[^1], s)
dec c.inUncheckedAssignSection, inUncheckedAssignSection
else:
result = nil
assert(false)
proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
if optOwnedRefs in c.graph.config.globalOptions and n[0].kind != nkEmpty:
@@ -689,9 +765,9 @@ 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 =
proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSingleUsedTemp}; inReturn = false): PNode =
if n.kind in {nkStmtList, nkStmtListExpr, nkBlockStmt, nkBlockExpr, nkIfStmt,
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt}:
nkIfExpr, nkCaseStmt, nkWhen, nkWhileStmt, nkParForStmt, nkTryStmt, nkPragmaBlock}:
template process(child, s): untyped = p(child, c, s, mode)
handleNestedTempl(n, process, tmpFlags = tmpFlags)
elif mode == sinkArg:
@@ -702,7 +778,15 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
result = passCopyToSink(n, c, s)
elif n.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkClosure, nkNilLit} +
nkCallKinds + nkLiterals:
result = p(n, c, s, consumed)
if n.kind in nkCallKinds and n[0].kind == nkSym:
if n[0].sym.magic == mEnsureMove:
inc c.inEnsureMove
result = p(n[1], c, s, sinkArg)
dec c.inEnsureMove
else:
result = p(n, c, s, consumed)
else:
result = p(n, c, s, consumed)
elif ((n.kind == nkSym and isSinkParam(n.sym)) or isAnalysableFieldAccess(n, c.owner)) and
isLastRead(n, c, s) and not (n.kind == nkSym and isCursor(n)):
# Sinked params can be consumed only once. We need to reset the memory
@@ -774,6 +858,12 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
if mode == normal and isRefConstr:
result = ensureDestruction(result, n, c, s)
of nkCallKinds:
if n[0].kind == nkSym and n[0].sym.magic == mEnsureMove:
inc c.inEnsureMove
result = p(n[1], c, s, sinkArg)
dec c.inEnsureMove
return
let inSpawn = c.inSpawn
if n[0].kind == nkSym and n[0].sym.magic == mSpawn:
c.inSpawn.inc
@@ -804,7 +894,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
if n[0].kind == nkSym and n[0].sym.magic in {mNew, mNewFinalize}:
result[0] = copyTree(n[0])
if c.graph.config.selectedGC in {gcHooks, gcArc, gcOrc}:
if c.graph.config.selectedGC in {gcHooks, gcArc, gcAtomicArc, gcOrc}:
let destroyOld = c.genDestroy(result[1])
result = newTree(nkStmtList, destroyOld, result)
else:
@@ -859,7 +949,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
if n[0].kind in {nkDotExpr, nkCheckedFieldExpr}:
cycleCheck(n, c)
assert n[1].kind notin {nkAsgn, nkFastAsgn, nkSinkAsgn}
let flags = if n.kind == nkSinkAsgn: {IsExplicitSink} else: {}
var flags = if n.kind == nkSinkAsgn: {IsExplicitSink} else: {}
if inReturn:
flags.incl(IsReturn)
result = moveOrCopy(p(n[0], c, s, mode), n[1], c, s, flags)
elif isDiscriminantField(n[0]):
result = c.genDiscriminantAsgn(s, n)
@@ -887,25 +979,6 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
if mode == normal:
result = ensureDestruction(result, n, c, s)
of nkPragmaBlock:
var inUncheckedAssignSection = 0
let pragmaList = n[0]
for pi in pragmaList:
if whichPragma(pi) == wCast:
case whichPragma(pi[1])
of wUncheckedAssign:
inUncheckedAssignSection = 1
else:
discard
result = shallowCopy(n)
inc c.inUncheckedAssignSection, inUncheckedAssignSection
for i in 0 ..< n.len:
result[i] = p(n[i], c, s, normal)
dec c.inUncheckedAssignSection, inUncheckedAssignSection
if n.typ != nil and hasDestructor(c, n.typ):
if mode == normal:
result = ensureDestruction(result, n, c, s)
of nkHiddenSubConv, nkHiddenStdConv, nkConv:
# we have an "ownership invariance" for all constructors C(x).
# See the comment for nkBracket construction. If the caller wants
@@ -962,7 +1035,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)
@@ -976,11 +1049,12 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
of nkGotoState, nkState, nkAsmStmt:
result = n
else:
result = nil
internalError(c.graph.config, n.info, "cannot inject destructors to node kind: " & $n.kind)
proc sameLocation*(a, b: PNode): bool =
proc sameConstant(a, b: PNode): bool =
a.kind in nkLiterals and a.intVal == b.intVal
a.kind in nkLiterals and b.kind in nkLiterals and a.intVal == b.intVal
const nkEndPoint = {nkSym, nkDotExpr, nkCheckedFieldExpr, nkBracketExpr}
if a.kind in nkEndPoint and b.kind in nkEndPoint:
@@ -1004,9 +1078,9 @@ proc sameLocation*(a, b: PNode): bool =
of nkHiddenStdConv, nkHiddenSubConv: sameLocation(a[1], b)
else: false
proc genFieldAccessSideEffects(c: var Con; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
proc genFieldAccessSideEffects(c: var Con; s: var Scope; dest, ri: PNode; flags: set[MoveOrCopyFlag] = {}): PNode =
# with side effects
var temp = newSym(skLet, getIdent(c.graph.cache, "bracketTmp"), nextSymId c.idgen, c.owner, ri[1].info)
var temp = newSym(skLet, getIdent(c.graph.cache, "bracketTmp"), c.idgen, c.owner, ri[1].info)
temp.typ = ri[1].typ
var v = newNodeI(nkLetSection, ri[1].info)
let tempAsNode = newSymNode(temp)
@@ -1021,14 +1095,22 @@ proc genFieldAccessSideEffects(c: var Con; dest, ri: PNode; flags: set[MoveOrCop
newAccess.add ri[0]
newAccess.add tempAsNode
var snk = c.genSink(dest, newAccess, flags)
var snk = c.genSink(s, dest, newAccess, flags)
result = newTree(nkStmtList, v, snk, c.genWasMoved(newAccess))
proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopyFlag] = {}): PNode =
var ri = ri
var isEnsureMove = 0
if ri.kind in nkCallKinds and ri[0].kind == nkSym and ri[0].sym.magic == mEnsureMove:
ri = ri[1]
isEnsureMove = 1
if sameLocation(dest, ri):
# rule (self-assignment-removal):
result = newNodeI(nkEmpty, dest.info)
elif isCursor(dest):
elif isCursor(dest) or dest.typ.kind in {tyOpenArray, tyVarargs}:
# hoisted openArray parameters might end up here
# openArray types don't have a lifted assignment operation (it's empty)
# bug #22132
case ri.kind:
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt:
template process(child, s): untyped = moveOrCopy(dest, child, c, s, flags)
@@ -1037,53 +1119,61 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
else:
result = newTree(nkFastAsgn, dest, p(ri, c, s, normal))
else:
case ri.kind
let ri2 = if ri.kind == nkWhen: ri[1][0] else: ri
case ri2.kind
of nkCallKinds:
result = c.genSink(dest, p(ri, c, s, consumed), flags)
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
of nkBracketExpr:
if isUnpackedTuple(ri[0]):
# unpacking of tuple: take over the elements
result = c.genSink(dest, p(ri, c, s, consumed), flags)
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
elif isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c, s):
if aliases(dest, ri) == no:
# Rule 3: `=sink`(x, z); wasMoved(z)
if isAtom(ri[1]):
var snk = c.genSink(dest, ri, flags)
var snk = c.genSink(s, dest, ri, flags)
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
else:
result = genFieldAccessSideEffects(c, dest, ri, flags)
result = genFieldAccessSideEffects(c, s, dest, ri, flags)
else:
result = c.genSink(dest, destructiveMoveVar(ri, c, s), flags)
result = c.genSink(s, dest, destructiveMoveVar(ri, c, s), flags)
else:
inc c.inEnsureMove, isEnsureMove
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
of nkBracket:
# array constructor
if ri.len > 0 and isDangerousSeq(ri.typ):
inc c.inEnsureMove, isEnsureMove
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
else:
result = c.genSink(dest, p(ri, c, s, consumed), flags)
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit:
result = c.genSink(dest, p(ri, c, s, consumed), flags)
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
of nkSym:
if isSinkParam(ri.sym) and isLastRead(ri, c, s):
# Rule 3: `=sink`(x, z); wasMoved(z)
let snk = c.genSink(dest, ri, flags)
let snk = c.genSink(s, dest, ri, flags)
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
elif ri.sym.kind != skParam and ri.sym.owner == c.owner and
isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri):
isLastRead(ri, c, s) and canBeMoved(c, dest.typ) and not isCursor(ri) and
not ({sfGlobal, sfPure} <= ri.sym.flags):
# Rule 3: `=sink`(x, z); wasMoved(z)
let snk = c.genSink(dest, ri, flags)
let snk = c.genSink(s, dest, ri, flags)
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
else:
inc c.inEnsureMove, isEnsureMove
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv, nkCast:
result = c.genSink(dest, p(ri, c, s, sinkArg), flags)
result = c.genSink(s, dest, p(ri, c, s, sinkArg), flags)
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt:
template process(child, s): untyped = moveOrCopy(dest, child, c, s, flags)
# We know the result will be a stmt so we use that fact to optimize
@@ -1094,10 +1184,12 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
if isAnalysableFieldAccess(ri, c.owner) and isLastRead(ri, c, s) and
canBeMoved(c, dest.typ):
# Rule 3: `=sink`(x, z); wasMoved(z)
let snk = c.genSink(dest, ri, flags)
let snk = c.genSink(s, dest, ri, flags)
result = newTree(nkStmtList, snk, c.genWasMoved(ri))
else:
inc c.inEnsureMove, isEnsureMove
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)

View File

@@ -78,6 +78,7 @@ Files: "lib"
[Other]
Files: "examples"
Files: "dist/nimble"
Files: "dist/checksums"
Files: "tests"
@@ -91,6 +92,7 @@ Files: "bin/nimgrab.exe"
Files: "bin/nimpretty.exe"
Files: "bin/testament.exe"
Files: "bin/nim-gdb.bat"
Files: "bin/atlas.exe"
Files: "koch.exe"
Files: "finish.exe"

View File

@@ -171,6 +171,7 @@ proc addToHex*(result: var string; arg: Int128) =
i -= 1
proc toHex*(arg: Int128): string =
result = ""
result.addToHex(arg)
proc inc*(a: var Int128, y: uint32 = 1) =
@@ -330,8 +331,8 @@ proc `*`*(a: Int128, b: int32): Int128 =
if b < 0:
result = -result
proc `*=`*(a: var Int128, b: int32): Int128 =
result = result * b
proc `*=`(a: var Int128, b: int32) =
a = a * b
proc makeInt128(high, low: uint64): Int128 =
result.udata[0] = cast[uint32](low)
@@ -360,6 +361,7 @@ proc `*=`*(a: var Int128, b: Int128) =
import bitops
proc fastLog2*(a: Int128): int =
result = 0
if a.udata[3] != 0:
return 96 + fastLog2(a.udata[3])
if a.udata[2] != 0:
@@ -571,4 +573,4 @@ proc maskBytes*(arg: Int128, numbytes: int): Int128 {.noinit.} =
of 8:
return maskUInt64(arg)
else:
assert(false, "masking only implemented for 1, 2, 4 and 8 bytes")
raiseAssert "masking only implemented for 1, 2, 4 and 8 bytes"

View File

@@ -21,6 +21,7 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool
proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool =
case n.kind
of nkRecList:
result = false
for i in 0..<n.len:
result = canAliasN(arg, n[i], marker)
if result: return
@@ -36,7 +37,7 @@ proc canAliasN(arg: PType; n: PNode; marker: var IntSet): bool =
else: discard
of nkSym:
result = canAlias(arg, n.sym.typ, marker)
else: discard
else: result = false
proc canAlias(arg, ret: PType; marker: var IntSet): bool =
if containsOrIncl(marker, ret.id):
@@ -56,6 +57,7 @@ proc canAlias(arg, ret: PType; marker: var IntSet): bool =
else:
result = true
of tyTuple:
result = false
for i in 0..<ret.len:
result = canAlias(arg, ret[i], marker)
if result: break
@@ -72,6 +74,69 @@ proc isValueOnlyType(t: PType): bool =
proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr, tyVar, tyLent}
result = not types.searchTypeFor(t, wrap)
type
SearchResult = enum
NotFound, Abort, Found
proc containsDangerousRefAux(t: PType; marker: var IntSet): SearchResult
proc containsDangerousRefAux(n: PNode; marker: var IntSet): SearchResult =
result = NotFound
case n.kind
of nkRecList:
for i in 0..<n.len:
result = containsDangerousRefAux(n[i], marker)
if result == Found: return result
of nkRecCase:
assert(n[0].kind == nkSym)
result = containsDangerousRefAux(n[0], marker)
if result == Found: return result
for i in 1..<n.len:
case n[i].kind
of nkOfBranch, nkElse:
result = containsDangerousRefAux(lastSon(n[i]), marker)
if result == Found: return result
else: discard
of nkSym:
result = containsDangerousRefAux(n.sym.typ, marker)
else: discard
proc containsDangerousRefAux(t: PType; marker: var IntSet): SearchResult =
result = NotFound
if t == nil: return result
if containsOrIncl(marker, t.id): return result
if t.kind == tyRef or (t.kind == tyProc and t.callConv == ccClosure):
result = Found
elif tfSendable in t.flags:
result = Abort
else:
# continue the type traversal:
result = NotFound
if result != NotFound: return result
case t.kind
of tyObject:
if t[0] != nil:
result = containsDangerousRefAux(t[0].skipTypes(skipPtrs), marker)
if result == NotFound: result = containsDangerousRefAux(t.n, marker)
of tyGenericInst, tyDistinct, tyAlias, tySink:
result = containsDangerousRefAux(lastSon(t), marker)
of tyArray, tySet, tyTuple, tySequence:
for i in 0..<t.len:
result = containsDangerousRefAux(t[i], marker)
if result == Found: return result
else:
discard
proc containsDangerousRef(t: PType): bool =
# a `ref` type is "dangerous" if it occurs not within a type that is like `Isolated[T]`.
# For example:
# `ref int` # dangerous
# `Isolated[ref int]` # not dangerous
var marker = initIntSet()
result = containsDangerousRefAux(t, marker) == Found
proc canAlias*(arg, ret: PType): bool =
if isValueOnlyType(arg):
# can alias only with addr(arg.x) and we don't care if it is not safe
@@ -80,12 +145,15 @@ proc canAlias*(arg, ret: PType): bool =
var marker = initIntSet()
result = canAlias(arg, ret, marker)
const
SomeVar = {skForVar, skParam, skVar, skLet, skConst, skResult, skTemp}
proc containsVariable(n: PNode): bool =
case n.kind
of nodesToIgnoreSet:
result = false
of nkSym:
result = n.sym.kind in {skForVar, skParam, skVar, skLet, skConst, skResult, skTemp}
result = n.sym.kind in SomeVar
else:
for ch in n:
if containsVariable(ch): return true
@@ -109,7 +177,7 @@ proc checkIsolate*(n: PNode): bool =
discard "fine, it is isolated already"
else:
let argType = n[i].typ
if argType != nil and not isCompileTimeOnly(argType) and containsTyRef(argType):
if argType != nil and not isCompileTimeOnly(argType) and containsDangerousRef(argType):
if argType.canAlias(n.typ) or containsVariable(n[i]):
# bug #19013: Alias information is not enough, we need to check for potential
# "overlaps". I claim the problem can only happen by reading again from a location
@@ -118,10 +186,12 @@ proc checkIsolate*(n: PNode): bool =
return false
result = true
of nkIfStmt, nkIfExpr:
result = false
for it in n:
result = checkIsolate(it.lastSon)
if not result: break
of nkCaseStmt:
result = false
for i in 1..<n.len:
result = checkIsolate(n[i].lastSon)
if not result: break
@@ -131,6 +201,7 @@ proc checkIsolate*(n: PNode): bool =
result = checkIsolate(n[i].lastSon)
if not result: break
of nkBracket, nkTupleConstr, nkPar:
result = false
for it in n:
result = checkIsolate(it)
if not result: break
@@ -143,6 +214,12 @@ proc checkIsolate*(n: PNode): bool =
result = checkIsolate(n[^1])
else:
result = false
of nkSym:
result = true
if n.sym.kind in SomeVar:
let argType = n.typ
if argType != nil and not isCompileTimeOnly(argType) and containsDangerousRef(argType):
result = false
else:
# unanalysable expression:
result = false

File diff suppressed because it is too large Load Diff

View File

@@ -140,7 +140,7 @@ proc createClosureIterStateType*(g: ModuleGraph; iter: PSym; idgen: IdGenerator)
rawAddSon(result, intType)
proc createStateField(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym =
result = newSym(skField, getIdent(g.cache, ":state"), nextSymId(idgen), iter, iter.info)
result = newSym(skField, getIdent(g.cache, ":state"), idgen, iter, iter.info)
result.typ = createClosureIterStateType(g, iter, idgen)
proc createEnvObj(g: ModuleGraph; idgen: IdGenerator; owner: PSym; info: TLineInfo): PType =
@@ -154,7 +154,7 @@ proc getClosureIterResult*(g: ModuleGraph; iter: PSym; idgen: IdGenerator): PSym
result = iter.ast[resultPos].sym
else:
# XXX a bit hacky:
result = newSym(skResult, getIdent(g.cache, ":result"), nextSymId(idgen), iter, iter.info, {})
result = newSym(skResult, getIdent(g.cache, ":result"), idgen, iter, iter.info, {})
result.typ = iter.typ[0]
incl(result.flags, sfUsed)
iter.ast.add newSymNode(result)
@@ -187,6 +187,8 @@ proc getEnvParam*(routine: PSym): PSym =
if hidden.kind == nkSym and hidden.sym.name.s == paramName:
result = hidden.sym
assert sfFromGeneric in result.flags
else:
result = nil
proc interestingVar(s: PSym): bool {.inline.} =
result = s.kind in {skVar, skLet, skTemp, skForVar, skParam, skResult} and
@@ -199,6 +201,8 @@ proc illegalCapture(s: PSym): bool {.inline.} =
proc isInnerProc(s: PSym): bool =
if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator} and s.magic == mNone:
result = s.skipGenericOwner.kind in routineKinds
else:
result = false
proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
# Bugfix: unfortunately we cannot use 'nkFastAsgn' here as that would
@@ -267,7 +271,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PN
addUniqueField(it.typ.skipTypes({tyOwned})[0], hp, g.cache, idgen)
env = indirectAccess(newSymNode(it), hp, hp.info)
else:
let e = newSym(skLet, iter.name, nextSymId(idgen), owner, n.info)
let e = newSym(skLet, iter.name, idgen, owner, n.info)
e.typ = hp.typ
e.flags = hp.flags
env = newSymNode(e)
@@ -293,33 +297,34 @@ 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
proc initDetectionPass(g: ModuleGraph; fn: PSym; idgen: IdGenerator): DetectionPass =
result.processed = initIntSet()
result.capturedVars = initIntSet()
result.ownerToType = initTable[int, PType]()
result.processed.incl(fn.id)
result.graph = g
result.idgen = idgen
result = DetectionPass(processed: toIntSet([fn.id]),
capturedVars: initIntSet(), ownerToType: initTable[int, PType](),
graph: g, idgen: idgen
)
discard """
proc outer =
@@ -380,7 +385,7 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
if c.graph.config.selectedGC == gcDestructors and sfCursor notin upField.flags:
localError(c.graph.config, dep.info, "internal error: up reference is not a .cursor")
else:
let result = newSym(skField, upIdent, nextSymId(c.idgen), obj.owner, obj.owner.info)
let result = newSym(skField, upIdent, c.idgen, obj.owner, obj.owner.info)
result.typ = fieldType
when false:
if c.graph.config.selectedGC == gcDestructors:
@@ -413,12 +418,15 @@ Consider:
"""
proc isTypeOf(n: PNode): bool =
n.kind == nkSym and n.sym.magic in {mTypeOf, mType}
proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
var cp = getEnvParam(fn)
let owner = if fn.kind == skIterator: fn else: fn.skipGenericOwner
let t = c.getEnvTypeForOwner(owner, info)
if cp == nil:
cp = newSym(skParam, getIdent(c.graph.cache, paramName), nextSymId(c.idgen), fn, fn.info)
cp = newSym(skParam, getIdent(c.graph.cache, paramName), c.idgen, fn, fn.info)
incl(cp.flags, sfFromGeneric)
cp.typ = t
addHiddenParam(fn, cp)
@@ -444,12 +452,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 +469,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 +486,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 +523,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
@@ -522,9 +540,8 @@ type
unownedEnvVars: Table[int, PNode] # only required for --newruntime
proc initLiftingPass(fn: PSym): LiftingPass =
result.processed = initIntSet()
result.processed.incl(fn.id)
result.envVars = initTable[int, PNode]()
result = LiftingPass(processed: toIntSet([fn.id]),
envVars: initTable[int, PNode]())
proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
let s = n.sym
@@ -545,7 +562,7 @@ proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
result = n
proc newEnvVar(cache: IdentCache; owner: PSym; typ: PType; info: TLineInfo; idgen: IdGenerator): PNode =
var v = newSym(skVar, getIdent(cache, envName), nextSymId(idgen), owner, info)
var v = newSym(skVar, getIdent(cache, envName), idgen, owner, info)
v.flags = {sfShadowed, sfGeneratedOp}
v.typ = typ
result = newSymNode(v)
@@ -569,7 +586,7 @@ proc setupEnvVar(owner: PSym; d: var DetectionPass;
result = newEnvVar(d.graph.cache, owner, asOwnedRef(d, envVarType), info, d.idgen)
c.envVars[owner.id] = result
if optOwnedRefs in d.graph.config.globalOptions:
var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), nextSymId d.idgen, owner, info)
var v = newSym(skVar, getIdent(d.graph.cache, envName & "Alt"), d.idgen, owner, info)
v.flags = {sfShadowed, sfGeneratedOp}
v.typ = envVarType
c.unownedEnvVars[owner.id] = newSymNode(v)
@@ -653,7 +670,7 @@ proc closureCreationForIter(iter: PNode;
d: var DetectionPass; c: var LiftingPass): PNode =
result = newNodeIT(nkStmtListExpr, iter.info, iter.sym.typ)
let owner = iter.sym.skipGenericOwner
var v = newSym(skVar, getIdent(d.graph.cache, envName), nextSymId(d.idgen), owner, iter.info)
var v = newSym(skVar, getIdent(d.graph.cache, envName), d.idgen, owner, iter.info)
incl(v.flags, sfShadowed)
v.typ = asOwnedRef(d, getHiddenParam(d.graph, iter.sym).typ)
var vnode: PNode
@@ -711,6 +728,7 @@ proc symToClosure(n: PNode; owner: PSym; d: var DetectionPass;
# direct dependency, so use the outer's env variable:
result = makeClosure(d.graph, d.idgen, s, setupEnvVar(owner, d, c, n.info), n.info)
else:
result = nil
let available = getHiddenParam(d.graph, owner)
let wanted = getHiddenParam(d.graph, s).typ
# ugh: call through some other inner proc;
@@ -792,6 +810,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:
@@ -936,14 +956,14 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym):
result = newNodeI(nkStmtList, body.info)
# static binding?
var env: PSym
var env: PSym = nil
let op = call[0]
if op.kind == nkSym and op.sym.isIterator:
# createClosure()
let iter = op.sym
let hp = getHiddenParam(g, iter)
env = newSym(skLet, iter.name, nextSymId(idgen), owner, body.info)
env = newSym(skLet, iter.name, idgen, owner, body.info)
env.typ = hp.typ
env.flags = hp.flags

View File

@@ -510,7 +510,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
rememberSplit(splitComma)
wrSpace em
of openPars:
if tok.strongSpaceA and not em.endsInWhite and
if tsLeading in tok.spacing and not em.endsInWhite and
(not em.wasExportMarker or tok.tokType == tkCurlyDotLe):
wrSpace em
wr(em, $tok.tokType, ltSomeParLe)
@@ -528,7 +528,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
wr(em, $tok.tokType, ltOther)
if not em.inquote: wrSpace(em)
of tkOpr, tkDotDot:
if em.inquote or (((not tok.strongSpaceA) and tok.strongSpaceB == tsNone) and
if em.inquote or (tok.spacing == {} and
tok.ident.s notin ["<", ">", "<=", ">=", "==", "!="]):
# bug #9504: remember to not spacify a keyword:
lastTokWasTerse = true
@@ -538,7 +538,7 @@ proc emitTok*(em: var Emitter; L: Lexer; tok: Token) =
if not em.endsInWhite: wrSpace(em)
wr(em, tok.ident.s, ltOpr)
template isUnary(tok): bool =
tok.strongSpaceB == tsNone and tok.strongSpaceA
tok.spacing == {tsLeading}
if not isUnary(tok):
rememberSplit(splitBinary)

View File

@@ -23,7 +23,6 @@ when defined(nimPreviewSlimSystem):
import std/[assertions, formatfloat]
const
MaxLineLength* = 80 # lines longer than this lead to a warning
numChars*: set[char] = {'0'..'9', 'a'..'z', 'A'..'Z'}
SymChars*: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
@@ -94,19 +93,18 @@ type
base2, base8, base16
TokenSpacing* = enum
tsNone, tsTrailing, tsEof
tsLeading, tsTrailing, tsEof
Token* = object # a Nim token
tokType*: TokType # the type of the token
base*: NumericalBase # the numerical base; only valid for int
# or float literals
spacing*: set[TokenSpacing] # spaces around token
indent*: int # the indentation; != -1 if the token has been
# preceded with indentation
ident*: PIdent # the parsed identifier
iNumber*: BiggestInt # the parsed integer literal
fNumber*: BiggestFloat # the parsed floating point literal
base*: NumericalBase # the numerical base; only valid for int
# or float literals
strongSpaceA*: bool # leading spaces of an operator
strongSpaceB*: TokenSpacing # trailing spaces of an operator
literal*: string # the parsed (string) literal; and
# documentation comments are here too
line*, col*: int
@@ -150,9 +148,11 @@ proc isNimIdentifier*(s: string): bool =
var i = 1
while i < sLen:
if s[i] == '_': inc(i)
if i < sLen and s[i] notin SymChars: return
if i < sLen and s[i] notin SymChars: return false
inc(i)
result = true
else:
result = false
proc `$`*(tok: Token): string =
case tok.tokType
@@ -178,7 +178,7 @@ proc initToken*(L: var Token) =
L.tokType = tkInvalid
L.iNumber = 0
L.indent = 0
L.strongSpaceA = false
L.spacing = {}
L.literal = ""
L.fNumber = 0.0
L.base = base10
@@ -191,7 +191,7 @@ proc fillToken(L: var Token) =
L.tokType = tkInvalid
L.iNumber = 0
L.indent = 0
L.strongSpaceA = false
L.spacing = {}
setLen(L.literal, 0)
L.fNumber = 0.0
L.base = base10
@@ -539,8 +539,8 @@ proc getNumber(L: var Lexer, result: var Token) =
of floatTypes:
result.fNumber = parseFloat(result.literal)
of tkUInt64Lit, tkUIntLit:
var iNumber: uint64
var len: int
var iNumber: uint64 = uint64(0)
var len: int = 0
try:
len = parseBiggestUInt(result.literal, iNumber)
except ValueError:
@@ -549,8 +549,8 @@ proc getNumber(L: var Lexer, result: var Token) =
raise newException(ValueError, "invalid integer: " & result.literal)
result.iNumber = cast[int64](iNumber)
else:
var iNumber: int64
var len: int
var iNumber: int64 = int64(0)
var len: int = 0
try:
len = parseBiggestInt(result.literal, iNumber)
except ValueError:
@@ -737,10 +737,6 @@ proc handleCRLF(L: var Lexer, pos: int): int =
template registerLine =
let col = L.getColNumber(pos)
when not defined(nimpretty):
if col > MaxLineLength:
lexMessagePos(L, hintLineTooLong, pos)
case L.buf[pos]
of CR:
registerLine()
@@ -960,13 +956,15 @@ proc getOperator(L: var Lexer, tok: var Token) =
tokenEnd(tok, pos-1)
# advance pos but don't store it in L.bufpos so the next token (which might
# be an operator too) gets the preceding spaces:
tok.strongSpaceB = tsNone
tok.spacing = tok.spacing - {tsTrailing, tsEof}
var trailing = false
while L.buf[pos] == ' ':
inc pos
if tok.strongSpaceB != tsTrailing:
tok.strongSpaceB = tsTrailing
trailing = true
if L.buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
tok.strongSpaceB = tsEof
tok.spacing.incl(tsEof)
elif trailing:
tok.spacing.incl(tsTrailing)
proc getPrecedence*(tok: Token): int =
## Calculates the precedence of the given token.
@@ -1011,6 +1009,7 @@ proc getPrecedence*(tok: Token): int =
else: return -10
proc newlineFollows*(L: Lexer): bool =
result = false
var pos = L.bufpos
while true:
case L.buf[pos]
@@ -1077,7 +1076,6 @@ proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int;
when defined(nimpretty): tok.literal.add "\L"
if isDoc:
when not defined(nimpretty): tok.literal.add "\n"
inc tok.iNumber
var c = toStrip
while L.buf[pos] == ' ' and c > 0:
inc pos
@@ -1096,8 +1094,6 @@ proc skipMultiLineComment(L: var Lexer; tok: var Token; start: int;
proc scanComment(L: var Lexer, tok: var Token) =
var pos = L.bufpos
tok.tokType = tkComment
# iNumber contains the number of '\n' in the token
tok.iNumber = 0
assert L.buf[pos+1] == '#'
when defined(nimpretty):
tok.commentOffsetA = L.offsetBase + pos
@@ -1140,7 +1136,6 @@ proc scanComment(L: var Lexer, tok: var Token) =
while L.buf[pos] == ' ' and c > 0:
inc pos
dec c
inc tok.iNumber
else:
if L.buf[pos] > ' ':
L.indentAhead = indent
@@ -1153,7 +1148,7 @@ proc scanComment(L: var Lexer, tok: var Token) =
proc skip(L: var Lexer, tok: var Token) =
var pos = L.bufpos
tokenBegin(tok, pos)
tok.strongSpaceA = false
tok.spacing.excl(tsLeading)
when defined(nimpretty):
var hasComment = false
var commentIndent = L.currLineIndent
@@ -1164,8 +1159,7 @@ proc skip(L: var Lexer, tok: var Token) =
case L.buf[pos]
of ' ':
inc(pos)
if not tok.strongSpaceA:
tok.strongSpaceA = true
tok.spacing.incl(tsLeading)
of '\t':
if not L.allowTabs: lexMessagePos(L, errGenerated, pos, "tabs are not allowed, use spaces instead")
inc(pos)
@@ -1187,7 +1181,7 @@ proc skip(L: var Lexer, tok: var Token) =
pos = L.bufpos
else:
break
tok.strongSpaceA = false
tok.spacing.excl(tsLeading)
when defined(nimpretty):
if L.buf[pos] == '#' and tok.line < 0: commentIndent = indent
if L.buf[pos] > ' ' and (L.buf[pos] != '#' or L.buf[pos+1] == '#'):
@@ -1403,8 +1397,9 @@ proc rawGetTok*(L: var Lexer, tok: var Token) =
proc getIndentWidth*(fileIdx: FileIndex, inputstream: PLLStream;
cache: IdentCache; config: ConfigRef): int =
var lex: Lexer
var tok: Token
result = 0
var lex: Lexer = default(Lexer)
var tok: Token = default(Token)
initToken(tok)
openLexer(lex, fileIdx, inputstream, cache, config)
var prevToken = tkEof

View File

@@ -8,7 +8,7 @@
#
## This module implements lifting for type-bound operations
## (``=sink``, ``=copy``, ``=destroy``, ``=deepCopy``).
## (`=sink`, `=copy`, `=destroy`, `=deepCopy`, `=wasMoved`, `=dup`).
import modulegraphs, lineinfos, idents, ast, renderer, semdata,
sighashes, lowerings, options, types, msgs, magicsys, tables, ccgutils
@@ -34,6 +34,7 @@ type
template destructor*(t: PType): PSym = getAttachedOp(c.g, t, attachedDestructor)
template assignment*(t: PType): PSym = getAttachedOp(c.g, t, attachedAsgn)
template dup*(t: PType): PSym = getAttachedOp(c.g, t, attachedDup)
template asink*(t: PType): PSym = getAttachedOp(c.g, t, attachedSink)
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode)
@@ -49,9 +50,9 @@ proc at(a, i: PNode, elemType: PType): PNode =
result[1] = i
result.typ = elemType
proc destructorOverriden(g: ModuleGraph; t: PType): bool =
proc destructorOverridden(g: ModuleGraph; t: PType): bool =
let op = getAttachedOp(g, t, attachedDestructor)
op != nil and sfOverriden in op.flags
op != nil and sfOverridden in op.flags
proc fillBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
for i in 0..<t.len:
@@ -82,14 +83,14 @@ proc genBuiltin(c: var TLiftCtx; magic: TMagic; name: string; i: PNode): PNode =
result = genBuiltin(c.g, c.idgen, magic, name, i)
proc defaultOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink}:
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink, attachedDup}:
body.add newAsgnStmt(x, y)
elif c.kind == attachedDestructor and c.addMemReset:
let call = genBuiltin(c, mDefault, "default", x)
call.typ = t
body.add newAsgnStmt(x, call)
elif c.kind == attachedWasMoved:
body.add genBuiltin(c, mWasMoved, "wasMoved", x)
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
proc genAddr(c: var TLiftCtx; x: PNode): PNode =
if x.kind == nkHiddenDeref:
@@ -139,11 +140,14 @@ proc genContainerOf(c: var TLiftCtx; objType: PType, field, x: PSym): PNode =
proc destructorCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
var destroy = newNodeIT(nkCall, x.info, op.typ[0])
destroy.add(newSymNode(op))
destroy.add genAddr(c, x)
if op.typ[1].kind != tyVar:
destroy.add x
else:
destroy.add genAddr(c, x)
if sfNeverRaises notin op.flags:
c.canRaise = true
if c.addMemReset:
result = newTree(nkStmtList, destroy, genBuiltin(c, mWasMoved, "wasMoved", x))
result = newTree(nkStmtList, destroy, genBuiltin(c, mWasMoved, "`=wasMoved`", x))
else:
result = destroy
@@ -158,8 +162,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
if c.filterDiscriminator != nil: return
let f = n.sym
let b = if c.kind == attachedTrace: y else: y.dotField(f)
if (sfCursor in f.flags and f.typ.skipTypes(abstractInst).kind in {tyRef, tyProc} and
c.g.config.selectedGC in {gcArc, gcOrc, gcHooks}) or
if (sfCursor in f.flags and c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcHooks}) or
enforceDefaultOp:
defaultOp(c, f.typ, body, x.dotField(f), b)
else:
@@ -243,7 +246,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
# for every field (dependent on dest.kind):
# `=` dest.field, src.field
# =destroy(blob)
var dummy = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId c.idgen, c.fn, c.info)
var dummy = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
dummy.typ = y.typ
if ccgIntroducedPtr(c.g.config, dummy, y.typ):
# Because of potential aliasing when the src param is passed by ref, we need to check for equality here,
@@ -252,7 +255,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x), newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y))
cond.typ = getSysType(c.g, x.info, tyBool)
body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info)))
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId c.idgen, c.fn, c.info)
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
temp.typ = x.typ
incl(temp.flags, sfFromGeneric)
var v = newNodeI(nkVarSection, c.info)
@@ -262,7 +265,7 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
#body.add newAsgnStmt(blob, x)
var wasMovedCall = newNodeI(nkCall, c.info)
wasMovedCall.add(newSymNode(createMagic(c.g, c.idgen, "wasMoved", mWasMoved)))
wasMovedCall.add(newSymNode(createMagic(c.g, c.idgen, "`=wasMoved`", mWasMoved)))
wasMovedCall.add x # mWasMoved does not take the address
body.add wasMovedCall
@@ -283,7 +286,7 @@ proc boolLit*(g: ModuleGraph; info: TLineInfo; value: bool): PNode =
result.typ = getSysType(g, info, tyBool)
proc getCycleParam(c: TLiftCtx): PNode =
assert c.kind == attachedAsgn
assert c.kind in {attachedAsgn, attachedDup}
if c.fn.typ.len == 4:
result = c.fn.typ.n.lastSon
assert result.kind == nkSym
@@ -298,7 +301,7 @@ proc newHookCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
result.add newSymNode(op)
if sfNeverRaises notin op.flags:
c.canRaise = true
if op.typ.sons[1].kind == tyVar:
if op.typ[1].kind == tyVar:
result.add genAddr(c, x)
else:
result.add x
@@ -322,6 +325,9 @@ proc newOpCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
proc newDeepCopyCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
result = newAsgnStmt(x, newOpCall(c, op, y))
proc newDupCall(c: var TLiftCtx; op: PSym; x, y: PNode): PNode =
result = newAsgnStmt(x, newOpCall(c, op, y))
proc usesBuiltinArc(t: PType): bool =
proc wrap(t: PType): bool {.nimcall.} = ast.isGCedMem(t)
result = types.searchTypeFor(t, wrap)
@@ -346,9 +352,9 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
field: var PSym): bool =
if optSeqDestructors in c.g.config.globalOptions:
var op = field
let destructorOverriden = destructorOverriden(c.g, t)
let destructorOverridden = destructorOverridden(c.g, t)
if op != nil and op != c.fn and
(sfOverriden in op.flags or destructorOverriden):
(sfOverridden in op.flags or destructorOverridden):
if sfError in op.flags:
incl c.fn.flags, sfError
#else:
@@ -356,10 +362,12 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
onUse(c.info, op)
body.add newHookCall(c, op, x, y)
result = true
elif op == nil and destructorOverriden:
elif op == nil and destructorOverridden:
op = produceSym(c.g, c.c, t, c.kind, c.info, c.idgen)
body.add newHookCall(c, op, x, y)
result = true
else:
result = false
elif tfHasAsgn in t.flags:
var op: PSym
if sameType(t, c.asgnForType):
@@ -389,12 +397,14 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
assert op.ast[genericParamsPos].kind == nkEmpty
body.add newHookCall(c, op, x, y)
result = true
else:
result = false
proc addDestructorCall(c: var TLiftCtx; orig: PType; body, x: PNode) =
let t = orig.skipTypes(abstractInst - {tyDistinct})
var op = t.destructor
if op != nil and sfOverriden in op.flags:
if op != nil and sfOverridden in op.flags:
if op.ast.isGenericRoutine:
# patch generic destructor:
op = instantiateGeneric(c, op, t, t.typeInst)
@@ -417,7 +427,7 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
case c.kind
of attachedDestructor:
var op = t.destructor
if op != nil and sfOverriden in op.flags:
if op != nil and sfOverridden in op.flags:
if op.ast.isGenericRoutine:
# patch generic destructor:
@@ -428,10 +438,12 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
onUse(c.info, op)
body.add destructorCall(c, op, x)
result = true
else:
result = false
#result = addDestructorCall(c, t, body, x)
of attachedAsgn, attachedSink, attachedTrace:
var op = getAttachedOp(c.g, t, c.kind)
if op != nil and sfOverriden in op.flags:
if op != nil and sfOverridden in op.flags:
if op.ast.isGenericRoutine:
# patch generic =trace:
op = instantiateGeneric(c, op, t, t.typeInst)
@@ -448,10 +460,12 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
onUse(c.info, op)
body.add newDeepCopyCall(c, op, x, y)
result = true
else:
result = false
of attachedWasMoved:
var op = getAttachedOp(c.g, t, attachedWasMoved)
if op != nil and sfOverriden in op.flags:
if op != nil and sfOverridden in op.flags:
if op.ast.isGenericRoutine:
# patch generic destructor:
@@ -462,9 +476,27 @@ proc considerUserDefinedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
onUse(c.info, op)
body.add genWasMovedCall(c, op, x)
result = true
else:
result = false
of attachedDup:
var op = getAttachedOp(c.g, t, attachedDup)
if op != nil and sfOverridden in op.flags:
if op.ast.isGenericRoutine:
# patch generic destructor:
op = instantiateGeneric(c, op, t, t.typeInst)
setAttachedOp(c.g, c.idgen.module, t, attachedDup, op)
#markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op)
body.add newDupCall(c, op, x, y)
result = true
else:
result = false
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId(c.idgen), c.fn, c.info)
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
temp.typ = getSysType(c.g, body.info, tyInt)
incl(temp.flags, sfFromGeneric)
@@ -474,7 +506,7 @@ proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
body.add v
proc declareTempOf(c: var TLiftCtx; body: PNode; value: PNode): PNode =
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), nextSymId(c.idgen), c.fn, c.info)
var temp = newSym(skTemp, getIdent(c.g.cache, lowerings.genPrefix), c.idgen, c.fn, c.info)
temp.typ = value.typ
incl(temp.flags, sfFromGeneric)
@@ -521,14 +553,28 @@ proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) =
else:
body.sons.setLen counterIdx
proc checkSelfAssignment(c: var TLiftCtx; t: PType; body, x, y: PNode) =
var cond = callCodegenProc(c.g, "sameSeqPayload", c.info,
newTreeIT(nkAddr, c.info, makePtrType(c.fn, x.typ, c.idgen), x),
newTreeIT(nkAddr, c.info, makePtrType(c.fn, y.typ, c.idgen), y)
)
cond.typ = getSysType(c.g, c.info, tyBool)
body.add genIf(c, cond, newTreeI(nkReturnStmt, c.info, newNodeI(nkEmpty, c.info)))
proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
of attachedDup:
body.add setLenSeqCall(c, t, x, y)
forallElements(c, t, body, x, y)
of attachedAsgn, attachedDeepCopy:
# we generate:
# if x.p == y.p:
# return
# setLen(dest, y.len)
# var i = 0
# while i < y.len: dest[i] = y[i]; inc(i)
# This is usually more efficient than a destroy/create pair.
checkSelfAssignment(c, t, body, x, y)
body.add setLenSeqCall(c, t, x, y)
forallElements(c, t, body, x, y)
of attachedSink:
@@ -542,17 +588,17 @@ proc fillSeqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
forallElements(c, t, body, x, y)
body.add genBuiltin(c, mDestroy, "destroy", x)
of attachedTrace:
if canFormAcycle(t.elemType):
if canFormAcycle(c.g, t.elemType):
# follow all elements:
forallElements(c, t, body, x, y)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
createTypeBoundOps(c.g, c.c, t, body.info, c.idgen)
# recursions are tricky, so we might need to forward the generated
# operation here:
var t = t
if t.assignment == nil or t.destructor == nil:
if t.assignment == nil or t.destructor == nil or t.dup == nil:
let h = sighashes.hashType(t,c.g.config, {CoType, CoConsiderOwned, CoDistinct})
let canon = c.g.canonTypes.getOrDefault(h)
if canon != nil: t = canon
@@ -578,16 +624,22 @@ proc useSeqOrStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
doAssert t.destructor != nil
body.add destructorCall(c, t.destructor, x)
of attachedTrace:
if t.kind != tyString and canFormAcycle(t.elemType):
if t.kind != tyString and canFormAcycle(c.g, t.elemType):
let op = getAttachedOp(c.g, t, c.kind)
if op == nil:
return # protect from recursion
body.add newHookCall(c, op, x, y)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedDup:
# XXX: replace these with assertions.
let op = getAttachedOp(c.g, t, c.kind)
if op == nil:
return # protect from recursion
body.add newDupCall(c, op, x, y)
proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
of attachedAsgn, attachedDeepCopy:
of attachedAsgn, attachedDeepCopy, attachedDup:
body.add callCodegenProc(c.g, "nimAsgnStrV2", c.info, genAddr(c, x), y)
of attachedSink:
let moveCall = genBuiltin(c, mMove, "move", x)
@@ -599,11 +651,11 @@ proc fillStrOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genBuiltin(c, mDestroy, "destroy", x)
of attachedTrace:
discard "strings are atomic and have no inner elements that are to trace"
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
proc cyclicType*(t: PType): bool =
proc cyclicType*(g: ModuleGraph, t: PType): bool =
case t.kind
of tyRef: result = types.canFormAcycle(t.lastSon)
of tyRef: result = types.canFormAcycle(g, t.lastSon)
of tyProc: result = t.callConv == ccClosure
else: result = false
@@ -631,7 +683,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let elemType = t.lastSon
createTypeBoundOps(c.g, c.c, elemType, c.info, c.idgen)
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(elemType)
let isCyclic = c.g.config.selectedGC == gcOrc and types.canFormAcycle(c.g, elemType)
let isInheritableAcyclicRef = c.g.config.selectedGC == gcOrc and
(not isPureObject(elemType)) and
@@ -639,7 +691,7 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# dynamic Acyclic refs need to use dyn decRef
let tmp =
if isCyclic and c.kind in {attachedAsgn, attachedSink}:
if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}:
declareTempOf(c, body, x)
else:
x
@@ -698,8 +750,16 @@ proc atomicRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# If the ref is polymorphic we have to account for this
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(x, c.idgen), y)
#echo "can follow ", elemType, " static ", isFinal(elemType)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
of attachedDup:
if isCyclic:
body.add newAsgnStmt(x, y)
body.add genIf(c, y, callCodegenProc(c.g,
"nimIncRefCyclic", c.info, y, getCycleParam(c)))
else:
body.add newAsgnStmt(x, y)
body.add genIf(c, y, callCodegenProc(c.g,
"nimIncRef", c.info, y))
proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
## Closures are really like refs except they always use a virtual destructor
@@ -709,7 +769,7 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let isCyclic = c.g.config.selectedGC == gcOrc
let tmp =
if isCyclic and c.kind in {attachedAsgn, attachedSink}:
if isCyclic and c.kind in {attachedAsgn, attachedSink, attachedDup}:
declareTempOf(c, body, xenv)
else:
xenv
@@ -743,12 +803,21 @@ proc atomicClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, cond, actions)
body.add newAsgnStmt(x, y)
of attachedDup:
let yenv = genBuiltin(c, mAccessEnv, "accessEnv", y)
yenv.typ = getSysType(c.g, c.info, tyPointer)
if isCyclic:
body.add newAsgnStmt(x, y)
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRefCyclic", c.info, yenv, getCycleParam(c)))
else:
body.add newAsgnStmt(x, y)
body.add genIf(c, yenv, callCodegenProc(c.g, "nimIncRef", c.info, yenv))
of attachedDestructor:
body.add genIf(c, cond, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace:
body.add callCodegenProc(c.g, "nimTraceRefDyn", c.info, genAddrOf(xenv, c.idgen), y)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case c.kind
@@ -761,6 +830,9 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y))
body.add genIf(c, x, callCodegenProc(c.g, "nimDecWeakRef", c.info, x))
body.add newAsgnStmt(x, y)
of attachedDup:
body.add newAsgnStmt(x, y)
body.add genIf(c, y, callCodegenProc(c.g, "nimIncRef", c.info, y))
of attachedDestructor:
# it's better to prepend the destruction of weak refs in order to
# prevent wrong "dangling refs exist" problems:
@@ -773,7 +845,7 @@ proc weakrefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.sons.insert(des, 0)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
var actions = newNodeI(nkStmtList, c.info)
@@ -795,11 +867,13 @@ proc ownedRefOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of attachedSink, attachedAsgn:
body.add genIf(c, x, actions)
body.add newAsgnStmt(x, y)
of attachedDup:
body.add newAsgnStmt(x, y)
of attachedDestructor:
body.add genIf(c, x, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
if c.kind == attachedDeepCopy:
@@ -811,7 +885,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
call[1] = y
body.add newAsgnStmt(x, call)
elif (optOwnedRefs in c.g.config.globalOptions and
optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcOrc}:
optRefCheck in c.g.config.options) or c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc}:
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
xx.typ = getSysType(c.g, c.info, tyPointer)
case c.kind
@@ -826,6 +900,11 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy))
body.add genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
body.add newAsgnStmt(x, y)
of attachedDup:
let yy = genBuiltin(c, mAccessEnv, "accessEnv", y)
yy.typ = getSysType(c.g, c.info, tyPointer)
body.add newAsgnStmt(x, y)
body.add genIf(c, yy, callCodegenProc(c.g, "nimIncRef", c.info, yy))
of attachedDestructor:
let des = genIf(c, xx, callCodegenProc(c.g, "nimDecWeakRef", c.info, xx))
if body.len == 0:
@@ -834,7 +913,7 @@ proc closureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
body.sons.insert(des, 0)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let xx = genBuiltin(c, mAccessEnv, "accessEnv", x)
@@ -846,11 +925,13 @@ proc ownedClosureOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of attachedSink, attachedAsgn:
body.add genIf(c, xx, actions)
body.add newAsgnStmt(x, y)
of attachedDup:
body.add newAsgnStmt(x, y)
of attachedDestructor:
body.add genIf(c, xx, actions)
of attachedDeepCopy: assert(false, "cannot happen")
of attachedTrace: discard
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "wasMoved", x)
of attachedWasMoved: body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case t.kind
@@ -859,7 +940,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
tyPtr, tyUncheckedArray, tyVar, tyLent:
defaultOp(c, t, body, x, y)
of tyRef:
if c.g.config.selectedGC in {gcArc, gcOrc}:
if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
atomicRefOp(c, t, body, x, y)
elif (optOwnedRefs in c.g.config.globalOptions and
optRefCheck in c.g.config.options):
@@ -868,7 +949,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
defaultOp(c, t, body, x, y)
of tyProc:
if t.callConv == ccClosure:
if c.g.config.selectedGC in {gcArc, gcOrc}:
if c.g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
atomicClosureOp(c, t, body, x, y)
else:
closureOp(c, t, body, x, y)
@@ -914,10 +995,25 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
defaultOp(c, t, body, x, y)
of tyObject:
if not considerUserDefinedOp(c, t, body, x, y):
if c.kind in {attachedAsgn, attachedSink} and t.sym != nil and sfImportc in t.sym.flags:
body.add newAsgnStmt(x, y)
if t.sym != nil and sfImportc in t.sym.flags:
case c.kind
of {attachedAsgn, attachedSink, attachedDup}:
body.add newAsgnStmt(x, y)
of attachedWasMoved:
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x)
else:
fillBodyObjT(c, t, body, x, y)
else:
fillBodyObjT(c, t, body, x, y)
if c.kind == attachedDup:
var op2 = getAttachedOp(c.g, t, attachedAsgn)
if op2 != nil and sfOverridden in op2.flags:
#markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op2)
body.add newHookCall(c, t.assignment, x, y)
else:
fillBodyObjT(c, t, body, x, y)
else:
fillBodyObjT(c, t, body, x, y)
of tyDistinct:
if not considerUserDefinedOp(c, t, body, x, y):
fillBody(c, t[0], body, x, y)
@@ -938,7 +1034,7 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
of tyOrdinal, tyRange, tyInferred,
tyGenericInst, tyAlias, tySink:
fillBody(c, lastSon(t), body, x, y)
of tyConcept, tyIterable: doAssert false
of tyConcept, tyIterable: raiseAssert "unreachable"
proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
kind: TTypeAttachedOp; info: TLineInfo;
@@ -950,15 +1046,56 @@ proc produceSymDistinctType(g: ModuleGraph; c: PContext; typ: PType;
result = getAttachedOp(g, baseType, kind)
setAttachedOp(g, idgen.module, typ, kind, result)
proc symDupPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator): PSym =
let procname = getIdent(g.cache, AttachedOpToStr[kind])
result = newSym(skProc, procname, idgen, owner, info)
let res = newSym(skResult, getIdent(g.cache, "result"), idgen, result, info)
let src = newSym(skParam, getIdent(g.cache, "src"),
idgen, result, info)
res.typ = typ
src.typ = typ
result.typ = newType(tyProc, nextTypeId idgen, owner)
result.typ.n = newNodeI(nkFormalParams, info)
rawAddSon(result.typ, res.typ)
result.typ.n.add newNodeI(nkEffectList, info)
result.typ.addParam src
if g.config.selectedGC == gcOrc and
cyclicType(g, typ.skipTypes(abstractInst)):
let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"),
idgen, result, info)
cycleParam.typ = getSysType(g, info, tyBool)
result.typ.addParam cycleParam
var n = newNodeI(nkProcDef, info, bodyPos+2)
for i in 0..<n.len: n[i] = newNodeI(nkEmpty, info)
n[namePos] = newSymNode(result)
n[paramsPos] = result.typ.n
n[bodyPos] = newNodeI(nkStmtList, info)
n[resultPos] = newSymNode(res)
result.ast = n
incl result.flags, sfFromGeneric
incl result.flags, sfGeneratedOp
proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp;
info: TLineInfo; idgen: IdGenerator): PSym =
if kind == attachedDup:
return symDupPrototype(g, typ, owner, kind, info, idgen)
let procname = getIdent(g.cache, AttachedOpToStr[kind])
result = newSym(skProc, procname, nextSymId(idgen), owner, info)
let dest = newSym(skParam, getIdent(g.cache, "dest"), nextSymId(idgen), result, info)
result = newSym(skProc, procname, idgen, owner, info)
let dest = newSym(skParam, getIdent(g.cache, "dest"), idgen, result, info)
let src = newSym(skParam, getIdent(g.cache, if kind == attachedTrace: "env" else: "src"),
nextSymId(idgen), result, info)
dest.typ = makeVarType(typ.owner, typ, idgen)
idgen, result, info)
if kind == attachedDestructor and typ.kind in {tyRef, tyString, tySequence} and g.config.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
dest.typ = typ
else:
dest.typ = makeVarType(typ.owner, typ, idgen)
if kind == attachedTrace:
src.typ = getSysType(g, info, tyPointer)
else:
@@ -970,9 +1107,9 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
result.typ.addParam src
if kind == attachedAsgn and g.config.selectedGC == gcOrc and
cyclicType(typ.skipTypes(abstractInst)):
cyclicType(g, typ.skipTypes(abstractInst)):
let cycleParam = newSym(skParam, getIdent(g.cache, "cyclic"),
nextSymId(idgen), result, info)
idgen, result, info)
cycleParam.typ = getSysType(g, info, tyBool)
result.typ.addParam cycleParam
@@ -984,6 +1121,9 @@ proc symPrototype(g: ModuleGraph; typ: PType; owner: PSym; kind: TTypeAttachedOp
result.ast = n
incl result.flags, sfFromGeneric
incl result.flags, sfGeneratedOp
if kind == attachedWasMoved:
incl result.flags, sfNoSideEffect
incl result.typ.flags, tfNoSideEffect
proc genTypeFieldCopy(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let xx = genBuiltin(c, mAccessTypeField, "accessTypeField", x)
@@ -1004,22 +1144,25 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
var a = TLiftCtx(info: info, g: g, kind: kind, c: c, asgnForType: typ, idgen: idgen,
fn: result)
let dest = result.typ.n[1].sym
let d = newDeref(newSymNode(dest))
let src = if kind in {attachedDestructor, attachedWasMoved}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
let dest = if kind == attachedDup: result.ast[resultPos].sym else: result.typ.n[1].sym
let d = if result.typ[1].kind == tyVar: newDeref(newSymNode(dest)) else: newSymNode(dest)
let src = case kind
of {attachedDestructor, attachedWasMoved}: newNodeIT(nkSym, info, getSysType(g, info, tyPointer))
of attachedDup: newSymNode(result.typ.n[1].sym)
else: newSymNode(result.typ.n[2].sym)
# register this operation already:
setAttachedOpPartial(g, idgen.module, typ, kind, result)
if kind == attachedSink and destructorOverriden(g, typ):
if kind == attachedSink and destructorOverridden(g, typ):
## compiler can use a combination of `=destroy` and memCopy for sink op
dest.flags.incl sfCursor
result.ast[bodyPos].add newOpCall(a, getAttachedOp(g, typ, attachedDestructor), d[0])
let op = getAttachedOp(g, typ, attachedDestructor)
result.ast[bodyPos].add newOpCall(a, op, if op.typ[1].kind == tyVar: d[0] else: d)
result.ast[bodyPos].add newAsgnStmt(d, src)
else:
var tk: TTypeKind
if g.config.selectedGC in {gcArc, gcOrc, gcHooks}:
if g.config.selectedGC in {gcArc, gcOrc, gcHooks, gcAtomicArc}:
tk = skipTypes(typ, {tyOrdinal, tyRange, tyInferred, tyGenericInst, tyStatic, tyAlias, tySink}).kind
else:
tk = tyNone # no special casing for strings and seqs
@@ -1030,7 +1173,7 @@ proc produceSym(g: ModuleGraph; c: PContext; typ: PType; kind: TTypeAttachedOp;
fillStrOp(a, typ, result.ast[bodyPos], d, src)
else:
fillBody(a, typ, result.ast[bodyPos], d, src)
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy} and not lacksMTypeField(typ):
if tk == tyObject and a.kind in {attachedAsgn, attachedSink, attachedDeepCopy, attachedDup} and not lacksMTypeField(typ):
# bug #19205: Do not forget to also copy the hidden type field:
genTypeFieldCopy(a, typ, result.ast[bodyPos], d, src)
@@ -1049,7 +1192,7 @@ proc produceDestructorForDiscriminator*(g: ModuleGraph; typ: PType; field: PSym,
a.addMemReset = true
let discrimantDest = result.typ.n[1].sym
let dst = newSym(skVar, getIdent(g.cache, "dest"), nextSymId(idgen), result, info)
let dst = newSym(skVar, getIdent(g.cache, "dest"), idgen, result, info)
dst.typ = makePtrType(typ.owner, typ, idgen)
let dstSym = newSymNode(dst)
let d = newDeref(dstSym)
@@ -1075,7 +1218,7 @@ proc patchBody(g: ModuleGraph; c: PContext; n: PNode; info: TLineInfo; idgen: Id
if op != nil:
if op.ast.isGenericRoutine:
internalError(g.config, info, "resolved destructor is generic")
if op.magic == mDestroy:
if op.magic == mDestroy and t.kind != tyString:
internalError(g.config, info, "patching mDestroy with mDestroy?")
n[0] = newSymNode(op)
for x in n: patchBody(g, c, x, info, idgen)
@@ -1128,7 +1271,7 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
# bug #15122: We need to produce all prototypes before entering the
# mind boggling recursion. Hacks like these imply we should rewrite
# this module.
var generics: array[attachedWasMoved..attachedTrace, bool]
var generics: array[attachedWasMoved..attachedTrace, bool] = default(array[attachedWasMoved..attachedTrace, bool])
for k in attachedWasMoved..lastAttached:
generics[k] = getAttachedOp(g, canon, k) != nil
if not generics[k]:

View File

@@ -49,6 +49,7 @@ proc liftLocals(n: PNode; i: int; c: var Ctx) =
liftLocals(it, i, c)
proc lookupParam(params, dest: PNode): PSym =
result = nil
if dest.kind != nkIdent: return nil
for i in 1..<params.len:
if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id:

View File

@@ -7,8 +7,8 @@
# distribution, for details about the copyright.
#
## This module contains the ``TMsgKind`` enum as well as the
## ``TLineInfo`` object.
## This module contains the `TMsgKind` enum as well as the
## `TLineInfo` object.
import ropes, tables, pathutils, hashes
@@ -44,6 +44,7 @@ type
errRstSandboxedDirective,
errProveInit, # deadcode
errGenerated,
errFailedMove,
errUser,
# warnings
warnCannotOpenFile = "CannotOpenFile", warnOctalEscape = "OctalEscape",
@@ -83,16 +84,17 @@ type
warnCstringConv = "CStringConv",
warnPtrToCstringConv = "PtrToCstringConv",
warnEffect = "Effect",
warnCastSizes = "CastSizes"
warnCastSizes = "CastSizes", # deadcode
warnAboveMaxSizeSet = "AboveMaxSizeSet",
warnImplicitTemplateRedefinition = "ImplicitTemplateRedefinition",
warnUnnamedBreak = "UnnamedBreak",
warnStmtListLambda = "StmtListLambda",
warnBareExcept = "BareExcept",
warnImplicitDefaultValue = "ImplicitDefaultValue",
warnUser = "User",
# hints
hintSuccess = "Success", hintSuccessX = "SuccessX",
hintCC = "CC",
hintLineTooLong = "LineTooLong",
hintXDeclaredButNotUsed = "XDeclaredButNotUsed", hintDuplicateModuleImport = "DuplicateModuleImport",
hintXCannotRaiseY = "XCannotRaiseY", hintConvToBaseNotNeeded = "ConvToBaseNotNeeded",
hintConvFromXtoItselfNotNeeded = "ConvFromXtoItselfNotNeeded", hintExprAlwaysX = "ExprAlwaysX",
@@ -127,6 +129,7 @@ const
errRstSandboxedDirective: "disabled directive: '$1'",
errProveInit: "Cannot prove that '$1' is initialized.", # deadcode
errGenerated: "$1",
errFailedMove: "$1",
errUser: "$1",
warnCannotOpenFile: "cannot open '$1'",
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
@@ -184,17 +187,18 @@ const
warnCstringConv: "$1",
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; this will become a compile time error in the future",
warnEffect: "$1",
warnCastSizes: "$1",
warnCastSizes: "$1", # deadcode
warnAboveMaxSizeSet: "$1",
warnImplicitTemplateRedefinition: "template '$1' is implicitly redefined; this is deprecated, add an explicit .redefine pragma",
warnUnnamedBreak: "Using an unnamed break in a block is deprecated; Use a named block with a named break instead",
warnStmtListLambda: "statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead",
warnBareExcept: "$1",
warnImplicitDefaultValue: "$1",
warnUser: "$1",
hintSuccess: "operation successful: $#",
# keep in sync with `testament.isSuccess`
hintSuccessX: "$build\n$loc lines; ${sec}s; $mem; proj: $project; out: $output",
hintCC: "CC: $1",
hintLineTooLong: "line too long",
hintXDeclaredButNotUsed: "'$1' is declared but not used",
hintDuplicateModuleImport: "$1",
hintXCannotRaiseY: "$1",
@@ -244,7 +248,8 @@ type
TNoteKinds* = set[TNoteKind]
proc computeNotesVerbosity(): array[0..3, TNoteKinds] =
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv}
result = default(array[0..3, TNoteKinds])
result[3] = {low(TNoteKind)..high(TNoteKind)} - {warnObservableStores, warnResultUsed, warnAnyEnumConv, warnBareExcept}
result[2] = result[3] - {hintStackTrace, hintExtendedContext, hintDeclaredLoc, hintProcessingStmt}
result[1] = result[2] - {warnProveField, warnProveIndex,
warnGcUnsafe, hintPath, hintDependency, hintCodeBegin, hintCodeEnd,
@@ -275,7 +280,7 @@ type
# and parsed; usually "" but is used
# for 'nimsuggest'
hash*: string # the checksum of the file
dirty*: bool # for 'nimfix' / 'nimpretty' like tooling
dirty*: bool # for 'nimpretty' like tooling
when defined(nimpretty):
fullContent*: string
FileIndex* = distinct int32
@@ -306,7 +311,7 @@ proc `==`*(a, b: FileIndex): bool {.borrow.}
proc hash*(i: TLineInfo): Hash =
hash (i.line.int, i.col.int, i.fileIndex.int)
proc raiseRecoverableError*(msg: string) {.noinline.} =
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
raise newException(ERecoverableError, msg)
const
@@ -337,9 +342,8 @@ type
proc initMsgConfig*(): MsgConfig =
result.msgContext = @[]
result.lastError = unknownLineInfo
result.filenameToIndexTbl = initTable[string, FileIndex]()
result.fileInfos = @[]
result.errorOutputs = {eStdOut, eStdErr}
result = MsgConfig(msgContext: @[], lastError: unknownLineInfo,
filenameToIndexTbl: initTable[string, FileIndex](),
fileInfos: @[], errorOutputs: {eStdOut, eStdErr}
)
result.filenameToIndexTbl["???"] = FileIndex(-1)

View File

@@ -19,10 +19,12 @@ const
Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'}
proc identLen*(line: string, start: int): int =
result = 0
while start+result < line.len and line[start+result] in Letters:
inc result
proc `=~`(s: string, a: openArray[string]): bool =
result = false
for x in a:
if s.startsWith(x): return true
@@ -95,7 +97,7 @@ template styleCheckDef*(ctx: PContext; info: TLineInfo; sym: PSym; k: TSymKind)
if optStyleCheck in ctx.config.options and # ignore if styleChecks are off
{optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # check only if hint/error is enabled
hintName in ctx.config.notes and # ignore if name checks are not requested
ctx.config.belongsToProjectPackage(ctx.module) and # ignore foreign packages
ctx.config.belongsToProjectPackage(sym) and # ignore foreign packages
optStyleUsages notin ctx.config.globalOptions and # ignore if requested to only check name usage
sym.kind != skResult and # ignore `result`
sym.kind != skTemp and # ignore temporary variables created by the compiler
@@ -136,7 +138,7 @@ template styleCheckUse*(ctx: PContext; info: TLineInfo; sym: PSym) =
## Check symbol uses match their definition's style.
if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
hintName in ctx.config.notes and # ignore if name checks are not requested
ctx.config.belongsToProjectPackage(ctx.module) and # ignore foreign packages
ctx.config.belongsToProjectPackage(sym) and # ignore foreign packages
sym.kind != skTemp and # ignore temporary variables created by the compiler
sym.name.s[0] in Letters and # ignore operators TODO: what about unicode symbols???
sfAnon notin sym.flags: # ignore temporary variables created by the compiler
@@ -147,6 +149,10 @@ proc checkPragmaUseImpl(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragm
if pragmaName != wanted:
lintReport(conf, info, wanted, pragmaName)
template checkPragmaUse*(conf: ConfigRef; info: TLineInfo; w: TSpecialWord; pragmaName: string) =
if {optStyleHint, optStyleError} * conf.globalOptions != {}:
checkPragmaUseImpl(conf, info, w, pragmaName)
template checkPragmaUse*(ctx: PContext; info: TLineInfo; w: TSpecialWord; pragmaName: string, sym: PSym) =
## Check builtin pragma uses match their definition's style.
## Note: This only applies to builtin pragmas, not user pragmas.
if {optStyleHint, optStyleError} * ctx.config.globalOptions != {} and # ignore if styleChecks are off
hintName in ctx.config.notes and # ignore if name checks are not requested
(sym != nil and ctx.config.belongsToProjectPackage(sym)): # ignore foreign packages
checkPragmaUseImpl(ctx.config, info, w, pragmaName)

View File

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

View File

@@ -8,14 +8,14 @@
#
# This module implements lookup helpers.
import std/[algorithm, strutils]
import std/[algorithm, strutils, tables]
when defined(nimPreviewSlimSystem):
import std/assertions
import
intsets, ast, astalgo, idents, semdata, types, msgs, options,
renderer, nimfix/prettybase, lineinfos, modulegraphs, astmsgs, sets
renderer, lineinfos, modulegraphs, astmsgs, sets, wordrecg
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope)
@@ -72,7 +72,7 @@ proc addUniqueSym*(scope: PScope, s: PSym): PSym =
proc openScope*(c: PContext): PScope {.discardable.} =
result = PScope(parent: c.currentScope,
symbols: newStrTable(),
symbols: initStrTable(),
depthLevel: c.scopeDepth + 1)
c.currentScope = result
@@ -94,17 +94,6 @@ iterator localScopesFrom*(c: PContext; scope: PScope): PScope =
if s == c.topLevelScope: break
yield s
proc skipAlias*(s: PSym; n: PNode; conf: ConfigRef): PSym =
if s == nil or s.kind != skAlias:
result = s
else:
result = s.owner
if conf.cmd == cmdNimfix:
prettybase.replaceDeprecated(conf, n.info, s, result)
else:
message(conf, n.info, warnDeprecated, "use " & result.name.s & " instead; " &
s.name.s & " is deprecated")
proc isShadowScope*(s: PScope): bool {.inline.} =
s.parent != nil and s.parent.depthLevel == s.depthLevel
@@ -265,6 +254,41 @@ proc searchInScopesFilterBy*(c: PContext, s: PIdent, filter: TSymKinds): seq[PSy
if s.kind in filter:
result.add s
proc isAmbiguous*(c: PContext, s: PIdent, filter: TSymKinds, sym: var PSym): bool =
result = false
block outer:
for scope in allScopes(c.currentScope):
var ti: TIdentIter
var candidate = initIdentIter(ti, scope.symbols, s)
var scopeHasCandidate = false
while candidate != nil:
if candidate.kind in filter:
if scopeHasCandidate:
# 2 candidates in same scope, ambiguous
return true
else:
scopeHasCandidate = true
sym = candidate
candidate = nextIdentIter(ti, scope.symbols)
if scopeHasCandidate:
# scope had a candidate but wasn't ambiguous
return false
var importsHaveCandidate = false
var marked = initIntSet()
for im in c.imports.mitems:
for s in symbols(im, marked, s, c.graph):
if s.kind in filter:
if importsHaveCandidate:
# 2 candidates among imports, ambiguous
return true
else:
importsHaveCandidate = true
sym = s
if importsHaveCandidate:
# imports had a candidate but wasn't ambiguous
return false
proc errorSym*(c: PContext, n: PNode): PSym =
## creates an error symbol to avoid cascading errors (for IDE support)
var m = n
@@ -274,7 +298,7 @@ proc errorSym*(c: PContext, n: PNode): PSym =
considerQuotedIdent(c, m)
else:
getIdent(c.cache, "err:" & renderTree(m))
result = newSym(skError, ident, nextSymId(c.idgen), getCurrOwner(c), n.info, {})
result = newSym(skError, ident, c.idgen, getCurrOwner(c), n.info, {})
result.typ = errorType(c)
incl(result.flags, sfDiscardable)
# pretend it's from the top level scope to prevent cascading errors:
@@ -309,7 +333,7 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) =
var it: TTabIter
var s = initTabIter(it, scope.symbols)
var missingImpls = 0
var unusedSyms: seq[tuple[sym: PSym, key: string]]
var unusedSyms: seq[tuple[sym: PSym, key: string]] = @[]
while s != nil:
if sfForward in s.flags and s.kind notin {skType, skModule}:
# too many 'implementation of X' errors are annoying
@@ -340,17 +364,18 @@ proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string;
# xxx pending bootstrap >= 1.4, replace all those overloads with a single one:
# proc addDecl*(c: PContext, sym: PSym, info = sym.info, scope = c.currentScope) {.inline.} =
proc addDeclAt*(c: PContext; scope: PScope, sym: PSym, info: TLineInfo) =
if sym.name.s == "_": return
if sym.name.id == ord(wUnderscore): return
let conflict = scope.addUniqueSym(sym)
if conflict != nil:
if sym.kind == skModule and conflict.kind == skModule and
sym.position == conflict.position:
if sym.kind == skModule and conflict.kind == skModule:
# e.g.: import foo; import foo
# xxx we could refine this by issuing a different hint for the case
# where a duplicate import happens inside an include.
localError(c.config, info, hintDuplicateModuleImport,
"duplicate import of '$1'; previous import here: $2" %
[sym.name.s, c.config $ conflict.info])
if c.importModuleMap[sym.id] == c.importModuleMap[conflict.id]:
#only hints if the conflict is the actual module not just a shared name
localError(c.config, info, hintDuplicateModuleImport,
"duplicate import of '$1'; previous import here: $2" %
[sym.name.s, c.config $ conflict.info])
else:
wrongRedefinition(c, info, sym.name.s, conflict.info, errGenerated)
@@ -396,11 +421,12 @@ proc addOverloadableSymAt*(c: PContext; scope: PScope, fn: PSym) =
if fn.kind notin OverloadableSyms:
internalError(c.config, fn.info, "addOverloadableSymAt")
return
let check = strTableGet(scope.symbols, fn.name)
if check != nil and check.kind notin OverloadableSyms:
wrongRedefinition(c, fn.info, fn.name.s, check.info)
else:
scope.addSym(fn)
if fn.name.id != ord(wUnderscore):
let check = strTableGet(scope.symbols, fn.name)
if check != nil and check.kind notin OverloadableSyms:
wrongRedefinition(c, fn.info, fn.name.s, check.info)
else:
scope.addSym(fn)
proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
## adds an overloadable symbol on the scope and the interface if appropriate
@@ -413,7 +439,7 @@ proc openShadowScope*(c: PContext) =
## opens a shadow scope, just like any other scope except the depth is the
## same as the parent -- see `isShadowScope`.
c.currentScope = PScope(parent: c.currentScope,
symbols: newStrTable(),
symbols: initStrTable(),
depthLevel: c.scopeDepth)
proc closeShadowScope*(c: PContext) =
@@ -437,13 +463,6 @@ proc mergeShadowScope*(c: PContext) =
else:
c.addInterfaceDecl(sym)
when false:
# `nimfix` used to call `altSpelling` and prettybase.replaceDeprecated(n.info, ident, alt)
proc altSpelling(c: PContext, x: PIdent): PIdent =
case x.s[0]
of 'A'..'Z': result = getIdent(c.cache, toLowerAscii(x.s[0]) & x.s.substr(1))
of 'a'..'z': result = getIdent(c.cache, toLowerAscii(x.s[0]) & x.s.substr(1))
else: result = x
import std/editdistance, heapqueue
@@ -474,7 +493,7 @@ proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) =
for (sym, depth, isLocal) in allSyms(c):
let depth = -depth - 1
let dist = editDistance(name0, sym.name.s.nimIdentNormalize)
var msg: string
var msg: string = ""
msg.add "\n ($1, $2): '$3'" % [$dist, $depth, sym.name.s]
list.push SpellCandidate(dist: dist, depth: depth, msg: msg, sym: sym)
@@ -489,12 +508,9 @@ proc fixSpelling(c: PContext, n: PNode, ident: PIdent, result: var string) =
let e = list.pop()
if c.config.spellSuggestMax == spellSuggestSecretSauce:
const
smallThres = 2
maxCountForSmall = 4
# avoids ton of operator matches when mis-matching short symbols such as `i`
# other heuristics could be devised, such as only suggesting operators if `name0`
# is an operator (likewise with non-operators).
if e.dist > e0.dist or (name0.len <= smallThres and count >= maxCountForSmall): break
minLengthForSuggestion = 4
maxCount = 3 # avoids ton of matches; three counts for equal distances
if e.dist > e0.dist or count >= maxCount or name0.len < minLengthForSuggestion: break
elif count >= c.config.spellSuggestMax: break
if count == 0:
result.add "\ncandidates (edit distance, scope distance); see '--spellSuggest': "
@@ -507,6 +523,7 @@ proc errorUseQualifier(c: PContext; info: TLineInfo; s: PSym; amb: var bool): PS
var err = "ambiguous identifier: '" & s.name.s & "'"
var i = 0
var ignoredModules = 0
result = nil
for candidate in importedItems(c, s.name):
if i == 0: err.add " -- use one of the following:\n"
else: err.add "\n"
@@ -546,12 +563,16 @@ proc errorUseQualifier*(c: PContext; info:TLineInfo; choices: PNode) =
errorUseQualifier(c, info, candidates, prefix)
proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string, extra = "") =
var err = "undeclared identifier: '" & name & "'" & extra
if c.recursiveDep.len > 0:
err.add "\nThis might be caused by a recursive module dependency:\n"
err.add c.recursiveDep
# prevent excessive errors for 'nim check'
c.recursiveDep = ""
var err: string
if name == "_":
err = "the special identifier '_' is ignored in declarations and cannot be used"
else:
err = "undeclared identifier: '" & name & "'" & extra
if c.recursiveDep.len > 0:
err.add "\nThis might be caused by a recursive module dependency:\n"
err.add c.recursiveDep
# prevent excessive errors for 'nim check'
c.recursiveDep = ""
localError(c.config, info, errGenerated, err)
proc errorUndeclaredIdentifierHint*(c: PContext; n: PNode, ident: PIdent): PSym =
@@ -565,17 +586,17 @@ proc lookUp*(c: PContext, n: PNode): PSym =
var amb = false
case n.kind
of nkIdent:
result = searchInScopes(c, n.ident, amb).skipAlias(n, c.config)
result = searchInScopes(c, n.ident, amb)
if result == nil: result = errorUndeclaredIdentifierHint(c, n, n.ident)
of nkSym:
result = n.sym
of nkAccQuoted:
var ident = considerQuotedIdent(c, n)
result = searchInScopes(c, ident, amb).skipAlias(n, c.config)
result = searchInScopes(c, ident, amb)
if result == nil: result = errorUndeclaredIdentifierHint(c, n, ident)
else:
internalError(c.config, n.info, "lookUp")
return
return nil
if amb:
#contains(c.ambiguousSymbols, result.id):
result = errorUseQualifier(c, n.info, result, amb)
@@ -593,14 +614,16 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
var amb = false
var ident = considerQuotedIdent(c, n)
if checkModule in flags:
result = searchInScopes(c, ident, amb).skipAlias(n, c.config)
result = searchInScopes(c, ident, amb)
else:
let candidates = searchInScopesFilterBy(c, ident, allExceptModule) #.skipAlias(n, c.config)
let candidates = searchInScopesFilterBy(c, ident, allExceptModule)
if candidates.len > 0:
result = candidates[0]
amb = candidates.len > 1
if amb and checkAmbiguity in flags:
errorUseQualifier(c, n.info, candidates)
else:
result = nil
if result == nil:
let candidates = allPureEnumFields(c, ident)
if candidates.len > 0:
@@ -627,13 +650,20 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
ident = considerQuotedIdent(c, n[1])
if ident != nil:
if m == c.module:
result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n, c.config)
result = strTableGet(c.topLevelScope.symbols, ident)
else:
result = someSym(c.graph, m, ident).skipAlias(n, c.config)
if c.importModuleLookup.getOrDefault(m.name.id).len > 1:
var amb: bool
result = errorUseQualifier(c, n.info, m, amb)
else:
result = someSym(c.graph, m, ident)
if result == nil and checkUndeclared in flags:
result = errorUndeclaredIdentifierHint(c, n[1], ident)
elif n[1].kind == nkSym:
result = n[1].sym
if result.owner != nil and result.owner != m and checkUndeclared in flags:
# dotExpr in templates can end up here
result = errorUndeclaredIdentifierHint(c, n[1], considerQuotedIdent(c, n[1]))
elif checkUndeclared in flags and
n[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
localError(c.config, n[1].info, "identifier expected, but got: " &
@@ -649,11 +679,12 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
o.marked = initIntSet()
case n.kind
of nkIdent, nkAccQuoted:
result = nil
var ident = considerQuotedIdent(c, n)
var scope = c.currentScope
o.mode = oimNoQualifier
while true:
result = initIdentIter(o.it, scope.symbols, ident).skipAlias(n, c.config)
result = initIdentIter(o.it, scope.symbols, ident)
if result != nil:
o.currentScope = scope
break
@@ -661,7 +692,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
scope = scope.parent
if scope == nil:
for i in 0..c.imports.high:
result = initIdentIter(o.mit, o.marked, c.imports[i], ident, c.graph).skipAlias(n, c.config)
result = initIdentIter(o.mit, o.marked, c.imports[i], ident, c.graph)
if result != nil:
o.currentScope = nil
o.importIdx = i
@@ -672,6 +703,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
result = n.sym
o.mode = oimDone
of nkDotExpr:
result = nil
o.mode = oimOtherModule
o.m = qualifiedLookUp(c, n[0], {checkUndeclared, checkModule})
if o.m != nil and o.m.kind == skModule:
@@ -684,10 +716,10 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
if o.m == c.module:
# a module may access its private members:
result = initIdentIter(o.it, c.topLevelScope.symbols,
ident).skipAlias(n, c.config)
ident)
o.mode = oimSelfModule
else:
result = initModuleIter(o.mit, c.graph, o.m, ident).skipAlias(n, c.config)
result = initModuleIter(o.mit, c.graph, o.m, ident)
else:
noidentError(c.config, n[1], n)
result = errorSym(c, n[1])
@@ -701,7 +733,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
o.symChoiceIndex = 1
o.marked = initIntSet()
incl(o.marked, result.id)
else: discard
else: result = nil
when false:
if result != nil and result.kind == skStub: loadStub(result)
@@ -716,11 +748,12 @@ proc lastOverloadScope*(o: TOverloadIter): int =
else: result = -1
proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym =
result = nil
assert o.currentScope == nil
var idx = o.importIdx+1
o.importIdx = c.imports.len # assume the other imported modules lack this symbol too
while idx < c.imports.len:
result = initIdentIter(o.mit, o.marked, c.imports[idx], o.it.name, c.graph).skipAlias(n, c.config)
result = initIdentIter(o.mit, o.marked, c.imports[idx], o.it.name, c.graph)
if result != nil:
# oh, we were wrong, some other module had the symbol, so remember that:
o.importIdx = idx
@@ -728,9 +761,10 @@ proc nextOverloadIterImports(o: var TOverloadIter, c: PContext, n: PNode): PSym
inc idx
proc symChoiceExtension(o: var TOverloadIter; c: PContext; n: PNode): PSym =
result = nil
assert o.currentScope == nil
while o.importIdx < c.imports.len:
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph).skipAlias(n, c.config)
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph)
#while result != nil and result.id in o.marked:
# result = nextIdentIter(o.it, o.marked, c.imports[o.importIdx])
if result != nil:
@@ -745,29 +779,29 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
of oimNoQualifier:
if o.currentScope != nil:
assert o.importIdx < 0
result = nextIdentIter(o.it, o.currentScope.symbols).skipAlias(n, c.config)
result = nextIdentIter(o.it, o.currentScope.symbols)
while result == nil:
o.currentScope = o.currentScope.parent
if o.currentScope != nil:
result = initIdentIter(o.it, o.currentScope.symbols, o.it.name).skipAlias(n, c.config)
result = initIdentIter(o.it, o.currentScope.symbols, o.it.name)
# BUGFIX: o.it.name <-> n.ident
else:
o.importIdx = 0
if c.imports.len > 0:
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph).skipAlias(n, c.config)
result = initIdentIter(o.mit, o.marked, c.imports[o.importIdx], o.it.name, c.graph)
if result == nil:
result = nextOverloadIterImports(o, c, n)
break
elif o.importIdx < c.imports.len:
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph).skipAlias(n, c.config)
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph)
if result == nil:
result = nextOverloadIterImports(o, c, n)
else:
result = nil
of oimSelfModule:
result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n, c.config)
result = nextIdentIter(o.it, c.topLevelScope.symbols)
of oimOtherModule:
result = nextModuleIter(o.mit, c.graph).skipAlias(n, c.config)
result = nextModuleIter(o.mit, c.graph)
of oimSymChoice:
if o.symChoiceIndex < n.len:
result = n[o.symChoiceIndex].sym
@@ -778,26 +812,28 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
o.mode = oimSymChoiceLocalLookup
o.currentScope = c.currentScope
result = firstIdentExcluding(o.it, o.currentScope.symbols,
n[0].sym.name, o.marked).skipAlias(n, c.config)
n[0].sym.name, o.marked)
while result == nil:
o.currentScope = o.currentScope.parent
if o.currentScope != nil:
result = firstIdentExcluding(o.it, o.currentScope.symbols,
n[0].sym.name, o.marked).skipAlias(n, c.config)
n[0].sym.name, o.marked)
else:
o.importIdx = 0
result = symChoiceExtension(o, c, n)
break
if result != nil:
incl o.marked, result.id
else:
result = nil
of oimSymChoiceLocalLookup:
if o.currentScope != nil:
result = nextIdentExcluding(o.it, o.currentScope.symbols, o.marked).skipAlias(n, c.config)
result = nextIdentExcluding(o.it, o.currentScope.symbols, o.marked)
while result == nil:
o.currentScope = o.currentScope.parent
if o.currentScope != nil:
result = firstIdentExcluding(o.it, o.currentScope.symbols,
n[0].sym.name, o.marked).skipAlias(n, c.config)
n[0].sym.name, o.marked)
else:
o.importIdx = 0
result = symChoiceExtension(o, c, n)
@@ -806,20 +842,23 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
incl o.marked, result.id
elif o.importIdx < c.imports.len:
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph).skipAlias(n, c.config)
result = nextIdentIter(o.mit, o.marked, c.imports[o.importIdx], c.graph)
#assert result.id notin o.marked
#while result != nil and result.id in o.marked:
# result = nextIdentIter(o.it, c.imports[o.importIdx]).skipAlias(n, c.config)
# result = nextIdentIter(o.it, c.imports[o.importIdx])
if result == nil:
inc o.importIdx
result = symChoiceExtension(o, c, n)
else:
result = nil
when false:
if result != nil and result.kind == skStub: loadStub(result)
proc pickSym*(c: PContext, n: PNode; kinds: set[TSymKind];
flags: TSymFlags = {}): PSym =
var o: TOverloadIter
result = nil
var o: TOverloadIter = default(TOverloadIter)
var a = initOverloadIter(o, c, n)
while a != nil:
if a.kind in kinds and flags <= a.flags:

View File

@@ -79,7 +79,7 @@ proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: P
if avoidTemp:
tempAsNode = value
else:
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen),
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), idgen,
owner, value.info, g.config.options)
temp.typ = skipTypes(value.typ, abstractInst)
incl(temp.flags, sfFromGeneric)
@@ -100,7 +100,7 @@ proc evalOnce*(g: ModuleGraph; value: PNode; idgen: IdGenerator; owner: PSym): P
## freely, multiple times. This is frequently required and such a builtin would also be
## handy to have in macros.nim. The value that can be reused is 'result.lastSon'!
result = newNodeIT(nkStmtListExpr, value.info, value.typ)
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), nextSymId(idgen),
var temp = newSym(skTemp, getIdent(g.cache, genPrefix), idgen,
owner, value.info, g.config.options)
temp.typ = skipTypes(value.typ, abstractInst)
incl(temp.flags, sfFromGeneric)
@@ -122,29 +122,10 @@ proc newTupleAccessRaw*(tup: PNode, i: int): PNode =
proc newTryFinally*(body, final: PNode): PNode =
result = newTree(nkHiddenTryStmt, body, newTree(nkFinally, final))
proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode =
let value = n.lastSon
result = newNodeI(nkStmtList, n.info)
var temp = newSym(skTemp, getIdent(g.cache, "_"), nextSymId(idgen), owner, value.info, owner.options)
var v = newNodeI(nkLetSection, value.info)
let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
var vpart = newNodeI(nkIdentDefs, tempAsNode.info, 3)
vpart[0] = tempAsNode
vpart[1] = newNodeI(nkEmpty, value.info)
vpart[2] = value
v.add vpart
result.add(v)
let lhs = n[0]
for i in 0..<lhs.len:
result.add newAsgnStmt(lhs[i], newTupleAccessRaw(tempAsNode, i))
proc lowerSwap*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode =
result = newNodeI(nkStmtList, n.info)
# note: cannot use 'skTemp' here cause we really need the copy for the VM :-(
var temp = newSym(skVar, getIdent(g.cache, genPrefix), nextSymId(idgen), owner, n.info, owner.options)
var temp = newSym(skVar, getIdent(g.cache, genPrefix), idgen, owner, n.info, owner.options)
temp.typ = n[1].typ
incl(temp.flags, sfFromGeneric)
incl(temp.flags, sfGenSym)
@@ -171,8 +152,7 @@ proc createObj*(g: ModuleGraph; idgen: IdGenerator; owner: PSym, info: TLineInfo
rawAddSon(result, getCompilerProc(g, "RootObj").typ)
result.n = newNodeI(nkRecList, info)
let s = newSym(skType, getIdent(g.cache, "Env_" & toFilename(g.config, info) & "_" & $owner.name.s),
nextSymId(idgen),
owner, info, owner.options)
idgen, owner, info, owner.options)
incl s.flags, sfAnon
s.typ = result
result.sym = s
@@ -234,10 +214,13 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym
# because of 'gensym' support, we have to mangle the name with its ID.
# This is hacky but the clean solution is much more complex than it looks.
var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len),
nextSymId(idgen), s.owner, s.info, s.options)
idgen, s.owner, s.info, s.options)
field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item)
let t = skipIntLit(s.typ, idgen)
field.typ = t
if s.kind in {skLet, skVar, skField, skForVar}:
#field.bitsize = s.bitsize
field.alignment = s.alignment
assert t.kind != tyTyped
propagateToOwner(obj, t)
field.position = obj.n.len
@@ -250,7 +233,7 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym
proc addUniqueField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym {.discardable.} =
result = lookupInRecord(obj.n, s.itemId)
if result == nil:
var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), nextSymId(idgen),
var field = newSym(skField, getIdent(cache, s.name.s & $obj.n.len), idgen,
s.owner, s.info, s.options)
field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item)
let t = skipIntLit(s.typ, idgen)
@@ -347,7 +330,8 @@ proc genDeref*(n: PNode; k = nkHiddenDeref): PNode =
proc callCodegenProc*(g: ModuleGraph; name: string;
info: TLineInfo = unknownLineInfo;
arg1, arg2, arg3, optionalArgs: PNode = nil): PNode =
arg1: PNode = nil, arg2: PNode = nil,
arg3: PNode = nil, optionalArgs: PNode = nil): PNode =
result = newNodeI(nkCall, info)
let sym = magicsys.getCompilerProc(g, name)
if sym == nil:

View File

@@ -26,11 +26,11 @@ proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym =
result = systemModuleSym(g, getIdent(g.cache, name))
if result == nil:
localError(g.config, info, "system module needs: " & name)
result = newSym(skError, getIdent(g.cache, name), nextSymId(g.idgen), g.systemModule, g.systemModule.info, {})
result = newSym(skError, getIdent(g.cache, name), g.idgen, g.systemModule, g.systemModule.info, {})
result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule)
if result.kind == skAlias: result = result.owner
proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym =
result = nil
let id = getIdent(g.cache, name)
for r in systemModuleSyms(g, id):
if r.magic == m:
@@ -39,7 +39,7 @@ proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSy
result = r
if result != nil: return result
localError(g.config, info, "system module needs: " & name)
result = newSym(skError, id, nextSymId(g.idgen), g.systemModule, g.systemModule.info, {})
result = newSym(skError, id, g.idgen, g.systemModule, g.systemModule.info, {})
result.typ = newType(tyError, nextTypeId(g.idgen), g.systemModule)
proc sysTypeFromName*(g: ModuleGraph; info: TLineInfo; name: string): PType =
@@ -81,8 +81,8 @@ proc getSysType*(g: ModuleGraph; info: TLineInfo; kind: TTypeKind): PType =
proc resetSysTypes*(g: ModuleGraph) =
g.systemModule = nil
initStrTable(g.compilerprocs)
initStrTable(g.exposed)
g.compilerprocs = initStrTable()
g.exposed = initStrTable()
for i in low(g.sysTypes)..high(g.sysTypes):
g.sysTypes[i] = nil
@@ -100,7 +100,7 @@ proc skipIntLit*(t: PType; id: IdGenerator): PType {.inline.} =
proc addSonSkipIntLit*(father, son: PType; id: IdGenerator) =
let s = son.skipIntLit(id)
father.sons.add(s)
father.add(s)
propagateToOwner(father, s)
proc getCompilerProc*(g: ModuleGraph; name: string): PSym =
@@ -124,7 +124,7 @@ proc registerNimScriptSymbol*(g: ModuleGraph; s: PSym) =
proc getNimScriptSymbol*(g: ModuleGraph; name: string): PSym =
strTableGet(g.exposed, getIdent(g.cache, name))
proc resetNimScriptSymbols*(g: ModuleGraph) = initStrTable(g.exposed)
proc resetNimScriptSymbols*(g: ModuleGraph) = g.exposed = initStrTable()
proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym =
case t.kind
@@ -146,6 +146,7 @@ proc getMagicEqSymForType*(g: ModuleGraph; t: PType; info: TLineInfo): PSym =
of tyProc:
result = getSysMagic(g, info, "==", mEqProc)
else:
result = nil
globalError(g.config, info,
"can't find magic equals operator for type kind " & $t.kind)

View File

@@ -13,7 +13,7 @@ when not defined(nimcore):
{.error: "nimcore MUST be defined for Nim's core tooling".}
import
std/[strutils, os, times, tables, sha1, with, json],
std/[strutils, os, times, tables, with, json],
llstream, ast, lexer, syntaxes, options, msgs,
condsyms,
idents, extccomp,
@@ -22,6 +22,8 @@ import
modules,
modulegraphs, lineinfos, pathutils, vmprofiler
# ensure NIR compiles:
import nir / nir
when defined(nimPreviewSlimSystem):
import std/[syncio, assertions]
@@ -29,6 +31,8 @@ when defined(nimPreviewSlimSystem):
import ic / [cbackend, integrity, navigator]
from ic / ic import rodViewer
import ../dist/checksums/src/checksums/sha1
import pipelines
when not defined(leanCompiler):
@@ -54,7 +58,7 @@ proc writeCMakeDepsFile(conf: ConfigRef) =
for it in conf.toCompile: cfiles.add(it.cname.string)
let fileset = cfiles.toCountTable()
# read old cfiles list
var fl: File
var fl: File = default(File)
var prevset = initCountTable[string]()
if open(fl, fname.string, fmRead):
for line in fl.lines: prevset.inc(line)
@@ -113,7 +117,7 @@ when not defined(leanCompiler):
setPipeLinePass(graph, Docgen2JsonPass)
of HtmlExt:
setPipeLinePass(graph, Docgen2Pass)
else: doAssert false, $ext
else: raiseAssert $ext
compilePipelineProject(graph)
proc commandCompileToC(graph: ModuleGraph) =
@@ -194,7 +198,7 @@ proc commandScan(cache: IdentCache, config: ConfigRef) =
if stream != nil:
var
L: Lexer
tok: Token
tok: Token = default(Token)
initToken(tok)
openLexer(L, f, stream, cache, config)
while true:
@@ -265,7 +269,7 @@ proc mainCommand*(graph: ModuleGraph) =
# and it has added this define implictly, so we must undo that here.
# A better solution might be to fix system.nim
undefSymbol(conf.symbols, "useNimRtl")
of backendInvalid: doAssert false
of backendInvalid: raiseAssert "unreachable"
proc compileToBackend() =
customizeForBackend(conf.backend)
@@ -275,7 +279,7 @@ proc mainCommand*(graph: ModuleGraph) =
of backendCpp: commandCompileToC(graph)
of backendObjc: commandCompileToC(graph)
of backendJs: commandCompileToJS(graph)
of backendInvalid: doAssert false
of backendInvalid: raiseAssert "unreachable"
template docLikeCmd(body) =
when defined(leanCompiler):
@@ -415,7 +419,7 @@ proc mainCommand*(graph: ModuleGraph) =
of cmdJsonscript:
setOutFile(graph.config)
commandJsonScript(graph)
of cmdUnknown, cmdNone, cmdIdeTools, cmdNimfix:
of cmdUnknown, cmdNone, cmdIdeTools:
rawMessage(conf, errGenerated, "invalid command: " & conf.command)
if conf.errorCounter == 0 and conf.cmd notin {cmdTcc, cmdDump, cmdNop}:

View File

@@ -11,7 +11,8 @@
## represents a complete Nim project. Single modules can either be kept in RAM
## or stored in a rod-file.
import intsets, tables, hashes, md5
import intsets, tables, hashes
import ../dist/checksums/src/checksums/md5
import ast, astalgo, options, lineinfos,idents, btrees, ropes, msgs, pathutils, packages
import ic / [packed_ast, ic]
@@ -78,6 +79,7 @@ type
procInstCache*: Table[ItemId, seq[LazyInstantiation]] # A symbol's ItemId.
attachedOps*: array[TTypeAttachedOp, Table[ItemId, LazySym]] # Type ID, destructors, etc.
methodsPerType*: Table[ItemId, seq[(int, LazySym)]] # Type ID, attached methods
memberProcsPerType*: Table[ItemId, seq[PSym]] # Type ID, attached member procs (only c++, virtual and ctor so far)
enumToStringProcs*: Table[ItemId, LazySym]
emittedTypeInfo*: Table[string, FileIndex]
@@ -140,7 +142,7 @@ type
isFrontend: bool]
proc resetForBackend*(g: ModuleGraph) =
initStrTable(g.compilerprocs)
g.compilerprocs = initStrTable()
g.typeInstCache.clear()
g.procInstCache.clear()
for a in mitems(g.attachedOps):
@@ -194,8 +196,8 @@ template semtabAll*(g: ModuleGraph, m: PSym): TStrTable =
g.ifaces[m.position].interfHidden
proc initStrTables*(g: ModuleGraph, m: PSym) =
initStrTable(semtab(g, m))
initStrTable(semtabAll(g, m))
semtab(g, m) = initStrTable()
semtabAll(g, m) = initStrTable()
proc strTableAdds*(g: ModuleGraph, m: PSym, s: PSym) =
strTableAdd(semtab(g, m), s)
@@ -366,6 +368,7 @@ proc copyTypeProps*(g: ModuleGraph; module: int; dest, src: PType) =
setAttachedOp(g, module, dest, k, op)
proc loadCompilerProc*(g: ModuleGraph; name: string): PSym =
result = nil
if g.config.symbolFiles == disabledSf: return nil
# slow, linear search, but the results are cached:
@@ -411,7 +414,7 @@ proc stopCompile*(g: ModuleGraph): bool {.inline.} =
result = g.doStopCompile != nil and g.doStopCompile()
proc createMagic*(g: ModuleGraph; idgen: IdGenerator; name: string, m: TMagic): PSym =
result = newSym(skProc, getIdent(g.cache, name), nextSymId(idgen), nil, unknownLineInfo, {})
result = newSym(skProc, getIdent(g.cache, name), idgen, nil, unknownLineInfo, {})
result.magic = m
result.flags = {sfNeverRaises}
@@ -456,7 +459,7 @@ proc initModuleGraphFields(result: ModuleGraph) =
# A module ID of -1 means that the symbol is not attached to a module at all,
# but to the module graph:
result.idgen = IdGenerator(module: -1'i32, symId: 0'i32, typeId: 0'i32)
initStrTable(result.packageSyms)
result.packageSyms = initStrTable()
result.deps = initIntSet()
result.importDeps = initTable[FileIndex, seq[FileIndex]]()
result.ifaces = @[]
@@ -466,9 +469,9 @@ proc initModuleGraphFields(result: ModuleGraph) =
result.suggestSymbols = initTable[FileIndex, seq[SymInfoPair]]()
result.suggestErrors = initTable[FileIndex, seq[Suggest]]()
result.methods = @[]
initStrTable(result.compilerprocs)
initStrTable(result.exposed)
initStrTable(result.packageTypes)
result.compilerprocs = initStrTable()
result.exposed = initStrTable()
result.packageTypes = initStrTable()
result.emptyNode = newNode(nkEmpty)
result.cacheSeqs = initTable[string, PNode]()
result.cacheCounters = initTable[string, BiggestInt]()
@@ -485,7 +488,7 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
initModuleGraphFields(result)
proc resetAllModules*(g: ModuleGraph) =
initStrTable(g.packageSyms)
g.packageSyms = initStrTable()
g.deps = initIntSet()
g.ifaces = @[]
g.importStack = @[]
@@ -493,11 +496,12 @@ proc resetAllModules*(g: ModuleGraph) =
g.usageSym = nil
g.owners = @[]
g.methods = @[]
initStrTable(g.compilerprocs)
initStrTable(g.exposed)
g.compilerprocs = initStrTable()
g.exposed = initStrTable()
initModuleGraphFields(g)
proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
result = nil
if fileIdx.int32 >= 0:
if isCachedModule(g, fileIdx.int32):
result = g.packed[fileIdx.int32].module
@@ -603,6 +607,7 @@ proc markClientsDirty*(g: ModuleGraph; fileIdx: FileIndex) =
proc needsCompilation*(g: ModuleGraph): bool =
# every module that *depends* on this file is also dirty:
result = false
for i in 0i32..<g.ifaces.len.int32:
let m = g.ifaces[i].module
if m != nil:
@@ -610,6 +615,7 @@ proc needsCompilation*(g: ModuleGraph): bool =
return true
proc needsCompilation*(g: ModuleGraph, fileIdx: FileIndex): bool =
result = false
let module = g.getModule(fileIdx)
if module != nil and g.isDirty(module):
return true
@@ -631,6 +637,8 @@ proc moduleFromRodFile*(g: ModuleGraph; fileIdx: FileIndex;
## Returns 'nil' if the module needs to be recompiled.
if g.config.symbolFiles in {readOnlySf, v2Sf, stressTest}:
result = moduleFromRodFile(g.packed, g.config, g.cache, fileIdx, cachedModules)
else:
result = nil
proc configComplete*(g: ModuleGraph) =
rememberStartupConfig(g.startupPackedConfig, g.config)

View File

@@ -226,7 +226,7 @@ proc setDirtyFile*(conf: ConfigRef; fileIdx: FileIndex; filename: AbsoluteFile)
proc setHash*(conf: ConfigRef; fileIdx: FileIndex; hash: string) =
assert fileIdx.int32 >= 0
when defined(gcArc) or defined(gcOrc):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
conf.m.fileInfos[fileIdx.int32].hash = hash
else:
shallowCopy(conf.m.fileInfos[fileIdx.int32].hash, hash)
@@ -234,7 +234,7 @@ proc setHash*(conf: ConfigRef; fileIdx: FileIndex; hash: string) =
proc getHash*(conf: ConfigRef; fileIdx: FileIndex): string =
assert fileIdx.int32 >= 0
when defined(gcArc) or defined(gcOrc):
when defined(gcArc) or defined(gcOrc) or defined(gcAtomicArc):
result = conf.m.fileInfos[fileIdx.int32].hash
else:
shallowCopy(result, conf.m.fileInfos[fileIdx.int32].hash)
@@ -294,9 +294,11 @@ proc toColumn*(info: TLineInfo): int {.inline.} =
result = info.col
proc toFileLineCol(info: InstantiationInfo): string {.inline.} =
result = ""
result.toLocation(info.filename, info.line, info.column + ColOffset)
proc toFileLineCol*(conf: ConfigRef; info: TLineInfo): string {.inline.} =
result = ""
result.toLocation(toMsgFilename(conf, info), info.line.int, info.col.int + ColOffset)
proc `$`*(conf: ConfigRef; info: TLineInfo): string = toFileLineCol(conf, info)
@@ -408,7 +410,7 @@ proc getMessageStr(msg: TMsgKind, arg: string): string = msgKindToString(msg) %
type TErrorHandling* = enum doNothing, doAbort, doRaise
proc log*(s: string) =
var f: File
var f: File = default(File)
if open(f, getHomeDir() / "nimsuggest.log", fmAppend):
f.writeLine(s)
close(f)
@@ -502,6 +504,8 @@ proc getSurroundingSrc(conf: ConfigRef; info: TLineInfo): string =
result = "\n" & indent & $sourceLine(conf, info)
if info.col >= 0:
result.add "\n" & indent & spaces(info.col) & '^'
else:
result = ""
proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): string =
let title = case msg
@@ -511,7 +515,8 @@ proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): s
conf.toFileLineCol(info) & " " & title & getMessageStr(msg, arg)
proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
eh: TErrorHandling, info2: InstantiationInfo, isRaw = false) {.gcsafe, noinline.} =
eh: TErrorHandling, info2: InstantiationInfo, isRaw = false,
ignoreError = false) {.gcsafe, noinline.} =
var
title: string
color: ForegroundColor
@@ -576,7 +581,8 @@ proc liMessage*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
" compiler msg initiated here", KindColor,
KindFormat % $hintMsgOrigin,
resetStyle, conf.unitSep)
handleError(conf, msg, eh, s, ignoreMsg)
if not ignoreError:
handleError(conf, msg, eh, s, ignoreMsg)
if msg in fatalMsgs:
# most likely would have died here but just in case, we restore state
conf.m.errorOutputs = errorOutputsOld

View File

@@ -309,6 +309,7 @@ proc symbol(n: PNode): Symbol =
# echo "symbol ", n, " ", n.kind, " ", result.int
func `$`(map: NilMap): string =
result = ""
var now = map
var stack: seq[NilMap] = @[]
while not now.isNil:
@@ -416,7 +417,7 @@ proc moveOut(ctx: NilCheckerContext, map: NilMap, target: PNode) =
if targetSetIndex != noSetIndex:
var targetSet = map.sets[targetSetIndex]
if targetSet.len > 1:
var other: ExprIndex
var other: ExprIndex = default(ExprIndex)
for element in targetSet:
if element.ExprIndex != targetIndex:
@@ -561,7 +562,7 @@ proc derefWarning(n, ctx, map; kind: Nilability) =
if n.info in ctx.warningLocations:
return
ctx.warningLocations.incl(n.info)
var a: seq[History]
var a: seq[History] = @[]
if n.kind == nkSym:
a = history(map, ctx.index(n))
var res = ""
@@ -765,7 +766,7 @@ proc checkIf(n, ctx, map): Check =
# the state of the conditions: negating conditions before the current one
var layerHistory = newNilMap(mapIf)
# the state after branch effects
var afterLayer: NilMap
var afterLayer: NilMap = nil
# the result nilability for expressions
var nilability = Safe
@@ -862,9 +863,10 @@ proc checkInfix(n, ctx, map): Check =
## a or b : map is an union of a and b's
## a == b : use checkCondition
## else: no change, just check args
result = default(Check)
if n[0].kind == nkSym:
var mapL: NilMap
var mapR: NilMap
var mapL: NilMap = nil
var mapR: NilMap = nil
if n[0].sym.magic notin {mAnd, mEqRef}:
mapL = checkCondition(n[1], ctx, map, false, false)
mapR = checkCondition(n[2], ctx, map, false, false)
@@ -909,7 +911,7 @@ proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode =
else: ""
var cache = newIdentCache()
var op = newSym(skVar, cache.getIdent(name), nextSymId ctx.idgen, nil, r.info)
var op = newSym(skVar, cache.getIdent(name), ctx.idgen, nil, r.info)
op.magic = magic
result = nkInfix.newTree(
@@ -920,7 +922,7 @@ proc infix(ctx: NilCheckerContext, l: PNode, r: PNode, magic: TMagic): PNode =
proc prefixNot(ctx: NilCheckerContext, node: PNode): PNode =
var cache = newIdentCache()
var op = newSym(skVar, cache.getIdent("not"), nextSymId ctx.idgen, nil, node.info)
var op = newSym(skVar, cache.getIdent("not"), ctx.idgen, nil, node.info)
op.magic = mNot
result = nkPrefix.newTree(
@@ -947,7 +949,7 @@ proc checkCase(n, ctx, map): Check =
let base = n[0]
result.map = map.copyMap()
result.nilability = Safe
var a: PNode
var a: PNode = nil
for child in n:
case child.kind:
of nkOfBranch:
@@ -1222,7 +1224,7 @@ proc check(n: PNode, ctx: NilCheckerContext, map: NilMap): Check =
# TODO deeper nested elements?
# A(field: B()) #
# field: Safe ->
var elements: seq[(PNode, Nilability)]
var elements: seq[(PNode, Nilability)] = @[]
for i, child in n:
result = check(child, ctx, result.map)
if i > 0:
@@ -1333,7 +1335,7 @@ proc preVisit(ctx: NilCheckerContext, s: PSym, body: PNode, conf: ConfigRef) =
ctx.symbolIndices = {resultId: resultExprIndex}.toTable()
var cache = newIdentCache()
ctx.expressions = SeqOfDistinct[ExprIndex, PNode](@[newIdentNode(cache.getIdent("result"), s.ast.info)])
var emptySet: IntSet # set[ExprIndex]
var emptySet: IntSet = initIntSet() # set[ExprIndex]
ctx.dependants = SeqOfDistinct[ExprIndex, IntSet](@[emptySet])
for i, arg in s.typ.n.sons:
if i > 0:

View File

@@ -7,6 +7,7 @@ define:nimcore
define:nimPreviewFloatRoundtrip
define:nimPreviewSlimSystem
define:nimPreviewCstringConversion
define:nimPreviewProcConversion
define:nimPreviewRangeDefault
threads:off
@@ -14,7 +15,6 @@ threads:off
@if windows:
cincludes: "$lib/wrappers/libffi/common"
tlsEmulation:off
@end
define:useStdoutAsStdmsg
@@ -31,9 +31,6 @@ define:useStdoutAsStdmsg
warning[ObservableStores]:off
@end
@if nimHasWarnCastSizes:
warning[CastSizes]:on
@end
@if nimHasWarningAsError:
warningAsError[GcUnsafe2]:on
@@ -46,3 +43,11 @@ define:useStdoutAsStdmsg
@if nimHasWarnBareExcept:
warningAserror[BareExcept]:on
@end
@if nimUseStrictDefs:
experimental:strictDefs
warningAsError[Uninit]:on
warningAsError[ProveInit]:on
@end

View File

@@ -12,10 +12,7 @@ import std/[os, strutils, parseopt]
when defined(nimPreviewSlimSystem):
import std/assertions
when defined(windows) and not defined(nimKochBootstrap):
# remove workaround pending bootstrap >= 1.5.1
# refs https://github.com/nim-lang/Nim/issues/18334#issuecomment-867114536
# alternative would be to prepend `currentSourcePath.parentDir.quoteShell`
when defined(windows):
when defined(gcc):
when defined(x86):
{.link: "../icons/nim.res".}
@@ -94,6 +91,9 @@ proc getNimRunExe(conf: ConfigRef): string =
if conf.isDefined("mingw"):
if conf.isDefined("i386"): result = "wine"
elif conf.isDefined("amd64"): result = "wine64"
else: result = ""
else:
result = ""
proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
let self = NimProg(
@@ -140,7 +140,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
# tasyncjs_fail` would fail, refs https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode
if cmdPrefix.len == 0: cmdPrefix = findNodeJs().quoteShell
cmdPrefix.add " --unhandled-rejections=strict"
else: doAssert false, $conf.backend
else: raiseAssert $conf.backend
if cmdPrefix.len > 0: cmdPrefix.add " "
# without the `cmdPrefix.len > 0` check, on windows you'd get a cryptic:
# `The parameter is incorrect`

View File

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

View File

@@ -214,7 +214,7 @@ proc parseAssignment(L: var Lexer, tok: var Token;
proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
config: ConfigRef): bool =
var
L: Lexer
L: Lexer = default(Lexer)
tok: Token
stream: PLLStream
stream = llStreamOpen(filename, fmRead)
@@ -228,6 +228,8 @@ proc readConfigFile*(filename: AbsoluteFile; cache: IdentCache;
if condStack.len > 0: lexMessage(L, errGenerated, "expected @end")
closeLexer(L)
return true
else:
result = false
proc getUserConfigPath*(filename: RelativeFile): AbsoluteFile =
result = getConfigDir().AbsoluteDir / RelativeDir"nim" / filename
@@ -250,7 +252,7 @@ proc loadConfigs*(cfg: RelativeFile; cache: IdentCache; conf: ConfigRef; idgen:
template runNimScriptIfExists(path: AbsoluteFile, isMain = false) =
let p = path # eval once
var s: PLLStream
var s: PLLStream = nil
if isMain and optWasNimscript in conf.globalOptions:
if conf.projectIsStdin: s = stdin.llStreamOpen
elif conf.projectIsCmd: s = llStreamOpen(conf.cmdInput)

View File

@@ -12,7 +12,7 @@ import
ast, modules, condsyms,
options, llstream, lineinfos, vm,
vmdef, modulegraphs, idents, os, pathutils,
scriptconfig, std/compilesettings
scriptconfig, std/[compilesettings, tables]
import pipelines
@@ -78,6 +78,9 @@ proc evalScript*(i: Interpreter; scriptStream: PLLStream = nil) =
assert i != nil
assert i.mainModule != nil, "no main module selected"
initStrTables(i.graph, i.mainModule)
i.graph.cacheSeqs.clear()
i.graph.cacheCounters.clear()
i.graph.cacheTables.clear()
i.mainModule.ast = nil
let s = if scriptStream != nil: scriptStream

View File

@@ -1,111 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Nimfix is a tool that helps to convert old-style Nimrod code to Nim code.
import strutils, os, parseopt
import compiler/[options, commands, modules, sem,
passes, passaux, linter,
msgs, nimconf,
extccomp, condsyms,
modulegraphs, idents]
const Usage = """
Nimfix - Tool to patch Nim code
Usage:
nimfix [options] projectfile.nim
Options:
--overwriteFiles:on|off overwrite the original nim files.
DEFAULT is ON!
--wholeProject overwrite every processed file.
--checkExtern:on|off style check also extern names
--styleCheck:on|off|auto performs style checking for identifiers
and suggests an alternative spelling;
'auto' corrects the spelling.
--bestEffort try to fix the code even when there
are errors.
In addition, all command line options of Nim are supported.
"""
proc mainCommand =
registerPass verbosePass
registerPass semPass
conf.setCmd cmdNimfix
searchPaths.add options.libpath
if gProjectFull.len != 0:
# current path is always looked first for modules
searchPaths.insert(gProjectPath, 0)
compileProject(newModuleGraph(), newIdentCache())
pretty.overwriteFiles()
proc processCmdLine*(pass: TCmdLinePass, cmd: string, config: ConfigRef) =
var p = parseopt.initOptParser(cmd)
var argsCount = 0
gOnlyMainfile = true
while true:
parseopt.next(p)
case p.kind
of cmdEnd: break
of cmdLongoption, cmdShortOption:
case p.key.normalize
of "overwritefiles":
case p.val.normalize
of "on": gOverWrite = true
of "off": gOverWrite = false
else: localError(gCmdLineInfo, errOnOrOffExpected)
of "checkextern":
case p.val.normalize
of "on": gCheckExtern = true
of "off": gCheckExtern = false
else: localError(gCmdLineInfo, errOnOrOffExpected)
of "stylecheck":
case p.val.normalize
of "off": gStyleCheck = StyleCheck.None
of "on": gStyleCheck = StyleCheck.Warn
of "auto": gStyleCheck = StyleCheck.Auto
else: localError(gCmdLineInfo, errOnOrOffExpected)
of "wholeproject": gOnlyMainfile = false
of "besteffort": msgs.gErrorMax = high(int) # don't stop after first error
else:
processSwitch(pass, p, config)
of cmdArgument:
options.gProjectName = unixToNativePath(p.key)
# if processArgument(pass, p, argsCount): break
proc handleCmdLine(config: ConfigRef) =
if paramCount() == 0:
stdout.writeLine(Usage)
else:
processCmdLine(passCmd1, "", config)
if gProjectName != "":
try:
gProjectFull = canonicalizePath(gProjectName)
except OSError:
gProjectFull = gProjectName
var p = splitFile(gProjectFull)
gProjectPath = p.dir
gProjectName = p.name
else:
gProjectPath = getCurrentDir()
loadConfigs(DefaultConfig, config) # load all config files
# now process command line arguments again, because some options in the
# command line can overwrite the config file's settings
extccomp.initVars()
processCmdLine(passCmd2, "", config)
mainCommand()
when compileOption("gc", "refc"):
GC_disableMarkAndSweep()
condsyms.initDefines()
defineSymbol "nimfix"
handleCmdline newConfigRef()

View File

@@ -1,17 +0,0 @@
# Special configuration file for the Nim project
# gc:markAndSweep
hint[XDeclaredButNotUsed]:off
path:"$projectPath/.."
path:"$lib/packages/docutils"
path:"$nim"
define:useStdoutAsStdmsg
symbol:nimfix
define:nimfix
cs:partial
#define:useNodeIds
define:booting
define:noDocgen

View File

@@ -1,45 +0,0 @@
#
#
# The Nim Compiler
# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
import strutils except Letters
import ".." / [ast, msgs, lineinfos, idents, options, linter]
proc replaceDeprecated*(conf: ConfigRef; info: TLineInfo; oldSym, newSym: PIdent) =
let line = sourceLine(conf, info)
var first = min(info.col.int, line.len)
if first < 0: return
#inc first, skipIgnoreCase(line, "proc ", first)
while first > 0 and line[first-1] in Letters: dec first
if first < 0: return
if line[first] == '`': inc first
let last = first+identLen(line, first)-1
if cmpIgnoreStyle(line[first..last], oldSym.s) == 0:
var x = line.substr(0, first-1) & newSym.s & line.substr(last+1)
when defined(gcArc) or defined(gcOrc):
conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1] = move x
else:
system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x)
conf.m.fileInfos[info.fileIndex.int32].dirty = true
#if newSym.s == "File": writeStackTrace()
proc replaceDeprecated*(conf: ConfigRef; info: TLineInfo; oldSym, newSym: PSym) =
replaceDeprecated(conf, info, oldSym.name, newSym.name)
proc replaceComment*(conf: ConfigRef; info: TLineInfo) =
let line = sourceLine(conf, info)
var first = info.col.int
if line[first] != '#': inc first
var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape
when defined(gcArc) or defined(gcOrc):
conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1] = move x
else:
system.shallowCopy(conf.m.fileInfos[info.fileIndex.int32].lines[info.line.int-1], x)
conf.m.fileInfos[info.fileIndex.int32].dirty = true

View File

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

2103
compiler/nir/ast2ir.nim Normal file

File diff suppressed because it is too large Load Diff

78
compiler/nir/cir.nim Normal file
View File

@@ -0,0 +1,78 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# We produce C code as a list of tokens.
import std / assertions
import .. / ic / bitabs
type
Token = LitId # indexing into the tokens BiTable[string]
PredefinedToken = enum
IgnoreMe = "<unused>"
EmptyToken = ""
DeclPrefix = "" # the next token is the name of a definition
CurlyLe = "{"
CurlyRi = "}"
ParLe = "("
ParRi = ")"
BracketLe = "["
BracketRi = "]"
NewLine = "\n"
Semicolon = ";"
Comma = ", "
Space = " "
Colon = ":"
Dot = "."
Arrow = "->"
Star = "*"
Amp = "&"
AsgnOpr = " = "
ScopeOpr = "::"
ConstKeyword = "const "
StaticKeyword = "static "
NimString = "NimString"
StrLitPrefix = "(NimChar*)"
StrLitNamePrefix = "Qstr"
LoopKeyword = "while (true) "
WhileKeyword = "while ("
IfKeyword = "if ("
ElseKeyword = "else "
SwitchKeyword = "switch ("
CaseKeyword = "case "
DefaultKeyword = "default:"
BreakKeyword = "break"
NullPtr = "nullptr"
IfNot = "if (!("
ReturnKeyword = "return "
const
ModulePrefix = Token(int(ReturnKeyword)+1)
proc fillTokenTable(tab: var BiTable[string]) =
for e in EmptyToken..high(PredefinedToken):
let id = tab.getOrIncl $e
assert id == LitId(e)
type
GeneratedCode* = object
code: seq[LitId]
tokens: BiTable[string]
proc initGeneratedCode*(): GeneratedCode =
result = GeneratedCode(code: @[], tokens: initBiTable[string]())
fillTokenTable(result.tokens)
proc add*(g: var GeneratedCode; t: PredefinedToken) {.inline.} =
g.code.add Token(t)
proc add*(g: var GeneratedCode; s: string) {.inline.} =
g.code.add g.tokens.getOrIncl(s)

22
compiler/nir/nir.nim Normal file
View File

@@ -0,0 +1,22 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Nim Intermediate Representation, designed to capture all of Nim's semantics without losing too much
## precious information. Can easily be translated into C. And to JavaScript, hopefully.
import nirtypes, nirinsts, ast2ir
when false:
type
Module* = object
types: TypeGraph
data: seq[Tree]
init: seq[Tree]
procs: seq[Tree]

314
compiler/nir/nirinsts.nim Normal file
View File

@@ -0,0 +1,314 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## NIR instructions. Somewhat inspired by LLVM's instructions.
import std / [assertions, hashes, strformat]
import .. / ic / bitabs
import nirlineinfos, nirtypes
type
SymId* = distinct int
proc `$`*(s: SymId): string {.borrow.}
proc hash*(s: SymId): Hash {.borrow.}
proc `==`*(a, b: SymId): bool {.borrow.}
type
Opcode* = enum
Nop,
ImmediateVal,
IntVal,
StrVal,
SymDef,
SymUse,
ModuleId,
Typed, # with type ID
NilVal,
Label,
Goto,
CheckedGoto,
LoopLabel,
GotoLoop, # last atom
ModuleSymUse, # `module.x`
ArrayConstr,
ObjConstr,
Ret,
Yld,
Select,
SelectPair, # ((values...), Label)
SelectList, # (values...)
SelectValue, # (value)
SelectRange, # (valueA..valueB)
SummonGlobal,
SummonThreadLocal,
Summon, # x = Summon Typed <Type ID>; x begins to live
Kill, # `Kill x`: scope end for `x`
AddrOf,
ArrayAt, # addr(a[i])
FieldAt, # addr(obj.field)
Load, # a[]
Store, # a[] = b
Asgn, # a = b
SetExc,
TestExc,
Call,
IndirectCall,
CheckedCall, # call that can raise
CheckedIndirectCall, # call that can raise
CheckedAdd, # with overflow checking etc.
CheckedSub,
CheckedMul,
CheckedDiv,
CheckedMod,
Add,
Sub,
Mul,
Div,
Mod,
BitShl,
BitShr,
BitAnd,
BitOr,
BitXor,
BitNot,
Eq,
Le,
Lt,
Cast,
NumberConv,
CheckedObjConv,
ObjConv,
TestOf,
Emit,
ProcDecl
const
LastAtomicValue = GotoLoop
OpcodeBits = 8'u32
OpcodeMask = (1'u32 shl OpcodeBits) - 1'u32
ValueProducingAtoms = {ImmediateVal, IntVal, StrVal, SymUse, NilVal}
ValueProducing* = {
ImmediateVal,
IntVal,
StrVal,
SymUse,
NilVal,
ModuleSymUse,
ArrayConstr,
ObjConstr,
CheckedAdd,
CheckedSub,
CheckedMul,
CheckedDiv,
CheckedMod,
Add,
Sub,
Mul,
Div,
Mod,
BitShl,
BitShr,
BitAnd,
BitOr,
BitXor,
BitNot,
Eq,
Le,
Lt,
Cast,
NumberConv,
CheckedObjConv,
ObjConv,
AddrOf,
Load,
ArrayAt,
FieldAt,
TestOf
}
type
Instr* = object # 8 bytes
x: uint32
info: PackedLineInfo
template kind*(n: Instr): Opcode = Opcode(n.x and OpcodeMask)
template operand(n: Instr): uint32 = (n.x shr OpcodeBits)
template toX(k: Opcode; operand: uint32): uint32 =
uint32(k) or (operand shl OpcodeBits)
template toX(k: Opcode; operand: LitId): uint32 =
uint32(k) or (operand.uint32 shl OpcodeBits)
proc `$`*(n: Instr): string =
result = fmt"{n.kind}: {n.operand}"
type
Tree* = object
nodes: seq[Instr]
Values* = object
numbers: BiTable[int64]
strings: BiTable[string]
type
PatchPos* = distinct int
NodePos* = distinct int
const
InvalidPatchPos* = PatchPos(-1)
proc debug*(t: Tree) {.deprecated.} =
for i in t.nodes:
echo i
proc isValid(p: PatchPos): bool {.inline.} = p.int != -1
proc prepare*(tree: var Tree; info: PackedLineInfo; kind: Opcode): PatchPos =
result = PatchPos tree.nodes.len
tree.nodes.add Instr(x: toX(kind, 1'u32), info: info)
proc isAtom(tree: Tree; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue
proc isAtom(tree: Tree; pos: NodePos): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue
proc patch*(tree: var Tree; pos: PatchPos) =
let pos = pos.int
let k = tree.nodes[pos].kind
assert k > LastAtomicValue
let distance = int32(tree.nodes.len - pos)
assert distance > 0
tree.nodes[pos].x = toX(k, cast[uint32](distance))
template build*(tree: var Tree; info: PackedLineInfo; kind: Opcode; body: untyped) =
let pos = prepare(tree, info, kind)
body
patch(tree, pos)
proc len*(tree: Tree): int {.inline.} = tree.nodes.len
template rawSpan(n: Instr): int = int(operand(n))
proc nextChild(tree: Tree; pos: var int) {.inline.} =
if tree.nodes[pos].kind > LastAtomicValue:
assert tree.nodes[pos].operand > 0'u32
inc pos, tree.nodes[pos].rawSpan
else:
inc pos
iterator sons*(tree: Tree; n: NodePos): NodePos =
var pos = n.int
assert tree.nodes[pos].kind > LastAtomicValue
let last = pos + tree.nodes[pos].rawSpan
inc pos
while pos < last:
yield NodePos pos
nextChild tree, pos
template `[]`*(t: Tree; n: NodePos): Instr = t.nodes[n.int]
proc span(tree: Tree; pos: int): int {.inline.} =
if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand)
proc copyTree*(dest: var Tree; src: Tree) =
let pos = 0
let L = span(src, pos)
let d = dest.nodes.len
dest.nodes.setLen(d + L)
assert L > 0
for i in 0..<L:
dest.nodes[d+i] = src.nodes[pos+i]
type
LabelId* = distinct int
proc newLabel*(labelGen: var int): LabelId {.inline.} =
result = LabelId labelGen
inc labelGen
proc addNewLabel*(t: var Tree; labelGen: var int; info: PackedLineInfo; k: Opcode): LabelId =
assert k in {Label, LoopLabel}
result = LabelId labelGen
t.nodes.add Instr(x: toX(k, uint32(result)), info: info)
inc labelGen
proc boolVal*(t: var Tree; info: PackedLineInfo; b: bool) =
t.nodes.add Instr(x: toX(ImmediateVal, uint32(b)), info: info)
proc gotoLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) =
assert k in {Goto, GotoLoop, CheckedGoto}
t.nodes.add Instr(x: toX(k, uint32(L)), info: info)
proc addLabel*(t: var Tree; info: PackedLineInfo; k: Opcode; L: LabelId) {.inline.} =
assert k in {Label, LoopLabel, Goto, GotoLoop, CheckedGoto}
t.nodes.add Instr(x: toX(k, uint32(L)), info: info)
proc addSymUse*(t: var Tree; info: PackedLineInfo; s: SymId) {.inline.} =
t.nodes.add Instr(x: toX(SymUse, uint32(s)), info: info)
proc addTyped*(t: var Tree; info: PackedLineInfo; typ: TypeId) {.inline.} =
t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info)
proc addSummon*(t: var Tree; info: PackedLineInfo; s: SymId; typ: TypeId) {.inline.} =
let x = prepare(t, info, Summon)
t.nodes.add Instr(x: toX(SymDef, uint32(s)), info: info)
t.nodes.add Instr(x: toX(Typed, uint32(typ)), info: info)
patch t, x
proc addImmediateVal*(t: var Tree; info: PackedLineInfo; x: int) =
assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int)
t.nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info)
type
Value* = distinct Tree
proc prepare*(dest: var Value; info: PackedLineInfo; k: Opcode): PatchPos {.inline.} =
assert k in ValueProducing - ValueProducingAtoms
result = prepare(Tree(dest), info, k)
proc patch*(dest: var Value; pos: PatchPos) {.inline.} =
patch(Tree(dest), pos)
proc localToValue*(info: PackedLineInfo; s: SymId): Value =
result = Value(Tree())
Tree(result).addSymUse info, s
proc hasValue*(v: Value): bool {.inline.} = Tree(v).len > 0
proc isEmpty*(v: Value): bool {.inline.} = Tree(v).len == 0
proc extractTemp*(v: Value): SymId =
if hasValue(v) and Tree(v)[NodePos 0].kind == SymUse:
result = SymId(Tree(v)[NodePos 0].operand)
else:
result = SymId(-1)
proc copyTree*(dest: var Tree; src: Value) = copyTree dest, Tree(src)
proc addImmediateVal*(t: var Value; info: PackedLineInfo; x: int) =
assert x >= 0 and x < ((1 shl 32) - OpcodeBits.int)
Tree(t).nodes.add Instr(x: toX(ImmediateVal, uint32(x)), info: info)
template build*(tree: var Value; info: PackedLineInfo; kind: Opcode; body: untyped) =
let pos = prepare(Tree(tree), info, kind)
body
patch(tree, pos)
proc addTyped*(t: var Value; info: PackedLineInfo; typ: TypeId) {.inline.} =
addTyped(Tree(t), info, typ)

View File

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

97
compiler/nir/nirslots.nim Normal file
View File

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

339
compiler/nir/nirtypes.nim Normal file
View File

@@ -0,0 +1,339 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Type system for NIR. Close to C's type system but without its quirks.
import std / [assertions, hashes]
import .. / ic / bitabs
type
NirTypeKind* = enum
VoidTy, IntTy, UIntTy, FloatTy, BoolTy, CharTy, NameVal, IntVal,
AnnotationVal,
VarargsTy, # the `...` in a C prototype; also the last "atom"
APtrTy, # pointer to aliasable memory
UPtrTy, # pointer to unique/unaliasable memory
AArrayPtrTy, # pointer to array of aliasable memory
UArrayPtrTy, # pointer to array of unique/unaliasable memory
ArrayTy,
LastArrayTy, # array of unspecified size as a last field inside an object
ObjectTy,
UnionTy,
ProcTy,
ObjectDecl,
UnionDecl,
FieldDecl
const
TypeKindBits = 8'u32
TypeKindMask = (1'u32 shl TypeKindBits) - 1'u32
type
TypeNode* = object # 4 bytes
x: uint32
template kind*(n: TypeNode): NirTypeKind = NirTypeKind(n.x and TypeKindMask)
template operand(n: TypeNode): uint32 = (n.x shr TypeKindBits)
template toX(k: NirTypeKind; operand: uint32): uint32 =
uint32(k) or (operand shl TypeKindBits)
template toX(k: NirTypeKind; operand: LitId): uint32 =
uint32(k) or (operand.uint32 shl TypeKindBits)
type
TypeId* = distinct int
proc `==`*(a, b: TypeId): bool {.borrow.}
proc hash*(a: TypeId): Hash {.borrow.}
type
TypeGraph* = object
nodes: seq[TypeNode]
names: BiTable[string]
numbers: BiTable[uint64]
const
VoidId* = TypeId 0
Bool8Id* = TypeId 1
Char8Id* = TypeId 2
Int8Id* = TypeId 3
Int16Id* = TypeId 4
Int32Id* = TypeId 5
Int64Id* = TypeId 6
UInt8Id* = TypeId 7
UInt16Id* = TypeId 8
UInt32Id* = TypeId 9
UInt64Id* = TypeId 10
Float32Id* = TypeId 11
Float64Id* = TypeId 12
LastBuiltinId* = 12
proc initTypeGraph*(): TypeGraph =
result = TypeGraph(nodes: @[
TypeNode(x: toX(VoidTy, 0'u32)),
TypeNode(x: toX(BoolTy, 8'u32)),
TypeNode(x: toX(CharTy, 8'u32)),
TypeNode(x: toX(IntTy, 8'u32)),
TypeNode(x: toX(IntTy, 16'u32)),
TypeNode(x: toX(IntTy, 32'u32)),
TypeNode(x: toX(IntTy, 64'u32)),
TypeNode(x: toX(UIntTy, 8'u32)),
TypeNode(x: toX(UIntTy, 16'u32)),
TypeNode(x: toX(UIntTy, 32'u32)),
TypeNode(x: toX(UIntTy, 64'u32)),
TypeNode(x: toX(FloatTy, 32'u32)),
TypeNode(x: toX(FloatTy, 64'u32))
])
assert result.nodes.len == LastBuiltinId+1
type
TypePatchPos* = distinct int
const
InvalidTypePatchPos* = TypePatchPos(-1)
LastAtomicValue = VarargsTy
proc isValid(p: TypePatchPos): bool {.inline.} = p.int != -1
proc prepare(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
result = TypePatchPos tree.nodes.len
tree.nodes.add TypeNode(x: toX(kind, 1'u32))
proc isAtom(tree: TypeGraph; pos: int): bool {.inline.} = tree.nodes[pos].kind <= LastAtomicValue
proc isAtom(tree: TypeGraph; pos: TypeId): bool {.inline.} = tree.nodes[pos.int].kind <= LastAtomicValue
proc patch(tree: var TypeGraph; pos: TypePatchPos) =
let pos = pos.int
let k = tree.nodes[pos].kind
assert k > LastAtomicValue
let distance = int32(tree.nodes.len - pos)
assert distance > 0
tree.nodes[pos].x = toX(k, cast[uint32](distance))
proc len*(tree: TypeGraph): int {.inline.} = tree.nodes.len
template rawSpan(n: TypeNode): int = int(operand(n))
proc nextChild(tree: TypeGraph; pos: var int) {.inline.} =
if tree.nodes[pos].kind > LastAtomicValue:
assert tree.nodes[pos].operand > 0'u32
inc pos, tree.nodes[pos].rawSpan
else:
inc pos
iterator sons*(tree: TypeGraph; n: TypeId): TypeId =
var pos = n.int
assert tree.nodes[pos].kind > LastAtomicValue
let last = pos + tree.nodes[pos].rawSpan
inc pos
while pos < last:
yield TypeId pos
nextChild tree, pos
template `[]`*(t: TypeGraph; n: TypeId): TypeNode = t.nodes[n.int]
proc elementType*(tree: TypeGraph; n: TypeId): TypeId {.inline.} =
assert tree[n].kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy, ArrayTy, LastArrayTy}
result = TypeId(n.int+1)
proc kind*(tree: TypeGraph; n: TypeId): NirTypeKind {.inline.} = tree[n].kind
proc span(tree: TypeGraph; pos: int): int {.inline.} =
if tree.nodes[pos].kind <= LastAtomicValue: 1 else: int(tree.nodes[pos].operand)
proc sons2(tree: TypeGraph; n: TypeId): (TypeId, TypeId) =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
result = (TypeId a, TypeId b)
proc sons3(tree: TypeGraph; n: TypeId): (TypeId, TypeId, TypeId) =
assert(not isAtom(tree, n.int))
let a = n.int+1
let b = a + span(tree, a)
let c = b + span(tree, b)
result = (TypeId a, TypeId b, TypeId c)
proc arrayLen*(tree: TypeGraph; n: TypeId): BiggestUInt =
assert tree[n].kind == ArrayTy
result = tree.numbers[LitId tree[n].operand]
proc openType*(tree: var TypeGraph; kind: NirTypeKind): TypePatchPos =
assert kind in {APtrTy, UPtrTy, AArrayPtrTy, UArrayPtrTy,
ArrayTy, LastArrayTy, ProcTy, ObjectDecl, UnionDecl,
FieldDecl}
result = prepare(tree, kind)
proc sealType*(tree: var TypeGraph; p: TypePatchPos): TypeId =
# TODO: Search for an existing instance of this type in
# order to reduce memory consumption.
result = TypeId(p)
patch tree, p
proc nominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string): TypeId =
assert kind in {ObjectTy, UnionTy}
result = TypeId tree.nodes.len
tree.nodes.add TypeNode(x: toX(kind, tree.names.getOrIncl(name)))
proc addNominalType*(tree: var TypeGraph; kind: NirTypeKind; name: string) =
assert kind in {ObjectTy, UnionTy}
tree.nodes.add TypeNode(x: toX(kind, tree.names.getOrIncl(name)))
proc addVarargs*(tree: var TypeGraph) =
tree.nodes.add TypeNode(x: toX(VarargsTy, 0'u32))
proc getFloat128Type*(tree: var TypeGraph): TypeId =
result = TypeId tree.nodes.len
tree.nodes.add TypeNode(x: toX(FloatTy, 128'u32))
proc addBuiltinType*(g: var TypeGraph; id: TypeId) =
g.nodes.add g[id]
template firstSon(n: TypeId): TypeId = TypeId(n.int+1)
proc addType*(g: var TypeGraph; t: TypeId) =
# We cannot simply copy `*Decl` nodes. We have to introduce `*Ty` nodes instead:
if g[t].kind in {ObjectDecl, UnionDecl}:
assert g[t.firstSon].kind == NameVal
let name = LitId g[t.firstSon].operand
if g[t].kind == ObjectDecl:
g.nodes.add TypeNode(x: toX(ObjectTy, name))
else:
g.nodes.add TypeNode(x: toX(UnionTy, name))
else:
let pos = t.int
let L = span(g, pos)
let d = g.nodes.len
g.nodes.setLen(d + L)
assert L > 0
for i in 0..<L:
g.nodes[d+i] = g.nodes[pos+i]
proc addArrayLen*(g: var TypeGraph; len: uint64) =
g.nodes.add TypeNode(x: toX(IntVal, g.numbers.getOrIncl(len)))
proc addName*(g: var TypeGraph; name: string) =
g.nodes.add TypeNode(x: toX(NameVal, g.names.getOrIncl(name)))
proc addAnnotation*(g: var TypeGraph; name: string) =
g.nodes.add TypeNode(x: toX(NameVal, g.names.getOrIncl(name)))
proc addField*(g: var TypeGraph; name: string; typ: TypeId) =
let f = g.openType FieldDecl
g.addType typ
g.addName name
discard sealType(g, f)
proc toString*(dest: var string; g: TypeGraph; i: TypeId) =
case g[i].kind
of VoidTy: dest.add "void"
of IntTy:
dest.add "i"
dest.addInt g[i].operand
of UIntTy:
dest.add "u"
dest.addInt g[i].operand
of FloatTy:
dest.add "f"
dest.addInt g[i].operand
of BoolTy:
dest.add "b"
dest.addInt g[i].operand
of CharTy:
dest.add "c"
dest.addInt g[i].operand
of NameVal, AnnotationVal:
dest.add g.names[LitId g[i].operand]
of IntVal:
dest.add $g.numbers[LitId g[i].operand]
of VarargsTy:
dest.add "..."
of APtrTy:
dest.add "aptr["
toString(dest, g, g.elementType(i))
dest.add "]"
of UPtrTy:
dest.add "uptr["
toString(dest, g, g.elementType(i))
dest.add "]"
of AArrayPtrTy:
dest.add "aArrayPtr["
toString(dest, g, g.elementType(i))
dest.add "]"
of UArrayPtrTy:
dest.add "uArrayPtr["
toString(dest, g, g.elementType(i))
dest.add "]"
of ArrayTy:
dest.add "Array["
let (elems, len) = g.sons2(i)
toString(dest, g, elems)
dest.add ", "
toString(dest, g, len)
dest.add "]"
of LastArrayTy:
# array of unspecified size as a last field inside an object
dest.add "LastArrayTy["
toString(dest, g, g.elementType(i))
dest.add "]"
of ObjectTy:
dest.add "object "
dest.add g.names[LitId g[i].operand]
of UnionTy:
dest.add "union "
dest.add g.names[LitId g[i].operand]
of ProcTy:
dest.add "proc["
for t in sons(g, i): toString(dest, g, t)
dest.add "]"
of ObjectDecl:
dest.add "object["
for t in sons(g, i):
toString(dest, g, t)
dest.add '\n'
dest.add "]"
of UnionDecl:
dest.add "union["
for t in sons(g, i):
toString(dest, g, t)
dest.add '\n'
dest.add "]"
of FieldDecl:
let (typ, name) = g.sons2(i)
toString(dest, g, typ)
dest.add ' '
toString(dest, g, name)
proc toString*(dest: var string; g: TypeGraph) =
var i = 0
while i < g.len:
toString(dest, g, TypeId i)
dest.add '\n'
nextChild g, i
proc `$`(g: TypeGraph): string =
result = ""
toString(result, g)
when isMainModule:
var g = initTypeGraph()
let a = g.openType ArrayTy
g.addBuiltinType Int8Id
g.addArrayLen 5'u64
let finalArrayType = sealType(g, a)
let obj = g.openType ObjectDecl
g.nodes.add TypeNode(x: toX(NameVal, g.names.getOrIncl("MyType")))
g.addField "p", finalArrayType
discard sealType(g, obj)
echo g

426
compiler/nir/types2ir.nim Normal file
View File

@@ -0,0 +1,426 @@
#
#
# The Nim Compiler
# (c) Copyright 2023 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
import std / [assertions, tables, sets]
import ".." / [ast, types, options, sighashes, modulegraphs]
import nirtypes
type
TypesCon* = object
processed: Table[ItemId, TypeId]
recursionCheck: HashSet[ItemId]
g: TypeGraph
conf: ConfigRef
proc initTypesCon*(conf: ConfigRef): TypesCon =
TypesCon(g: initTypeGraph(), conf: conf)
proc mangle(c: var TypesCon; t: PType): string =
result = $sighashes.hashType(t, c.conf)
template cached(c: var TypesCon; t: PType; body: untyped) =
result = c.processed.getOrDefault(t.itemId)
if result.int == 0:
body
c.processed[t.itemId] = result
proc typeToIr*(c: var TypesCon; t: PType): TypeId
proc collectFieldTypes(c: var TypesCon; n: PNode; dest: var Table[ItemId, TypeId]) =
case n.kind
of nkRecList:
for i in 0..<n.len:
collectFieldTypes(c, n[i], dest)
of nkRecCase:
assert(n[0].kind == nkSym)
collectFieldTypes(c, n[0], dest)
for i in 1..<n.len:
case n[i].kind
of nkOfBranch, nkElse:
collectFieldTypes c, lastSon(n[i]), dest
else: discard
of nkSym:
dest[n.sym.itemId] = typeToIr(c, n.sym.typ)
else:
assert false, "unknown node kind: " & $n.kind
proc objectToIr(c: var TypesCon; n: PNode; fieldTypes: Table[ItemId, TypeId]; unionId: var int) =
case n.kind
of nkRecList:
for i in 0..<n.len:
objectToIr(c, n[i], fieldTypes, unionId)
of nkRecCase:
assert(n[0].kind == nkSym)
objectToIr(c, n[0], fieldTypes, unionId)
let u = openType(c.g, UnionDecl)
c.g.addName "u_" & $unionId
inc unionId
for i in 1..<n.len:
case n[i].kind
of nkOfBranch, nkElse:
let subObj = openType(c.g, ObjectDecl)
c.g.addName "uo_" & $unionId & "_" & $i
objectToIr c, lastSon(n[i]), fieldTypes, unionId
discard sealType(c.g, subObj)
else: discard
discard sealType(c.g, u)
of nkSym:
c.g.addField n.sym.name.s & "_" & $n.sym.position, fieldTypes[n.sym.itemId]
else:
assert false, "unknown node kind: " & $n.kind
proc objectToIr(c: var TypesCon; t: PType): TypeId =
if t[0] != nil:
# ensure we emitted the base type:
discard typeToIr(c, t[0])
var unionId = 0
var fieldTypes = initTable[ItemId, TypeId]()
collectFieldTypes c, t.n, fieldTypes
let obj = openType(c.g, ObjectDecl)
c.g.addName mangle(c, t)
if t[0] != nil:
c.g.addNominalType(ObjectTy, mangle(c, t[0]))
else:
c.g.addBuiltinType VoidId # object does not inherit
if not lacksMTypeField(t):
let f2 = c.g.openType FieldDecl
let voidPtr = openType(c.g, APtrTy)
c.g.addBuiltinType(VoidId)
discard sealType(c.g, voidPtr)
c.g.addName "m_type"
discard sealType(c.g, f2) # FieldDecl
objectToIr c, t.n, fieldTypes, unionId
result = sealType(c.g, obj)
proc objectHeaderToIr(c: var TypesCon; t: PType): TypeId =
result = c.g.nominalType(ObjectTy, mangle(c, t))
proc tupleToIr(c: var TypesCon; t: PType): TypeId =
var fieldTypes = newSeq[TypeId](t.len)
for i in 0..<t.len:
fieldTypes[i] = typeToIr(c, t[i])
let obj = openType(c.g, ObjectDecl)
c.g.addName mangle(c, t)
for i in 0..<t.len:
c.g.addField "f_" & $i, fieldTypes[i]
result = sealType(c.g, obj)
proc procToIr(c: var TypesCon; t: PType; addEnv = false): TypeId =
var fieldTypes = newSeq[TypeId](0)
for i in 0..<t.len:
if not isCompileTimeOnly(t[i]):
fieldTypes.add typeToIr(c, t[i])
let obj = openType(c.g, ProcTy)
case t.callConv
of ccNimCall, ccFastCall, ccClosure: c.g.addAnnotation "__fastcall"
of ccStdCall: c.g.addAnnotation "__stdcall"
of ccCDecl: c.g.addAnnotation "__cdecl"
of ccSafeCall: c.g.addAnnotation "__safecall"
of ccSysCall: c.g.addAnnotation "__syscall"
of ccInline: c.g.addAnnotation "__inline"
of ccNoInline: c.g.addAnnotation "__noinline"
of ccThisCall: c.g.addAnnotation "__thiscall"
of ccNoConvention: c.g.addAnnotation ""
for i in 0..<fieldTypes.len:
c.g.addType fieldTypes[i]
if addEnv:
let a = openType(c.g, APtrTy)
c.g.addBuiltinType(VoidId)
discard sealType(c.g, a)
if tfVarargs in t.flags:
c.g.addVarargs()
result = sealType(c.g, obj)
proc nativeInt(c: TypesCon): TypeId =
case c.conf.target.intSize
of 2: result = Int16Id
of 4: result = Int32Id
else: result = Int64Id
proc openArrayToIr(c: var TypesCon; t: PType): TypeId =
# object (a: ArrayPtr[T], len: int)
let e = lastSon(t)
let mangledBase = mangle(c, e)
let typeName = "NimOpenArray" & mangledBase
let elementType = typeToIr(c, e)
let p = openType(c.g, ObjectDecl)
c.g.addName typeName
let f = c.g.openType FieldDecl
let arr = c.g.openType AArrayPtrTy
c.g.addType elementType
discard sealType(c.g, arr) # LastArrayTy
c.g.addName "data"
discard sealType(c.g, f) # FieldDecl
c.g.addField "len", c.nativeInt
result = sealType(c.g, p) # ObjectDecl
proc stringToIr(c: var TypesCon; t: PType): TypeId =
#[
NimStrPayload = object
cap: int
data: UncheckedArray[char]
NimStringV2 = object
len: int
p: ptr NimStrPayload
]#
let p = openType(c.g, ObjectDecl)
c.g.addName "NimStrPayload"
c.g.addField "cap", c.nativeInt
let f = c.g.openType FieldDecl
let arr = c.g.openType LastArrayTy
c.g.addBuiltinType Char8Id
discard sealType(c.g, arr) # LastArrayTy
c.g.addName "data"
discard sealType(c.g, f) # FieldDecl
let payload = sealType(c.g, p)
let str = openType(c.g, ObjectDecl)
c.g.addName "NimStringV2"
c.g.addField "len", c.nativeInt
let fp = c.g.openType FieldDecl
let ffp = c.g.openType APtrTy
c.g.addNominalType ObjectTy, "NimStrPayload"
discard sealType(c.g, ffp) # APtrTy
c.g.addName "p"
discard sealType(c.g, fp) # FieldDecl
result = sealType(c.g, str) # ObjectDecl
proc seqToIr(c: var TypesCon; t: PType): TypeId =
#[
NimSeqPayload[T] = object
cap: int
data: UncheckedArray[T]
NimSeqV2*[T] = object
len: int
p: ptr NimSeqPayload[T]
]#
let e = lastSon(t)
let mangledBase = mangle(c, e)
let payloadName = "NimSeqPayload" & mangledBase
let elementType = typeToIr(c, e)
let p = openType(c.g, ObjectDecl)
c.g.addName payloadName
c.g.addField "cap", c.nativeInt
let f = c.g.openType FieldDecl
let arr = c.g.openType LastArrayTy
c.g.addType elementType
discard sealType(c.g, arr) # LastArrayTy
c.g.addName "data"
discard sealType(c.g, f) # FieldDecl
let payload = sealType(c.g, p)
let sq = openType(c.g, ObjectDecl)
c.g.addName "NimSeqV2" & mangledBase
c.g.addField "len", c.nativeInt
let fp = c.g.openType FieldDecl
let ffp = c.g.openType APtrTy
c.g.addNominalType ObjectTy, "NimSeqPayload" & mangledBase
discard sealType(c.g, ffp) # APtrTy
c.g.addName "p"
discard sealType(c.g, fp) # FieldDecl
result = sealType(c.g, sq) # ObjectDecl
proc closureToIr(c: var TypesCon; t: PType): TypeId =
# struct {fn(args, void* env), env}
# typedef struct {$n" &
# "N_NIMCALL_PTR($2, ClP_0) $3;$n" &
# "void* ClE_0;$n} $1;$n"
let mangledBase = mangle(c, t)
let typeName = "NimClosure" & mangledBase
let procType = procToIr(c, t, addEnv=true)
let p = openType(c.g, ObjectDecl)
c.g.addName typeName
let f = c.g.openType FieldDecl
c.g.addType procType
c.g.addName "ClP_0"
discard sealType(c.g, f) # FieldDecl
let f2 = c.g.openType FieldDecl
let voidPtr = openType(c.g, APtrTy)
c.g.addBuiltinType(VoidId)
discard sealType(c.g, voidPtr)
c.g.addName "ClE_0"
discard sealType(c.g, f2) # FieldDecl
result = sealType(c.g, p) # ObjectDecl
proc typeToIr*(c: var TypesCon; t: PType): TypeId =
case t.kind
of tyInt:
case int(getSize(c.conf, t))
of 2: result = Int16Id
of 4: result = Int32Id
else: result = Int64Id
of tyInt8: result = Int8Id
of tyInt16: result = Int16Id
of tyInt32: result = Int32Id
of tyInt64: result = Int64Id
of tyFloat:
case int(getSize(c.conf, t))
of 4: result = Float32Id
else: result = Float64Id
of tyFloat32: result = Float32Id
of tyFloat64: result = Float64Id
of tyFloat128: result = getFloat128Type(c.g)
of tyUInt:
case int(getSize(c.conf, t))
of 2: result = UInt16Id
of 4: result = UInt32Id
else: result = UInt64Id
of tyUInt8: result = UInt8Id
of tyUInt16: result = UInt16Id
of tyUInt32: result = UInt32Id
of tyUInt64: result = UInt64Id
of tyBool: result = Bool8Id
of tyChar: result = Char8Id
of tyVoid: result = VoidId
of tySink, tyGenericInst, tyDistinct, tyAlias, tyOwned, tyRange:
result = typeToIr(c, t.lastSon)
of tyEnum:
if firstOrd(c.conf, t) < 0:
result = Int32Id
else:
case int(getSize(c.conf, t))
of 1: result = UInt8Id
of 2: result = UInt16Id
of 4: result = Int32Id
of 8: result = Int64Id
else: result = Int32Id
of tyOrdinal, tyGenericBody, tyGenericParam, tyInferred, tyStatic:
if t.len > 0:
result = typeToIr(c, t.lastSon)
else:
result = TypeId(-1)
of tyFromExpr:
if t.n != nil and t.n.typ != nil:
result = typeToIr(c, t.n.typ)
else:
result = TypeId(-1)
of tyArray:
cached(c, t):
var n = toInt64(lengthOrd(c.conf, t))
if n <= 0: n = 1 # make an array of at least one element
let elemType = typeToIr(c, t[1])
let a = openType(c.g, ArrayTy)
c.g.addType(elemType)
c.g.addArrayLen uint64(n)
result = sealType(c.g, a)
of tyPtr, tyRef:
cached(c, t):
let e = t.lastSon
if e.kind == tyUncheckedArray:
let elemType = typeToIr(c, e.lastSon)
let a = openType(c.g, AArrayPtrTy)
c.g.addType(elemType)
result = sealType(c.g, a)
else:
let elemType = typeToIr(c, t.lastSon)
let a = openType(c.g, APtrTy)
c.g.addType(elemType)
result = sealType(c.g, a)
of tyVar, tyLent:
cached(c, t):
let elemType = typeToIr(c, t.lastSon)
let a = openType(c.g, APtrTy)
c.g.addType(elemType)
result = sealType(c.g, a)
of tySet:
let s = int(getSize(c.conf, t))
case s
of 1: result = UInt8Id
of 2: result = UInt16Id
of 4: result = UInt32Id
of 8: result = UInt64Id
else:
# array[U8, s]
cached(c, t):
let a = openType(c.g, ArrayTy)
c.g.addType(UInt8Id)
c.g.addArrayLen uint64(s)
result = sealType(c.g, a)
of tyPointer:
let a = openType(c.g, APtrTy)
c.g.addBuiltinType(VoidId)
result = sealType(c.g, a)
of tyObject:
# Objects are special as they can be recursive in Nim. This is easily solvable.
# We check if we are already "processing" t. If so, we produce `ObjectTy`
# instead of `ObjectDecl`.
cached(c, t):
if not c.recursionCheck.containsOrIncl(t.itemId):
result = objectToIr(c, t)
else:
result = objectHeaderToIr(c, t)
of tyTuple:
cached(c, t):
result = tupleToIr(c, t)
of tyProc:
cached(c, t):
if t.callConv == ccClosure:
result = closureToIr(c, t)
else:
result = procToIr(c, t)
of tyVarargs, tyOpenArray:
cached(c, t):
result = openArrayToIr(c, t)
of tyString:
cached(c, t):
result = stringToIr(c, t)
of tySequence:
cached(c, t):
result = seqToIr(c, t)
of tyCstring:
cached(c, t):
let a = openType(c.g, AArrayPtrTy)
c.g.addBuiltinType Char8Id
result = sealType(c.g, a)
of tyUncheckedArray:
# We already handled the `ptr UncheckedArray` in a special way.
cached(c, t):
let elemType = typeToIr(c, t.lastSon)
let a = openType(c.g, LastArrayTy)
c.g.addType(elemType)
result = sealType(c.g, a)
of tyNone, tyEmpty, tyUntyped, tyTyped, tyTypeDesc,
tyNil, tyGenericInvocation, tyProxy, tyBuiltInTypeClass,
tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass,
tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward:
result = TypeId(-1)

2
compiler/nir/utils.nim Normal file
View File

@@ -0,0 +1,2 @@
template unreachable*(s = "unreachable") = raiseAssert s
template todo*(s = "todo") = raiseAssert s

View File

@@ -12,6 +12,8 @@
const
MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets?
DefaultSetElements* = 1 shl 8
## assumed set element count when using int literals
VersionAsString* = system.NimVersion
RodFileVersion* = "1223" # modify this if the rod-format changes!

View File

@@ -113,7 +113,7 @@ proc analyse(c: var Con; b: var BasicBlock; n: PNode) =
if n[0].kind == nkSym:
let s = n[0].sym
let name = s.name.s.normalize
if s.magic == mWasMoved or name == "=wasmoved":
if name == "=wasmoved":
b.wasMovedLocs.add n
special = true
elif name == "=destroy":
@@ -279,7 +279,7 @@ proc optimize*(n: PNode): PNode =
Now assume 'use' raises, then we shouldn't do the 'wasMoved(s)'
]#
var c: Con
var c: Con = Con()
var b: BasicBlock
analyse(c, b, n)
if c.somethingTodo:

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