Compare commits

...

53 Commits

Author SHA1 Message Date
Miran
78983f1876 update the changelog (#24213) 2024-10-01 22:22:30 +02:00
ringabout
0e1df88f7e check fileExists for outputFile (#24211)
ref
a5f46a72ba (commitcomment-147402726)
2024-10-01 08:11:07 +02:00
Miran
a5f46a72ba bump NimVersion to 2.2.0 (#24210) 2024-09-30 20:59:38 +02:00
ringabout
4974baf7fa fixes #24008; triggers a recompilation on output executables changes when switching release/debug modes (#24193)
fixes #24008

The old logic didn't check the contents of the output executables, when
it switched release->debug->release, it picked up the Json files used in
the first release building, the content of which didn't change. So it
mistook the executables which are built by the second debug building as
the functioning one.

`changeDetectedViaJsonBuildInstructions` needs a way to distinguish the
executables generated by different buildings.
2024-09-30 20:55:47 +02:00
metagn
b82ff5a87b make C++ atomic opt in via -d:nimUseCppAtomics (#24209)
refs #24207

The `-d:nimUseCAtomics` flag added in #24207 is now inverted and made
into `-d:nimUseCppAtomics`, which means C++ atomics are only enabled
with the define. This flag is now also documented and tested.
2024-09-30 20:54:07 +02:00
metagn
2a48182288 remove prev == nil requirement for typedesc params as type nodes (#24206)
fixes #24203

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

The reason this only happens for types like `seq[int]`, `(int, int)` etc
is because they don't have syms: `semTypeIdent` attempts to directly
[replace the typedesc param
itself](b0e6d28782/compiler/semtypes.nim (L1916))
with the sym of the base type of the resolved typedesc type if it
exists, which means `semTypeNode` doesn't receive the typedesc param sym
to perform the assert.
2024-09-30 17:34:49 +02:00
metagn
febc58e036 allow C atomics on C++ with -d:nimUseCAtomics (#24207)
refs https://github.com/nim-lang/Nim/pull/24200#issuecomment-2382501282

Workaround for C++ Atomic[T] issues that doesn't require a compiler
change. Not tested or documented in case it's not meant to be officially
supported, locally tested `tatomics` and #24159 to work with it though,
can add these as tests if required.
2024-09-30 17:34:09 +02:00
metagn
b0e6d28782 fix logic for dcEqIgnoreDistinct in sameType (#24197)
fixes #22523

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

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

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

#24037 shouldn't be a dependency but the diff follows it.
2024-09-29 10:23:59 +02:00
metagn
7974a2208c fix cyclic node flag getting added to sink call [backport:2.0] (#24194)
Sorry I don't have a test case or issue for this. `injectdestructors` is
supposed to add a final bool argument to `=copy` and `=dup` to mark
cyclic types, as generated by `liftdestructors`. Hence this flag is
added after every call to `genCopy`, but `genCopy` can generate a
`=sink` call when passed the flag `IsExplicitSink` by `nkSinkAsgn`. This
creates a codegen error, saying the sink received an extra argument.
This is fixed by not adding the argument on the flag `IsExplicitSink`.

This is a followup to #20585 which is on the 2.0 branch, hence this is
marked backport.
2024-09-29 10:21:45 +02:00
metagn
7cbe031909 fix trivial segfault in sigmatch for static types (#24196)
refs #7382, caused by #24005
2024-09-29 10:20:38 +02:00
ringabout
4f5c0efaf2 fixes #24174; allow copyDir and copyDirWithPermissions skipping special files (#24190)
fixes  #24174
2024-09-27 16:36:31 +02:00
metagn
821d0806fe Revert "make default values typed in proc AST same as param sym AST" (#24191)
Reverts #24184, reopens #12942, reopens #19118

#24184 seems to have caused a regression in
https://github.com/c-blake/thes and
https://github.com/c-blake/bu/blob/main/rp.nim#L84 reproducible with
`git clone https://github.com/c-blake/cligen; git clone
https://github.com/c-blake/thes; cd thes; nim c -p=../cligen thes`.
Changing the `const` to `let` makes it compile.

A minimization that is probably the same issue is:

```nim
const a: seq[string] = @[]

proc foo(x = a) =
  echo typeof(x)
  echo x

import macros

macro resemFoo() =
  result = getImpl(bindSym"foo")

block:
  resemFoo() # Error: cannot infer the type of parameter 'x'
```

This should be a regression test in a future reimplementation of #24184.
2024-09-27 15:34:09 +02:00
metagn
2cdc0e913f use cbuilder for tuple/object generation (#24145)
based on #24127

Needs some tweaks to replace the other `struct` type generations, e.g.
seqs, maybe by exposing `BaseTypeKind` as a parameter. C++ and
codegenDecl etc seem like they are going to need attention.

Also `Builder` should really be `distinct string` that one has to call
`extract` on, but for this to be optimal in the current codegen, we
would need something like:

```nim
template buildInto(s: var string, builderName: untyped, body) =
  template `builderName`: untyped = Builder(s)
  body

buildInto(result, builder):
  builder.add ...
```

but this could be a separate PR since it might not work with the
compiler. The possibly-not-optimal alternative is to do:

```nim
template build(builderName: untyped, body): string =
  var `builderName` = Builder("")
  body
  extract(`builderName`)

result = build(builder):
  builder.add ...
```

where the compiler maybe copies the built string but shouldn't.

---------

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
2024-09-27 11:12:39 +02:00
metagn
dc3ffb6a71 consider calling convention and iterator in getType for procs (#24181)
fixes #19010

`getType` for proc types generated an `nkProcTy` for iterator types
instead of `nkIteratorTy`, and didn't generate a calling convention
pragma unless it was in the proc AST. Iterator types now generate
`nkIteratorTy`, and a calling convention pragma is added if the calling
convention isn't `closure` or was explicitly provided.
2024-09-27 11:11:21 +02:00
metagn
56a3dd57fb evaluate all hidden conversions in case branches (#24187)
fixes #11422, refs #8336/#8333, refs #20130

The compiler generates conversion nodes *after* evaluating the branches
of case statements as constants, the reasoning is that case branches
accept constants of different types, like arrays or sets. But this means
that conversion nodes that need to be evaluated like converter calls
don't get evaluated as a constant for codegen. #8336 fixed this by
re-evaluating the node if an `nkHiddenCallConv` was created, and in
#20130 this logic also had to be added for `nkHiddenStdConv` for
cstrings. This logic was only for single case elements, it has now been
added to range elements as well to fix #11422. Additionally, all
conversion nodes are now evaluated for simplicity, but maybe this won't
pass CI.
2024-09-27 11:09:49 +02:00
ringabout
7cccf36d7b improve changelogs (#24188)
Co-authored-by: metagn <metagngn@gmail.com>
2024-09-27 16:46:16 +08:00
ringabout
d4027f25c4 fixes #24175; Sink parameters not copied at compile time (#24178)
fixes #24175
2024-09-27 09:36:09 +02:00
metagn
75b9d66582 treat resolved symbols on RHS of module qualification as identifiers (#24180)
fixes #19866 given #23997

When searching for a module-qualified symbol, `qualifiedLookUp` tries to
obtain the raw identifier from the RHS of the dot field. However it only
does this when the RHS is either an `nkIdent` or an `nkAccQuoted` node,
not when the node is a resolved symbol or a symchoice, such as in
templates and generics when the module symbol can't be resolved yet.
Since the LHS is a module symbol when the compiler checks for this, any
resolved symbol information doesn't matter, since it has to be a member
of the module. So we now obtain the identifier from these nodes as well
as the unresolved identifier nodes.

The test is a bit niche and possibly not officially supported, but this
is likely a more general problem and I just couldn't think of another
test that would be more "proper". It's better than the error message
`'a' has no type` at least.
2024-09-27 09:34:13 +02:00
metagn
c21bf7f41b make default values typed in proc AST same as param sym AST (#24184)
fixes #12942, fixes #19118

This is the exact same as #20735 but maybe the situation has improved
after #24065.
2024-09-27 09:33:40 +02:00
ringabout
62a5bb4d0a fixes #24173; always bundle checksums (#24189)
fixes #24173

`cloneDependency` always has its logic to use existing deps
2024-09-27 09:33:13 +02:00
metagn
fd379c2f94 fix nimsuggest crash with arrow type sugar (#24185)
fixes #24179 

The original fix made it so calls to `skError`/`skUnknown` (in this case
`->`, for some reason `sugar` couldn't be imported) returned an error
node, however this breaks tsug_accquote for some reason I don't
understand (it even parses as `tsug_accquote.discard`) so I've just
added a guard based on the stacktrace.
2024-09-27 06:23:29 +02:00
metagn
1bd5a4a99e render float128 literals (#24182)
fixes #23639

Not sure if these are meant to be supported but it's better than
crashing.
2024-09-27 06:11:21 +02:00
metagn
a27542195c only merge valid implicit pragmas to routine AST, include templates (#24171)
fixes #19277, refs #24169, refs #18124

When pragmas are pushed to a routine, if the routine symbol AST isn't
nil by the time the pushed pragmas are being processed, the pragmas are
implicitly added to the symbol AST. However this is done without
restriction on the pragma, if the pushed pragma isn't supposed to apply
to the routine, it's still added to the routine. This is why the symbol
AST for templates wasn't set before the pushed pragma processing in
#18124. Now, the pragmas added to the AST are restricted to ones that
apply to the given routine. This means we can set the template symbol
AST earlier so that the pragmas get added to the template AST.
2024-09-26 06:34:50 +02:00
Alfred Morgan
69b2a6effc sort modules and added std/setutils (#24168) 2024-09-26 06:29:25 +02:00
ringabout
6d6489a9ab fixes requiresInit for var statements without initialization (#24177)
ref https://forum.nim-lang.org/t/12530
2024-09-26 06:28:40 +02:00
ringabout
3b85c1a2e9 fixes #24167; {.push deprecated.} for templates (#24170)
fixes #24167
2024-09-25 13:00:06 +02:00
metagn
b9de2bb4f3 fix nil literal giving itself type untyped/typed [backport] (#24165)
fixes #24164, regression from #20091

The expression `nil` as the default value of template parameter `x:
untyped` is typechecked with expected type `untyped` since #20091. The
expected type is checked if it matches the `nil` literal with a match
better than a subtype match, and the type is set to it if it does.
However `untyped` matches with a generic match which is better, so the
`nil` literal has type `untyped`. This breaks type matching for the
literal. So if the expected type is `untyped` or `typed`, it is now
ignored and the `nil` literal just has the `nil` type.
2024-09-23 18:18:22 +03:00
Jake Leahy
6f6e34ebb0 Fix line info used for UnunsedImport from subdirectories (#24158)
When importing from subdirectories, the line info used in `UnusedImport`
warning would be the `/` node and not the actual module node. More
obvious with grouped imports where all unused imports would show the
same column

![image](https://github.com/user-attachments/assets/42850130-1e0e-46b9-bd72-54864a1ad41c)

Fix is to just use the last child node for infixes when getting the line
info
2024-09-23 10:14:26 +02:00
metagn
a55c15c651 fix tmarshalsegfault depending on execution time (#24153)
Added in #24119, the test checks if every string produced is equal, but
the value of the strings depend on the `now()` timestamp of when they
were produced. 30 of them are produced in a for loop in sequence with
each other, but the first one is set after the data is marshalled into
and unmarshalled from a file. This means the timestamp strings can
differ depending on the execution time and causes this test to be flaky.
Instead we just make 2 strings from the same data and check if they
equal each other.
2024-09-22 13:57:03 +02:00
metagn
7da2ffb751 fix custom pragma with backticks not working [backport] (#24151)
refs https://forum.nim-lang.org/t/12522
2024-09-22 13:56:40 +02:00
ringabout
5c843d3d60 fixes #24147; Copy hook causes an incompatible-pointer-types (#24149)
fixes #24147
2024-09-22 13:51:51 +02:00
metagn
a1777200c1 fix inTypeofContext leaking after compiles raises exception [backport:2.0] (#24152)
fixes #24150, refs #22022

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

To fix this, `defer:` is used for the `dec c.inTypeofContext` call, as
is done for
[`instCounter`](d51d88700b/compiler/seminst.nim (L374))
in other parts of the compiler.
2024-09-22 13:51:19 +02:00
tocariimaa
d51d88700b Implement removeHandler in std/logging module (fixes #23757) (#24143)
Since the module allows for a handler to be added multiple times, for
the sake of consistency, `removeHandler` only removes the first found
instance of the handler in the `handlers` seq. So for n calls of
`addHandler` using the same handler, n calls of `removeHandler` are
required.

fixes #23757

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2024-09-20 17:32:23 +02:00
Ryan McConnell
37dba853c9 Fix incorrect inheritance penalty for some objects (#24144)
This fixes a logic error in  #23870
The inheritance penalty should be -1 if there is no inheritance
relationship. Not sure how to write a test case for this one honestly.

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
2024-09-20 17:32:07 +02:00
ringabout
755307be61 fixes #24141; Calling algorithm reverse causes a SIGSEGV on ORC (#24142)
fixes #24141
2024-09-19 15:17:25 +02:00
metagn
05a7a48a2b fix inverted order of resolved tyFromExpr match (#24138)
fixes #22276

When matching against `tyFromExpr`, the compiler tries to instantiate it
then operates on the potentially instantiated type. But the way it does
this is inverted, it checks if the instantiated type matches the
argument type, not if the argument type matches the instantiated type.
This has been the case since
ac271e76b1 (diff-251afcd01d239369019495096c187998dd6695b6457528953237a7e4a10f7138),
which doesn't comment on it, so I'm guessing this isn't intended. I
don't know if it would break anything though.
2024-09-19 07:20:29 +02:00
tocariimaa
84f5060e94 Create IPPROTO_NONE alias & Add test for Unix socket (#24139)
closes #24116
2024-09-19 07:19:59 +02:00
metagn
ff005ad7dc fix segfault in generic param mismatch error, skip typedesc (#24140)
refs #24010, refs
https://github.com/nim-lang/Nim/issues/24125#issuecomment-2358377076

The generic mismatch errors added in #24010 made it possible for `nArg`
to be `nil` in the error reporting since it checked the call argument
list, not the generic parameter list for the mismatching argument node,
which causes a segfault. This is fixed by checking the generic parameter
list immediately on any generic mismatch error.

Also the `typedesc` type is skipped for the value of the generic params
since it's redundant and the generic parameter constraints don't have
it.
2024-09-19 07:19:07 +02:00
metagn
6cc50ec316 fix system for nimscript config files on js backend (#24135)
fixes #21441

When compiling for JS, nimscript config files have both `defined(js)`
and `defined(nimscript)` be true at the same time. This is required so
that the nimscript config file knows the current compilation is for the
JS backend. However the system module doesn't account for this in some
cases, defining JS-specific code or not defining nimscript-specific code
when compiling such nimscript files. To fix this, have the `nimscript`
define take priority over the `js` one.
2024-09-19 00:35:29 +02:00
metagn
58cf62451d fix typed case range not counting for exhaustiveness (#24136)
fixes #22661

Range expressions in `of` branches in `case` statements start off as
calls to `..` then become `nkRange` when getting typed. For this reason
the compiler leaves `nkRange` alone when type checking the case
statements again, but it still does the exhaustiveness checking for the
entire case statement, and leaving the range alone means it doesn't
count the values of the range for exhaustiveness. So the counting is now
also done on `nkRange` nodes in the same way as when typechecking it the
first time.
2024-09-18 23:50:58 +02:00
metagn
00ac961ab1 require not nil to be on the same line after a type (#24134)
fixes #23565
2024-09-18 22:45:19 +02:00
metagn
0c3573e4a0 make genericsOpenSym work at instantiation time, new behavior in openSym (#24111)
alternative to #24101

#23892 changed the opensym experimental switch so that it has to be
enabled in the context of the generic/template declarations capturing
the symbols, not the context of the instantiation of the
generics/templates. This was to be in line with where the compiler gives
the warnings and changes behavior in a potentially breaking way.

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

Before it was just a generics-only version of `openSym` along with
`templateOpenSym` which was only for templates. So `templateOpenSym` is
removed along with this change, but no one appears to have used it.
2024-09-18 19:27:09 +02:00
Miran
79b17b7c05 workaround for strunicode package no longer needed (#24132) 2024-09-18 19:16:08 +02:00
metagn
1660ddf98a make var/pointer types not match if base type has to be converted (#24130)
split again from #24038, fixes
https://github.com/status-im/nimbus-eth2/pull/6554#issuecomment-2354977102

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

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

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

Different from #24038 in that the preview define that made subrange
matches also fail to match is removed for a simpler diff so that it can
be backported.
2024-09-18 17:37:18 +02:00
ringabout
c759d7abd1 fixes rst parsing Markdown CodeblockFields blocking the loop (#24128)
```nim
import packages/docutils/[rst, rstgen]

let message = """```llvm-profdata"""

echo rstgen.rstToHtml(message, {roSupportMarkdown}, nil)
```
2024-09-18 17:35:46 +02:00
metagn
04ccd2f4f0 revert second argument of inc not being generic (#24129)
refs #22328, fixes regression in
https://forum.nim-lang.org/t/12465#76998
2024-09-17 21:28:54 +02:00
metagn
680a13a142 fix segfault in effect tracking for sym node with nil type (#24114)
fixes #24112

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

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

Alternatively `semObjConstr` and `semConv` could be changed to set the
type of their first node to the found type but I'm not sure if this
would break anything. They could call `semExprWithType` on the first
node but `semTypeNode` would still have to be called (maybe call it
before?). This isn't a problem if the sym node has a type but is just
nested in `nkOpenSym` or `nkOpenSymChoice` which have nil type instead
(i.e. with openSym enabled), so maybe this still is the "most general"
solution, I don't know.
2024-09-17 14:01:48 +02:00
ringabout
21a161a535 remove nimfrs and varslot (#24126)
was introduced for debugger
b63f322a46 (diff-abd3a10386cf1ae32bfd3ffae82335a1938cc6c6d92be0ee492fcb44b9f2b552)


b63f322a46/lib/system/debugger.nim
2024-09-17 14:01:21 +02:00
metagn
1fbb67ffe9 make distinct conversions addressable in VM (#24124)
fixes #24097

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

This doesn't handle ranges after #24037 because `sameBackendType` is
used and not `sameBackendTypeIgnoreRange`. This is so this is
backportable without #24037 and another PR can be opened that implements
it for ranges and adds tests as well. We can also merge
`sameBackendTypeIgnoreRange` with `sameBackendType` since it doesn't
seem like anything that uses it would be affected (only cycle checks and
the VM), but then we still have to add tests.
2024-09-17 06:29:49 +02:00
metagn
b5f2eafed1 don't match arguments with typeclass type in generics (#24123)
fixes #24121

Proc arguments can have typeclass type like `Foo | Bar` that `sigmatch`
handles specially before matching them to the param type, because they
wouldn't match otherwise. Not exactly sure why this existed but matching
any typeclass or unresolved type in generic contexts now fails the match
so typing the call is delayed until instantiation.

Also it turns out default values with `tyFromExpr` type depending on
other parameters was never tested, this also needs a patch to make the
`tyFromExpr` type `tfNonConstExpr` so it doesn't try to evaluate the
other parameter at compile time.
2024-09-17 06:22:45 +02:00
metagn
fe55dcb2be test case haul before 2.2 (#24119)
closes #4774, closes #7385, closes #10019, closes #12405, closes #12732,
closes #13270, closes #13799, closes #15247, closes #16128, closes
#16175, closes #16774, closes #17527, closes #20880, closes #21346
2024-09-17 09:50:10 +08:00
Juan M Gómez
651fdbe586 Fixes #23624 "nim check crash" (#23625) 2024-09-16 20:45:00 +02:00
ringabout
d0dc4ac22f minor improvement (#24113) 2024-09-16 22:31:39 +08:00
117 changed files with 2035 additions and 552 deletions

View File

@@ -1,195 +1,18 @@
# v2.2.0 - yyyy-mm-dd
# v2.x.x - yyyy-mm-dd
## Changes affecting backward compatibility
- `-d:nimStrictDelete` becomes the default. An index error is produced when the index passed to `system.delete` was out of bounds. Use `-d:nimAuditDelete` to mimic the old behavior for backwards compatibility.
- The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/<version>` instead of `Nim httpclient/<version>` which was incorrect according to the HTTP spec.
- Methods now support implementations based on a VTable by using `--experimental:vtables`. Methods are then confined to be in the same module where their type has been defined.
- With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default.
- A bug where tuple unpacking assignment with a longer tuple on the RHS than the LHS was allowed has been fixed, i.e. code like:
```nim
var a, b: int
(a, b) = (1, 2, 3, 4)
```
will no longer compile.
- `internalNew` is removed from system, use `new` instead.
- `bindMethod` in `std/jsffi` is deprecated, don't use it with closures.
- JS backend now supports lambda lifting for closures. Use `--legacy:jsNoLambdaLifting` to emulate old behavior.
- JS backend now supports closure iterators.
- `owner` in `std/macros` is deprecated.
- Ambiguous type symbols in generic procs and templates now generate symchoice nodes.
Previously; in templates they would error immediately at the template definition,
and in generic procs a type symbol would arbitrarily be captured, losing the
information of the other symbols. This means that generic code can now give
errors for ambiguous type symbols, and macros operating on generic proc AST
may encounter symchoice nodes instead of the arbitrarily resolved type symbol nodes.
- Partial generic instantiation of routines is no longer allowed. Previously
it compiled in niche situations due to bugs in the compiler.
```nim
proc foo[T, U](x: T, y: U) = echo (x, y)
proc foo[T, U](x: var T, y: U) = echo "var ", (x, y)
proc bar[T]() =
foo[float](1, "abc")
bar[int]() # before: (1.0, "abc"), now: type mismatch, missing generic parameter
```
- `const` values now open a new scope for each constant, meaning symbols
declared in them can no longer be used outside or in the value of
other constants.
```nim
const foo = (var a = 1; a)
const bar = a # error
let baz = a # error
```
- The following POSIX wrappers have had their types changed from signed to
unsigned types on OSX and FreeBSD/OpenBSD to correct codegen errors:
- `Gid` (was `int32`, is now `uint32`)
- `Uid` (was `int32`, is now `uint32`)
- `Dev` (was `int32`, is now `uint32` on FreeBSD)
- `Nlink` (was `int16`, is now `uint32` on OpenBSD and `uint16` on OSX/other BSD)
- `sin6_flowinfo` and `sin6_scope_id` fields of `Sockaddr_in6`
(were `int32`, are now `uint32`)
- `n_net` field of `Tnetent` (was `int32`, is now `uint32`)
## Standard library additions and changes
[//]: # "Changes:"
- Changed `std/osfiles.copyFile` to allow to specify `bufferSize` instead of a hardcoded one.
- Changed `std/osfiles.copyFile` to use `POSIX_FADV_SEQUENTIAL` hints for kernel-level aggressive sequential read-aheads.
- `std/htmlparser` has been moved to a nimble package, use `nimble` or `atlas` to install it.
[//]: # "Additions:"
- Added `newStringUninit` to system, which creates a new string of length `len` like `newString` but with uninitialized content.
- Added `setLenUninit` to system, which doesn't initialize
slots when enlarging a sequence.
- Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value.
- Added `rangeBase` to `std/typetraits` to obtain the base type of a range type or
convert a value with a range type to its base type.
- Added Viewport API for the JavaScript targets in the `dom` module.
- Added `toSinglyLinkedRing` and `toDoublyLinkedRing` to `std/lists` to convert from `openArray`s.
- ORC: To be enabled via `nimOrcStats` there is a new API called `GC_orcStats` that can be used to query how many
objects the cyclic collector did free. If the number is zero that is a strong indicator that you can use `--mm:arc`
instead of `--mm:orc`.
- A `$` template is provided for `Path` in `std/paths`.
- `std/hashes.hash(x:string)` changed to produce a 64-bit string `Hash` (based
on Google's Farm Hash) which is also often faster than the present one. Define
`nimStringHash2` to get the old values back. `--jsbigint=off` mode always only
produces the old values. This may impact your automated tests if they depend
on hash order in some obvious or indirect way. Using `sorted` or `OrderedTable`
is often an easy workaround.
[//]: # "Deprecations:"
- Deprecates `system.newSeqUninitialized`, which is replaced by `newSeqUninit`.
[//]: # "Removals:"
## Language changes
- `noInit` can be used in types and fields to disable member initializers in the C++ backend.
- C++ custom constructors initializers see https://nim-lang.org/docs/manual_experimental.html#constructor-initializer
- `member` can be used to attach a procedure to a C++ type.
- C++ `constructor` now reuses `result` instead creating `this`.
- Tuple unpacking changes:
- Tuple unpacking assignment now supports using underscores to discard values.
```nim
var a, c: int
(a, _, c) = (1, 2, 3)
```
- Tuple unpacking variable declarations now support type annotations, but
only for the entire tuple.
```nim
let (a, b): (int, int) = (1, 2)
let (a, (b, c)): (byte, (float, cstring)) = (1, (2, "abc"))
```
- The experimental option `--experimental:openSym` has been added to allow
captured symbols in generic routine and template bodies respectively to be
replaced by symbols injected locally by templates/macros at instantiation
time. `bind` may be used to keep the captured symbols over the injected ones
regardless of enabling the option, but other methods like renaming the
captured symbols should be used instead so that the code is not affected by
context changes.
Since this change may affect runtime behavior, the experimental switch
`openSym`, or `genericsOpenSym` and `templateOpenSym` for only the respective
routines, needs to be enabled; and a warning is given in the case where an
injected symbol would replace a captured symbol not bound by `bind` and
the experimental switch isn't enabled.
```nim
const value = "captured"
template foo(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
body
proc old[T](): string =
foo(123):
return value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
echo old[int]() # "captured"
template oldTempl(): string =
block:
foo(123):
value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
echo oldTempl() # "captured"
{.experimental: "openSym".} # or {.experimental: "genericsOpenSym".} for just generic procs
proc bar[T](): string =
foo(123):
return value
assert bar[int]() == "injected" # previously it would be "captured"
proc baz[T](): string =
bind value
foo(123):
return value
assert baz[int]() == "captured"
# {.experimental: "templateOpenSym".} would be needed here if genericsOpenSym was used
template barTempl(): string =
block:
foo(123):
value
assert barTempl() == "injected" # previously it would be "captured"
template bazTempl(): string =
bind value
block:
foo(123):
value
assert bazTempl() == "captured"
```
This option also generates a new node kind `nnkOpenSym` which contains
exactly 1 `nnkSym` node. In the future this might be merged with a slightly
modified `nnkOpenSymChoice` node but macros that want to support the
experimental feature should still handle `nnkOpenSym`, as the node kind would
simply not be generated as opposed to being removed.
## Compiler changes
- `--nimcache` using a relative path as the argument in a config file is now relative to the config file instead of the current directory.
## Tool changes
- 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,12 +1,248 @@
# v2.2.0 - 2023-mm-dd
# v2.2.0 - 2024-10-02
## Changes affecting backward compatibility
- `-d:nimStrictDelete` becomes the default. An index error is produced when the index passed to `system.delete` is out of bounds. Use `-d:nimAuditDelete` to mimic the old behavior for backward compatibility.
- The default user-agent in `std/httpclient` has been changed to `Nim-httpclient/<version>` instead of `Nim httpclient/<version>` which was incorrect according to the HTTP spec.
- Methods now support implementations based on a VTable by using `--experimental:vtables`. Methods are then confined to the same module where their type has been defined.
- With `-d:nimPreviewNonVarDestructor`, non-var destructors become the default.
- A bug where tuple unpacking assignment with a longer tuple on the RHS than the LHS was allowed has been fixed, i.e. code like:
```nim
var a, b: int
(a, b) = (1, 2, 3, 4)
```
will no longer compile.
- `internalNew` is removed from the `system` module, use `new` instead.
- `bindMethod` in `std/jsffi` is deprecated, don't use it with closures.
- JS backend now supports lambda lifting for closures. Use `--legacy:jsNoLambdaLifting` to emulate old behaviors.
- JS backend now supports closure iterators.
- `owner` in `std/macros` is deprecated.
- Ambiguous type symbols in generic procs and templates now generate symchoice nodes.
Previously; in templates they would error immediately at the template definition,
and in generic procs a type symbol would arbitrarily be captured, losing the
information of the other symbols. This means that generic code can now give
errors for ambiguous type symbols, and macros operating on generic proc AST
may encounter symchoice nodes instead of the arbitrarily resolved type symbol nodes.
- Partial generic instantiation of routines is no longer allowed. Previously
it compiled in niche situations due to bugs in the compiler.
```nim
proc foo[T, U](x: T, y: U) = echo (x, y)
proc foo[T, U](x: var T, y: U) = echo "var ", (x, y)
proc bar[T]() =
foo[float](1, "abc")
bar[int]() # before: (1.0, "abc"), now: type mismatch, missing generic parameter
```
- `const` values now open a new scope for each constant, meaning symbols
declared in them can no longer be used outside or in the value of
other constants.
```nim
const foo = (var a = 1; a)
const bar = a # error
let baz = a # error
```
- The following POSIX wrappers have had their types changed from signed to
unsigned types on OSX and FreeBSD/OpenBSD to correct codegen errors:
- `Gid` (was `int32`, is now `uint32`)
- `Uid` (was `int32`, is now `uint32`)
- `Dev` (was `int32`, is now `uint32` on FreeBSD)
- `Nlink` (was `int16`, is now `uint32` on OpenBSD and `uint16` on OSX/other BSD)
- `sin6_flowinfo` and `sin6_scope_id` fields of `Sockaddr_in6`
(were `int32`, are now `uint32`)
- `n_net` field of `Tnetent` (was `int32`, is now `uint32`)
- The `Atomic[T]` type on C++ now uses C11 primitives by default instead of
`std::atomic`. To use `std::atomic` instead, `-d:nimUseCppAtomics` can be defined.
## Standard library additions and changes
[//]: # "Changes:"
- Changed `std/osfiles.copyFile` to allow specifying `bufferSize` instead of a hard-coded one.
- Changed `std/osfiles.copyFile` to use `POSIX_FADV_SEQUENTIAL` hints for kernel-level aggressive sequential read-aheads.
- `std/htmlparser` has been moved to a nimble package, use `nimble` or `atlas` to install it.
- Changed `std/os.copyDir` and `copyDirWithPermissions` to allow skipping special "file" objects like FIFOs, device files, etc on Unix by specifying a `skipSpecial` parameter.
[//]: # "Additions:"
- Added `newStringUninit` to the `system` module, which creates a new string of length `len` like `newString` but with uninitialized content.
- Added `setLenUninit` to the `system` module, which doesn't initialize
slots when enlarging a sequence.
- Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value.
- Added `rangeBase` to `std/typetraits` to obtain the base type of a range type or
convert a value with a range type to its base type.
- Added Viewport API for the JavaScript targets in the `dom` module.
- Added `toSinglyLinkedRing` and `toDoublyLinkedRing` to `std/lists` to convert from `openArray`s.
- ORC: To be enabled via `nimOrcStats` there is a new API called `GC_orcStats` that can be used to query how many
objects the cyclic collector did free. If the number is zero that is a strong indicator that you can use `--mm:arc`
instead of `--mm:orc`.
- A `$` template is provided for `Path` in `std/paths`.
- `std/hashes.hash(x:string)` changed to produce a 64-bit string `Hash` (based
on Google's Farm Hash) which is also often faster than the present one. Define
`nimStringHash2` to get the old values back. `--jsbigint=off` mode always only
produces the old values. This may impact your automated tests if they depend
on hash order in some obvious or indirect way. Using `sorted` or `OrderedTable`
is often an easy workaround.
[//]: # "Deprecations:"
- Deprecates `system.newSeqUninitialized`, which is replaced by `newSeqUninit`.
[//]: # "Removals:"
## Language changes
- `noInit` can be used in types and fields to disable member initializers in the C++ backend.
- C++ custom constructors initializers see https://nim-lang.org/docs/manual_experimental.html#constructor-initializer
- `member` can be used to attach a procedure to a C++ type.
- C++ `constructor` now reuses `result` instead creating `this`.
- Tuple unpacking changes:
- Tuple unpacking assignment now supports using underscores to discard values.
```nim
var a, c: int
(a, _, c) = (1, 2, 3)
```
- Tuple unpacking variable declarations now support type annotations, but
only for the entire tuple.
```nim
let (a, b): (int, int) = (1, 2)
let (a, (b, c)): (byte, (float, cstring)) = (1, (2, "abc"))
```
- The experimental option `--experimental:openSym` has been added to allow
captured symbols in generic routine and template bodies respectively to be
replaced by symbols injected locally by templates/macros at instantiation
time. `bind` may be used to keep the captured symbols over the injected ones
regardless of enabling the option, but other methods like renaming the
captured symbols should be used instead so that the code is not affected by
context changes.
Since this change may affect runtime behavior, the experimental switch
`openSym` needs to be enabled; and a warning is given in the case where an
injected symbol would replace a captured symbol not bound by `bind` and
the experimental switch isn't enabled.
```nim
const value = "captured"
template foo(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
body
proc old[T](): string =
foo(123):
return value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
echo old[int]() # "captured"
template oldTempl(): string =
block:
foo(123):
value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
echo oldTempl() # "captured"
{.experimental: "openSym".}
proc bar[T](): string =
foo(123):
return value
assert bar[int]() == "injected" # previously it would be "captured"
proc baz[T](): string =
bind value
foo(123):
return value
assert baz[int]() == "captured"
template barTempl(): string =
block:
foo(123):
value
assert barTempl() == "injected" # previously it would be "captured"
template bazTempl(): string =
bind value
block:
foo(123):
value
assert bazTempl() == "captured"
```
This option also generates a new node kind `nnkOpenSym` which contains
exactly 1 `nnkSym` node. In the future this might be merged with a slightly
modified `nnkOpenSymChoice` node but macros that want to support the
experimental feature should still handle `nnkOpenSym`, as the node kind would
simply not be generated as opposed to being removed.
Another experimental switch `genericsOpenSym` exists that enables this behavior
at instantiation time, meaning templates etc can enable it specifically when
they are being called. However this does not generate `nnkOpenSym` nodes
(unless the other switch is enabled) and so doesn't reflect the regular
behavior of the switch.
```nim
const value = "captured"
template foo(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
{.push experimental: "genericsOpenSym".}
body
{.pop.}
proc bar[T](): string =
foo(123):
return value
echo bar[int]() # "injected"
template barTempl(): string =
block:
var res: string
foo(123):
res = value
res
assert barTempl() == "injected"
```
## Compiler changes
- `--nimcache` using a relative path as the argument in a config file is now relative to the config file instead of the current directory.
## Tool changes
- koch now allows bootstrapping with `-d:nimHasLibFFI`, replacing the older option of building the compiler directly w/ the `libffi` nimble package.

View File

@@ -1,4 +1,4 @@
# v1.xx.x - yyyy-mm-dd
# v2.xx.x - yyyy-mm-dd
This is an example file.
The changes should go to changelog.md!

View File

@@ -1057,8 +1057,11 @@ proc getDeclPragma*(n: PNode): PNode =
proc extractPragma*(s: PSym): PNode =
## gets the pragma node of routine/type/var/let/const symbol `s`
if s.kind in routineKinds:
result = s.ast[pragmasPos]
if s.kind in routineKinds: # bug #24167
if s.ast[pragmasPos] != nil and s.ast[pragmasPos].kind != nkEmpty:
result = s.ast[pragmasPos]
else:
result = nil
elif s.kind in {skType, skVar, skLet, skConst}:
if s.ast != nil and s.ast.len > 0:
if s.ast[0].kind == nkPragmaExpr and s.ast[0].len > 1:

121
compiler/cbuilder.nim Normal file
View File

@@ -0,0 +1,121 @@
type
Snippet = string
Builder = string
template newBuilder(s: string): Builder =
s
proc addField(obj: var Builder; name, typ: Snippet) =
obj.add('\t')
obj.add(typ)
obj.add(" ")
obj.add(name)
obj.add(";\n")
proc addField(obj: var Builder; field: PSym; name, typ: Snippet; isFlexArray: bool; initializer: Snippet) =
obj.add('\t')
if field.alignment > 0:
obj.add("NIM_ALIGN(")
obj.addInt(field.alignment)
obj.add(") ")
obj.add(typ)
if sfNoalias in field.flags:
obj.add(" NIM_NOALIAS")
obj.add(" ")
obj.add(name)
if isFlexArray:
obj.add("[SEQ_DECL_SIZE]")
if field.bitsize != 0:
obj.add(":")
obj.addInt(field.bitsize)
if initializer.len != 0:
obj.add(initializer)
obj.add(";\n")
proc structOrUnion(t: PType): Snippet =
let t = t.skipTypes({tyAlias, tySink})
if tfUnion in t.flags: "union"
else: "struct"
proc ptrType(t: Snippet): Snippet =
t & "*"
template addStruct(obj: var Builder; m: BModule; typ: PType; name: string; baseType: string; body: typed) =
if tfPacked in typ.flags:
if hasAttribute in CC[m.config.cCompiler].props:
obj.add(structOrUnion(typ))
obj.add(" __attribute__((__packed__))")
else:
obj.add("#pragma pack(push, 1)\n")
obj.add(structOrUnion(typ))
else:
obj.add(structOrUnion(typ))
obj.add(" ")
obj.add(name)
type BaseClassKind = enum
bcNone, bcCppInherit, bcSupField, bcNoneRtti, bcNoneTinyRtti
var baseKind = bcNone
if typ.kind == tyObject:
if typ.baseClass == nil:
if lacksMTypeField(typ):
baseKind = bcNone
elif optTinyRtti in m.config.globalOptions:
baseKind = bcNoneTinyRtti
else:
baseKind = bcNoneRtti
elif m.compileToCpp:
baseKind = bcCppInherit
else:
baseKind = bcSupField
if baseKind == bcCppInherit:
obj.add(" : public ")
obj.add(baseType)
obj.add(" ")
obj.add("{\n")
let currLen = obj.len
case baseKind
of bcNone:
# rest of the options add a field or don't need it due to inheritance,
# we need to add the dummy field for uncheckedarray ahead of time
# so that it remains trailing
if typ.itemId notin m.g.graph.memberProcsPerType and
typ.n != nil and typ.n.len == 1 and typ.n[0].kind == nkSym and
typ.n[0].sym.typ.skipTypes(abstractInst).kind == tyUncheckedArray:
# only consists of flexible array field, add *initial* dummy field
obj.addField(name = "dummy", typ = "char")
of bcCppInherit: discard
of bcNoneRtti:
obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimType")))
of bcNoneTinyRtti:
obj.addField(name = "m_type", typ = ptrType(cgsymValue(m, "TNimTypeV2")))
of bcSupField:
obj.addField(name = "Sup", typ = baseType)
body
if baseKind == bcNone and currLen == obj.len and typ.itemId notin m.g.graph.memberProcsPerType:
# no fields were added, add dummy field
obj.addField(name = "dummy", typ = "char")
obj.add("};\n")
if tfPacked in typ.flags and hasAttribute notin CC[m.config.cCompiler].props:
result.add("#pragma pack(pop)\n")
template addFieldWithStructType(obj: var Builder; m: BModule; parentTyp: PType; fieldName: string, body: typed) =
## adds a field with a `struct { ... }` type, building it according to `body`
obj.add('\t')
if tfPacked in parentTyp.flags:
if hasAttribute in CC[m.config.cCompiler].props:
obj.add("struct __attribute__((__packed__)) {\n")
else:
obj.add("#pragma pack(push, 1)\nstruct {")
else:
obj.add("struct {\n")
body
obj.add("} ")
obj.add(fieldName)
obj.add(";\n")
if tfPacked in parentTyp.flags and hasAttribute notin CC[m.config.cCompiler].props:
result.add("#pragma pack(pop)\n")
template addAnonUnion(obj: var Builder; body: typed) =
obj.add "union{\n"
body
obj.add("};\n")

View File

@@ -376,11 +376,6 @@ proc getTypePre(m: BModule; typ: PType; sig: SigHash): Rope =
result = getSimpleTypeDesc(m, typ)
if result == "": result = cacheGetType(m.typeCache, sig)
proc structOrUnion(t: PType): Rope =
let t = t.skipTypes({tyAlias, tySink})
if tfUnion in t.flags: "union"
else: "struct"
proc addForwardStructFormat(m: BModule; structOrUnion: Rope, typename: Rope) =
if m.compileToCpp:
m.s[cfsForwardTypes].addf "$1 $2;$n", [structOrUnion, typename]
@@ -698,7 +693,7 @@ proc genCppInitializer(m: BModule, prc: BProc; typ: PType; didGenTemp: var bool)
proc genRecordFieldsAux(m: BModule; n: PNode,
rectype: PType,
check: var IntSet; result: var Rope; unionPrefix = "") =
check: var IntSet; result: var Builder; unionPrefix = "") =
case n.kind
of nkRecList:
for i in 0..<n.len:
@@ -715,64 +710,51 @@ proc genRecordFieldsAux(m: BModule; n: PNode,
let k = lastSon(n[i])
if k.kind != nkSym:
let structName = "_" & mangleRecFieldName(m, n[0].sym) & "_" & $i
var a = newRopeAppender()
var a = newBuilder("")
genRecordFieldsAux(m, k, rectype, check, a, unionPrefix & $structName & ".")
if a != "":
if tfPacked notin rectype.flags:
unionBody.add("struct {")
else:
if hasAttribute in CC[m.config.cCompiler].props:
unionBody.add("struct __attribute__((__packed__)){")
else:
unionBody.addf("#pragma pack(push, 1)$nstruct{", [])
unionBody.add(a)
unionBody.addf("} $1;$n", [structName])
if tfPacked in rectype.flags and hasAttribute notin CC[m.config.cCompiler].props:
unionBody.addf("#pragma pack(pop)$n", [])
if a.len != 0:
unionBody.addFieldWithStructType(m, rectype, structName):
unionBody.add(a)
else:
genRecordFieldsAux(m, k, rectype, check, unionBody, unionPrefix)
else: internalError(m.config, "genRecordFieldsAux(record case branch)")
if unionBody != "":
result.addf("union{\n$1};$n", [unionBody])
if unionBody.len != 0:
result.addAnonUnion:
result.add(unionBody)
of nkSym:
let field = n.sym
if field.typ.kind == tyVoid: return
#assert(field.ast == nil)
let sname = mangleRecFieldName(m, field)
fillLoc(field.loc, locField, n, unionPrefix & sname, OnUnknown)
if field.alignment > 0:
result.addf "NIM_ALIGN($1) ", [rope(field.alignment)]
# for importcpp'ed objects, we only need to set field.loc, but don't
# have to recurse via 'getTypeDescAux'. And not doing so prevents problems
# with heavily templatized C++ code:
if not isImportedCppType(rectype):
let noAlias = if sfNoalias in field.flags: " NIM_NOALIAS" else: ""
let fieldType = field.loc.lode.typ.skipTypes(abstractInst)
var typ: Rope = ""
var isFlexArray = false
var initializer = ""
if fieldType.kind == tyUncheckedArray:
result.addf("\t$1 $2[SEQ_DECL_SIZE];$n",
[getTypeDescAux(m, fieldType.elemType, check, dkField), sname])
typ = getTypeDescAux(m, fieldType.elemType, check, dkField)
isFlexArray = true
elif fieldType.kind == tySequence:
# we need to use a weak dependency here for trecursive_table.
result.addf("\t$1$3 $2;$n", [getTypeDescWeak(m, field.loc.t, check, dkField), sname, noAlias])
elif field.bitsize != 0:
result.addf("\t$1$4 $2:$3;$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, rope($field.bitsize), noAlias])
typ = getTypeDescWeak(m, field.loc.t, check, dkField)
else:
typ = getTypeDescAux(m, field.loc.t, check, dkField)
# don't use fieldType here because we need the
# tyGenericInst for C++ template support
let noInit = sfNoInit in field.flags or (field.typ.sym != nil and sfNoInit in field.typ.sym.flags)
if not noInit and (fieldType.isOrHasImportedCppType() or hasCppCtor(m, field.owner.typ)):
var didGenTemp = false
var initializer = genCppInitializer(m, nil, fieldType, didGenTemp)
result.addf("\t$1$3 $2$4;$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias, initializer])
else:
result.addf("\t$1$3 $2;$n", [getTypeDescAux(m, field.loc.t, check, dkField), sname, noAlias])
initializer = genCppInitializer(m, nil, fieldType, didGenTemp)
result.addField(field, sname, typ, isFlexArray, initializer)
else: internalError(m.config, n.info, "genRecordFieldsAux()")
proc genMemberProcHeader(m: BModule; prc: PSym; result: var Rope; asPtr: bool = false, isFwdDecl:bool = false)
proc getRecordFields(m: BModule; typ: PType, check: var IntSet): Rope =
result = newRopeAppender()
proc addRecordFields(result: var Builder; m: BModule; typ: PType, check: var IntSet) =
genRecordFieldsAux(m, typ.n, typ, check, result)
if typ.itemId in m.g.graph.memberProcsPerType:
let procs = m.g.graph.memberProcsPerType[typ.itemId]
@@ -794,88 +776,34 @@ proc fillObjectFields*(m: BModule; typ: PType) =
# sometimes generic objects are not consistently merged. We patch over
# this fact here.
var check = initIntSet()
discard getRecordFields(m, typ, check)
var ignored = newBuilder("")
addRecordFields(ignored, m, typ, check)
proc mangleDynLibProc(sym: PSym): Rope
proc getRecordDescAux(m: BModule; typ: PType, name, baseType: Rope,
check: var IntSet, hasField:var bool): Rope =
result = ""
if typ.kind == tyObject:
if typ.baseClass == nil:
if lacksMTypeField(typ):
appcg(m, result, " {$n", [])
else:
if optTinyRtti in m.config.globalOptions:
appcg(m, result, " {$n#TNimTypeV2* m_type;$n", [])
else:
appcg(m, result, " {$n#TNimType* m_type;$n", [])
hasField = true
elif m.compileToCpp:
appcg(m, result, " : public $1 {$n", [baseType])
if typ.isException and m.config.exc == excCpp:
when false:
appcg(m, result, "virtual void raise() { throw *this; }$n", []) # required for polymorphic exceptions
if typ.sym.magic == mException:
# Add cleanup destructor to Exception base class
appcg(m, result, "~$1();$n", [name])
# define it out of the class body and into the procs section so we don't have to
# artificially forward-declare popCurrentExceptionEx (very VERY troublesome for HCR)
appcg(m, cfsProcs, "inline $1::~$1() {if(this->raiseId) #popCurrentExceptionEx(this->raiseId);}$n", [name])
hasField = true
else:
appcg(m, result, " {$n $1 Sup;$n", [baseType])
hasField = true
else:
result.addf(" {$n", [name])
proc getRecordDesc(m: BModule; typ: PType, name: Rope,
check: var IntSet): Rope =
# declare the record:
var hasField = false
var structOrUnion: string
if tfPacked in typ.flags:
if hasAttribute in CC[m.config.cCompiler].props:
structOrUnion = structOrUnion(typ) & " __attribute__((__packed__))"
else:
structOrUnion = "#pragma pack(push, 1)\L" & structOrUnion(typ)
else:
structOrUnion = structOrUnion(typ)
var baseType: string = ""
if typ.baseClass != nil:
baseType = getTypeDescAux(m, typ.baseClass.skipTypes(skipPtrs), check, dkField)
if typ.sym == nil or sfCodegenDecl notin typ.sym.flags:
result = structOrUnion & " " & name
result.add(getRecordDescAux(m, typ, name, baseType, check, hasField))
let desc = getRecordFields(m, typ, check)
if not hasField and typ.itemId notin m.g.graph.memberProcsPerType:
if desc == "":
result.add("\tchar dummy;\n")
elif typ.n.len == 1 and typ.n[0].kind == nkSym:
let field = typ.n[0].sym
let fieldType = field.typ.skipTypes(abstractInst)
if fieldType.kind == tyUncheckedArray:
result.add("\tchar dummy;\n")
result.add(desc)
else:
result.add(desc)
result.add("};\L")
result = newBuilder("")
result.addStruct(m, typ, name, baseType):
result.addRecordFields(m, typ, check)
else:
let desc = getRecordFields(m, typ, check)
var desc = newBuilder("")
desc.addRecordFields(m, typ, check)
result = runtimeFormat(typ.sym.cgDeclFrmt, [name, desc, baseType])
if tfPacked in typ.flags and hasAttribute notin CC[m.config.cCompiler].props:
result.add "#pragma pack(pop)\L"
proc getTupleDesc(m: BModule; typ: PType, name: Rope,
check: var IntSet): Rope =
result = "$1 $2 {$n" % [structOrUnion(typ), name]
var desc: Rope = ""
for i, a in typ.ikids:
desc.addf("$1 Field$2;$n",
[getTypeDescAux(m, a, check, dkField), rope(i)])
if desc == "": result.add("char dummy;\L")
else: result.add(desc)
result.add("};\L")
result = newBuilder("")
result.addStruct(m, typ, name, ""):
for i, a in typ.ikids:
result.addField(
name = "Field" & $i,
typ = getTypeDescAux(m, a, check, dkField))
proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool =
# A helper proc for handling cppimport patterns, involving numeric
@@ -932,12 +860,11 @@ proc getTypeDescAux(m: BModule; origTyp: PType, check: var IntSet; kind: TypeDes
if t != origTyp and origTyp.sym != nil: useHeader(m, origTyp.sym)
let sig = hashType(origTyp, m.config)
result = "" # todo move `result = getTypePre(m, t, sig)` here ?
result = getTypePre(m, t, sig)
defer: # defer is the simplest in this case
if isImportedType(t) and not m.typeABICache.containsOrIncl(sig):
addAbiCheck(m, t, result)
result = getTypePre(m, t, sig)
if result != "" and t.kind != tyOpenArray:
excl(check, t.id)
if kind == dkRefParam or kind == dkRefGenericParam and origTyp.kind == tyGenericInst:

View File

@@ -373,6 +373,7 @@ proc dataField(p: BProc): Rope =
proc genProcPrototype(m: BModule, sym: PSym)
include cbuilder
include ccgliterals
include ccgtypes
@@ -783,15 +784,11 @@ $1define nimfr_(proc, file) \
TFrame FR_; \
FR_.procname = proc; FR_.filename = file; FR_.line = 0; FR_.len = 0; #nimFrame(&FR_);
$1define nimfrs_(proc, file, slots, length) \
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) \
FR_.line = n;
$1define nimln_(n) \
FR_.line = n;
$1define nimlf_(n, file) \
FR_.line = n; FR_.filename = file;
$1define nimlf_(n, file) \
FR_.line = n; FR_.filename = file;
"""
if p.module.s[cfsFrameDefines].len == 0:

View File

@@ -167,4 +167,5 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimHasVtables")
defineSymbol("nimHasGenericsOpenSym2")
defineSymbol("nimHasGenericsOpenSym3")
defineSymbol("nimHasJsNoLambdaLifting")

View File

@@ -1000,10 +1000,11 @@ proc jsonBuildInstructionsFile*(conf: ConfigRef): AbsoluteFile =
# works out of the box with `hashMainCompilationParams`.
result = getNimcacheDir(conf) / conf.outFile.changeFileExt("json")
const cacheVersion = "D20210525T193831" # update when `BuildCache` spec changes
const cacheVersion = "D20240927T193831" # update when `BuildCache` spec changes
type BuildCache = object
cacheVersion: string
outputFile: string
outputLastModificationTime: string
compile: seq[(string, string)]
link: seq[string]
linkcmd: string
@@ -1047,6 +1048,8 @@ proc writeJsonBuildInstructions*(conf: ConfigRef; deps: StringTableRef) =
bcache.depfiles.add (path, $secureHashFile(path))
bcache.nimexe = hashNimExe()
if fileExists(bcache.outputFile):
bcache.outputLastModificationTime = $getLastModificationTime(bcache.outputFile)
conf.jsonBuildFile = conf.jsonBuildInstructionsFile
conf.jsonBuildFile.string.writeFile(bcache.toJson.pretty)
@@ -1067,6 +1070,8 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: Absolute
# xxx optimize by returning false if stdin input was the same
for (file, hash) in bcache.depfiles:
if $secureHashFile(file) != hash: return true
if bcache.outputLastModificationTime != $getLastModificationTime(bcache.outputFile):
return true
proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
var bcache: BuildCache = default(BuildCache)
@@ -1083,7 +1088,7 @@ proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
"jsonscript command outputFile '$1' must match '$2' which was specified during --compileOnly, see \"outputFile\" entry in '$3' " %
[outputCurrent, output, jsonFile.string])
var cmds: TStringSeq = default(TStringSeq)
var prettyCmds: TStringSeq= default(TStringSeq)
var prettyCmds: TStringSeq = default(TStringSeq)
let prettyCb = proc (idx: int) = writePrettyCmdsStderr(prettyCmds[idx])
for (name, cmd) in bcache.compile:
cmds.add cmd

View File

@@ -246,7 +246,8 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym, importHidden: bool)
result = createModuleAliasImpl(realModule.name)
if importHidden:
result.options.incl optImportHidden
c.unusedImports.add((result, n.info))
let moduleIdent = if n.kind == nkInfix: n[^1] else: n
c.unusedImports.add((result, moduleIdent.info))
c.importModuleMap[result.id] = realModule.id
c.importModuleLookup.mgetOrPut(result.name.id, @[]).addUnique realModule.id

View File

@@ -317,8 +317,9 @@ proc isCriticalLink(dest: PNode): bool {.inline.} =
]#
result = dest.kind != nkSym
proc finishCopy(c: var Con; result, dest: PNode; isFromSink: bool) =
if c.graph.config.selectedGC == gcOrc:
proc finishCopy(c: var Con; result, dest: PNode; flags: set[MoveOrCopyFlag]; isFromSink: bool) =
if c.graph.config.selectedGC == gcOrc and IsExplicitSink notin flags:
# add cyclic flag, but not to sink calls, which IsExplicitSink generates
let t = dest.typ.skipTypes(tyUserTypeClasses + {tyGenericInst, tyAlias, tySink, tyDistinct})
if cyclicType(c.graph, t):
result.add boolLit(c.graph, result.info, isFromSink or isCriticalLink(dest))
@@ -464,7 +465,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
var newCall = newTreeIT(nkCall, src.info, src.typ,
newSymNode(op),
src)
c.finishCopy(newCall, n, isFromSink = true)
c.finishCopy(newCall, n, {}, isFromSink = true)
result.add newTreeI(nkFastAsgn,
src.info, tmp,
newCall
@@ -473,7 +474,7 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
result.add c.genWasMoved(tmp)
var m = c.genCopy(tmp, n, {})
m.add p(n, c, s, normal)
c.finishCopy(m, n, isFromSink = true)
c.finishCopy(m, n, {}, isFromSink = true)
result.add m
if isLValue(n) and not isCapturedVar(n) and nTyp.skipTypes(abstractInst).kind != tyRef and c.inSpawn == 0:
message(c.graph.config, n.info, hintPerformance,
@@ -761,7 +762,7 @@ proc pRaiseStmt(n: PNode, c: var Con; s: var Scope): PNode =
let tmp = c.getTemp(s, n[0].typ, n.info)
var m = c.genCopyNoCheck(tmp, n[0], attachedAsgn)
m.add p(n[0], c, s, normal)
c.finishCopy(m, n[0], isFromSink = false)
c.finishCopy(m, n[0], {}, isFromSink = false)
result = newTree(nkStmtList, c.genWasMoved(tmp), m)
var toDisarm = n[0]
if toDisarm.kind == nkStmtListExpr: toDisarm = toDisarm.lastSon
@@ -1173,7 +1174,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
c.finishCopy(result, dest, flags, isFromSink = false)
of nkBracket:
# array constructor
if ri.len > 0 and isDangerousSeq(ri.typ):
@@ -1181,7 +1182,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
c.finishCopy(result, dest, flags, isFromSink = false)
else:
result = c.genSink(s, dest, p(ri, c, s, consumed), flags)
of nkObjConstr, nkTupleConstr, nkClosure, nkCharLit..nkNilLit:
@@ -1202,7 +1203,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
c.finishCopy(result, dest, flags, isFromSink = false)
of nkHiddenSubConv, nkHiddenStdConv, nkConv, nkObjDownConv, nkObjUpConv, nkCast:
result = c.genSink(s, dest, p(ri, c, s, sinkArg), flags)
of nkStmtListExpr, nkBlockExpr, nkIfExpr, nkCaseStmt, nkTryStmt:
@@ -1222,7 +1223,7 @@ proc moveOrCopy(dest, ri: PNode; c: var Con; s: var Scope, flags: set[MoveOrCopy
result = c.genCopy(dest, ri, flags)
dec c.inEnsureMove, isEnsureMove
result.add p(ri, c, s, consumed)
c.finishCopy(result, dest, isFromSink = false)
c.finishCopy(result, dest, flags, isFromSink = false)
when false:
proc computeUninit(c: var Con) =

View File

@@ -224,10 +224,16 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool,
proc fillBodyObjTImpl(c: var TLiftCtx; t: PType, body, x, y: PNode) =
if t.baseClass != nil:
let obj = newNodeIT(nkHiddenSubConv, c.info, t.baseClass)
obj.add newNodeI(nkEmpty, c.info)
obj.add x
fillBody(c, skipTypes(t.baseClass, abstractPtrs), body, obj, y)
let dest = newNodeIT(nkHiddenSubConv, c.info, t.baseClass)
dest.add newNodeI(nkEmpty, c.info)
dest.add x
var src = y
if c.kind in {attachedAsgn, attachedDeepCopy, attachedSink}:
src = newNodeIT(nkHiddenSubConv, c.info, t.baseClass)
src.add newNodeI(nkEmpty, c.info)
src.add y
fillBody(c, skipTypes(t.baseClass, abstractPtrs), body, dest, src)
fillBodyObj(c, t.n, body, x, y, enforceDefaultOp = false)
proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =

View File

@@ -685,10 +685,12 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
var m = qualifiedLookUp(c, n[0], (flags * {checkUndeclared}) + {checkModule})
if m != nil and m.kind == skModule:
var ident: PIdent = nil
if n[1].kind == nkIdent:
ident = n[1].ident
elif n[1].kind == nkAccQuoted:
if n[1].kind == nkAccQuoted:
ident = considerQuotedIdent(c, n[1])
else:
# this includes sym and symchoice nodes, but since we are looking in
# a module, it shouldn't matter what was captured
ident = n[1].getPIdent
if ident != nil:
if m == c.module:
var ti: TIdentIter = default(TIdentIter)

View File

@@ -629,7 +629,7 @@ proc warningDeprecated*(conf: ConfigRef, info: TLineInfo = gCmdLineInfo, msg = "
message(conf, info, warnDeprecated, msg)
proc internalErrorImpl(conf: ConfigRef; info: TLineInfo, errMsg: string, info2: InstantiationInfo) =
if conf.cmd == cmdIdeTools and conf.structuredErrorHook.isNil: return
if conf.cmd in {cmdIdeTools, cmdCheck} and conf.structuredErrorHook.isNil: return
writeContext(conf, info)
liMessage(conf, info, errInternal, errMsg, doAbort, info2)

View File

@@ -226,8 +226,8 @@ type
strictCaseObjects,
inferGenericTypes,
openSym, # remove nfDisabledOpenSym when this is default
# separated alternatives to above:
genericsOpenSym, templateOpenSym,
# alternative to above:
genericsOpenSym
vtables
LegacyFeature* = enum

View File

@@ -1401,7 +1401,7 @@ proc primary(p: var Parser, mode: PrimaryMode): PNode =
result = primarySuffix(p, result, baseInd, mode)
proc binaryNot(p: var Parser; a: PNode): PNode =
if p.tok.tokType == tkNot:
if p.tok.tokType == tkNot and p.tok.indent < 0:
let notOpr = newIdentNodeP(p.tok.ident, p)
getTok(p)
optInd(p, notOpr)

View File

@@ -800,13 +800,14 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym =
proc semCustomPragma(c: PContext, n: PNode, sym: PSym): PNode =
var callNode: PNode
if n.kind in {nkIdent, nkSym}:
case n.kind
of nkIdentKinds:
# pragma -> pragma()
callNode = newTree(nkCall, n)
elif n.kind == nkExprColonExpr:
of nkExprColonExpr:
# pragma: arg -> pragma(arg)
callNode = newTree(nkCall, n[0], n[1])
elif n.kind in nkPragmaCallKinds:
of nkPragmaCallKinds - {nkExprColonExpr}:
callNode = n
else:
invalidPragma(c, n)
@@ -1343,6 +1344,16 @@ proc mergePragmas(n, pragmas: PNode) =
else:
for p in pragmas: n[pragmasPos].add p
proc mergeValidPragmas(n, pragmas: PNode, validPragmas: TSpecialWords) =
if n[pragmasPos].kind == nkEmpty:
n[pragmasPos] = newNodeI(nkPragma, n.info)
for p in pragmas:
let prag = whichPragma(p)
if prag in validPragmas:
let copy = copyTree(p)
overwriteLineInfo copy, n.info
n[pragmasPos].add copy
proc implicitPragmas*(c: PContext, sym: PSym, info: TLineInfo,
validPragmas: TSpecialWords) =
if sym != nil and sym.kind != skModule:
@@ -1356,7 +1367,8 @@ proc implicitPragmas*(c: PContext, sym: PSym, info: TLineInfo,
internalError(c.config, info, "implicitPragmas")
inc i
popInfoContext(c.config)
if sym.kind in routineKinds and sym.ast != nil: mergePragmas(sym.ast, o)
if sym.kind in routineKinds and sym.ast != nil:
mergeValidPragmas(sym.ast, o, validPragmas)
if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
localError(c.config, info, ".dynlib requires .exportc")

View File

@@ -442,6 +442,11 @@ proc atom(g: TSrcGen; n: PNode): string =
result = $n.floatVal & "\'f64"
else:
result = litAux(g, n, (cast[ptr int64](addr(n.floatVal)))[], 8) & "\'f64"
of nkFloat128Lit:
if n.flags * {nfBase2, nfBase8, nfBase16} == {}:
result = $n.floatVal & "\'f128"
else:
result = litAux(g, n, (cast[ptr int64](addr(n.floatVal)))[], 8) & "\'f128"
of nkNilLit: result = "nil"
of nkType:
if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s

View File

@@ -246,10 +246,18 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
candidates.add(getProcHeader(c.config, err.sym, prefer))
candidates.addDeclaredLocMaybe(c.config, err.sym)
candidates.add("\n")
let nArg = if err.firstMismatch.arg < n.len: n[err.firstMismatch.arg] else: nil
const genericParamMismatches = {kGenericParamTypeMismatch, kExtraGenericParam, kMissingGenericParam}
let isGenericMismatch = err.firstMismatch.kind in genericParamMismatches
var argList = n
if isGenericMismatch and n[0].kind == nkBracketExpr:
argList = n[0]
let nArg =
if err.firstMismatch.arg < argList.len:
argList[err.firstMismatch.arg]
else:
nil
let nameParam = if err.firstMismatch.formal != nil: err.firstMismatch.formal.name.s else: ""
if n.len > 1:
const genericParamMismatches = {kGenericParamTypeMismatch, kExtraGenericParam, kMissingGenericParam}
if verboseTypeMismatch notin c.config.legacyFeatures:
case err.firstMismatch.kind
of kUnknownNamedParam:
@@ -309,7 +317,7 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
var wanted = err.firstMismatch.formal.typ
if wanted.kind == tyGenericParam and wanted.genericParamHasConstraints:
wanted = wanted.genericConstraint
let got = arg.typ
let got = arg.typ.skipTypes({tyTypeDesc})
doAssert err.firstMismatch.formal != nil
doAssert wanted != nil
doAssert got != nil
@@ -350,17 +358,9 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
of kMissingGenericParam:
candidates.add("\n missing generic parameter: " & nameParam)
of kTypeMismatch, kGenericParamTypeMismatch, kVarNeeded:
var arg: PNode = nArg
let genericMismatch = err.firstMismatch.kind == kGenericParamTypeMismatch
if genericMismatch:
let pos = err.firstMismatch.arg
doAssert n[0].kind == nkBracketExpr and pos < n[0].len
arg = n[0][pos]
else:
arg = nArg
doAssert arg != nil
doAssert nArg != nil
var wanted = err.firstMismatch.formal.typ
if genericMismatch and wanted.kind == tyGenericParam and
if isGenericMismatch and wanted.kind == tyGenericParam and
wanted.genericParamHasConstraints:
wanted = wanted.genericConstraint
doAssert err.firstMismatch.formal != nil
@@ -368,16 +368,17 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
candidates.addTypeDeclVerboseMaybe(c.config, wanted)
candidates.add "\n but expression '"
if err.firstMismatch.kind == kVarNeeded:
candidates.add renderNotLValue(arg)
candidates.add renderNotLValue(nArg)
candidates.add "' is immutable, not 'var'"
else:
candidates.add renderTree(arg)
candidates.add renderTree(nArg)
candidates.add "' is of type: "
let got = arg.typ
var got = nArg.typ
if isGenericMismatch: got = got.skipTypes({tyTypeDesc})
candidates.addTypeDeclVerboseMaybe(c.config, got)
if arg.kind in nkSymChoices:
if nArg.kind in nkSymChoices:
candidates.add "\n"
candidates.add ambiguousIdentifierMsg(arg, indent = 2)
candidates.add ambiguousIdentifierMsg(nArg, indent = 2)
doAssert wanted != nil
if got != nil:
if got.kind == tyProc and wanted.kind == tyProc:

View File

@@ -75,6 +75,7 @@ type
# overload resolution.
efTypeAllowed # typeAllowed will be called after
efWantNoDefaults
efIgnoreDefaults # var statements without initialization
efAllowSymChoice # symchoice node should not be resolved
TExprFlags* = set[TExprFlag]

View File

@@ -187,6 +187,7 @@ proc semOpenSym(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType,
break
o = o.owner
# nothing found
n.flags.excl nfDisabledOpenSym
if not warnDisabled and isSym:
result = semExpr(c, n, flags, expectedType)
else:
@@ -197,7 +198,9 @@ proc semOpenSym(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType,
proc semSymChoice(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType = nil): PNode =
if n.kind == nkOpenSymChoice:
result = semOpenSym(c, n, flags, expectedType, warnDisabled = nfDisabledOpenSym in n.flags)
result = semOpenSym(c, n, flags, expectedType,
warnDisabled = nfDisabledOpenSym in n.flags and
genericsOpenSym notin c.features)
if result != nil:
return
result = n
@@ -887,6 +890,9 @@ proc analyseIfAddressTaken(c: PContext, n: PNode, isOutParam: bool): PNode =
proc analyseIfAddressTakenInCall(c: PContext, n: PNode, isConverter = false) =
checkMinSonsLen(n, 1, c.config)
if n[0].typ == nil:
# n[0] might be erroring node in nimsuggest
return
const
FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap,
@@ -3293,8 +3299,12 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
of nkSym:
let s = n.sym
if nfDisabledOpenSym in n.flags:
let res = semOpenSym(c, n, flags, expectedType, warnDisabled = true)
assert res == nil
let override = genericsOpenSym in c.features
let res = semOpenSym(c, n, flags, expectedType,
warnDisabled = not override)
if res != nil:
assert override
return res
# because of the changed symbol binding, this does not mean that we
# don't have to check the symbol for semantics here again!
result = semSym(c, n, s, flags)
@@ -3307,7 +3317,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}, expectedType: PType
of nkNilLit:
if result.typ == nil:
result.typ = getNilType(c)
if expectedType != nil:
if expectedType != nil and expectedType.kind notin {tyUntyped, tyTyped}:
var m = newCandidate(c, result.typ)
if typeRel(m, expectedType, result.typ) >= isSubtype:
result.typ = expectedType

View File

@@ -74,7 +74,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
else:
result = symChoice(c, n, s, scOpen)
if canOpenSym(s):
if {openSym, genericsOpenSym} * c.features != {}:
if openSym in c.features:
if result.kind == nkSym:
result = newOpenSym(result)
else:
@@ -112,7 +112,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
# we are in a generic context and `prepareNode` will be called
result = newSymNodeTypeDesc(s, c.idgen, n.info)
if canOpenSym(result.sym):
if {openSym, genericsOpenSym} * c.features != {}:
if openSym in c.features:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
@@ -122,7 +122,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
else:
result = newSymNodeTypeDesc(s, c.idgen, n.info)
if canOpenSym(result.sym):
if {openSym, genericsOpenSym} * c.features != {}:
if openSym in c.features:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
@@ -141,7 +141,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
return
result = newSymNodeTypeDesc(s, c.idgen, n.info)
if canOpenSym(result.sym):
if {openSym, genericsOpenSym} * c.features != {}:
if openSym in c.features:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
@@ -153,7 +153,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
# we are in a generic context and `prepareNode` will be called
result = newSymNodeTypeDesc(s, c.idgen, n.info)
if canOpenSym(result.sym):
if {openSym, genericsOpenSym} * c.features != {}:
if openSym in c.features:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
@@ -164,7 +164,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
else:
result = newSymNode(s, n.info)
if canOpenSym(result.sym):
if {openSym, genericsOpenSym} * c.features != {}:
if openSym in c.features:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym

View File

@@ -254,6 +254,8 @@ proc instantiateProcType(c: PContext, pt: TypeMapping,
let needsStaticSkipping = resulti.kind == tyFromExpr
let needsTypeDescSkipping = resulti.kind == tyTypeDesc and tfUnresolved in resulti.flags
if resulti.kind == tyFromExpr:
resulti.flags.incl tfNonConstExpr
result[i] = replaceTypeVarsT(cl, resulti)
if needsStaticSkipping:
result[i] = result[i].skipTypes({tyStatic})

View File

@@ -50,8 +50,8 @@ proc semTypeOf(c: PContext; n: PNode): PNode =
m = mode.intVal
result = newNodeI(nkTypeOfExpr, n.info)
inc c.inTypeofContext
defer: dec c.inTypeofContext # compiles can raise an exception
let typExpr = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
dec c.inTypeofContext
result.add typExpr
if typExpr.typ.kind == tyFromExpr:
typExpr.typ.flags.incl tfNonConstExpr

View File

@@ -387,10 +387,13 @@ proc semConstructFields(c: PContext, n: PNode, constrCtx: var ObjConstrContext,
if e != nil:
result.status = initFull
elif field.ast != nil:
result.status = initUnknown
result.defaults.add newTree(nkExprColonExpr, n, field.ast)
if efIgnoreDefaults notin flags:
result.status = initUnknown
result.defaults.add newTree(nkExprColonExpr, n, field.ast)
else:
result.status = initNone
else:
if efWantNoDefaults notin flags: # cannot compute defaults at the typeRightPass
if {efWantNoDefaults, efIgnoreDefaults} * flags == {}: # cannot compute defaults at the typeRightPass
let defaultExpr = defaultNodeField(c, n, constrCtx.checkDefault)
if defaultExpr != nil:
result.status = initUnknown
@@ -443,7 +446,7 @@ proc defaultConstructionError(c: PContext, t: PType, info: TLineInfo) =
assert objType != nil
if objType.kind == tyObject:
var constrCtx = initConstrContext(objType, newNodeI(nkObjConstr, info))
let initResult = semConstructTypeAux(c, constrCtx, {efWantNoDefaults})
let initResult = semConstructTypeAux(c, constrCtx, {efIgnoreDefaults})
if constrCtx.missingFields.len > 0:
localError(c.config, info,
"The $1 type doesn't have a default value. The following fields must be initialized: $2." % [typeToString(t), listSymbolNames(constrCtx.missingFields)])

View File

@@ -1210,7 +1210,7 @@ proc track(tracked: PEffects, n: PNode) =
if n.sym.typ != nil and tfHasAsgn in n.sym.typ.flags:
tracked.owner.flags.incl sfInjectDestructors
# bug #15038: ensure consistency
if not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ): n.typ = n.sym.typ
if n.typ == nil or (not hasDestructor(n.typ) and sameType(n.typ, n.sym.typ)): n.typ = n.sym.typ
of nkHiddenAddr, nkAddr:
if n[0].kind == nkSym and isLocalSym(tracked, n[0].sym) and
n.typ.kind notin {tyVar, tyLent}:

View File

@@ -233,7 +233,7 @@ proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bo
of OverloadableSyms:
result = symChoice(c.c, n, s, scOpen, isField)
if not isField and result.kind in {nkSym, nkOpenSymChoice}:
if {openSym, templateOpenSym} * c.c.features != {}:
if openSym in c.c.features:
if result.kind == nkSym:
result = newOpenSym(result)
else:
@@ -246,7 +246,7 @@ proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bo
else:
result = newSymNodeTypeDesc(s, c.c.idgen, n.info)
if not isField and s.owner != c.owner:
if {openSym, templateOpenSym} * c.c.features != {}:
if openSym in c.c.features:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
@@ -264,7 +264,7 @@ proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bo
if not isField and not (s.owner == c.owner and
s.typ != nil and s.typ.kind == tyGenericParam) and
result.kind in {nkSym, nkOpenSymChoice}:
if {openSym, templateOpenSym} * c.c.features != {}:
if openSym in c.c.features:
if result.kind == nkSym:
result = newOpenSym(result)
else:
@@ -277,7 +277,7 @@ proc semTemplSymbol(c: var TemplCtx, n: PNode, s: PSym; isField, isAmbiguous: bo
else:
result = newSymNode(s, n.info)
if not isField:
if {openSym, templateOpenSym} * c.c.features != {}:
if openSym in c.c.features:
result = newOpenSym(result)
else:
result.flags.incl nfDisabledOpenSym
@@ -693,6 +693,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
pushOwner(c, s)
openScope(c)
n[namePos] = newSymNode(s)
s.ast = n # for implicitPragmas to use
pragmaCallable(c, s, n, templatePragmas)
implicitPragmas(c, s, n.info, templatePragmas)
@@ -763,11 +764,6 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
closeScope(c)
popOwner(c)
# set the symbol AST after pragmas, at least. This stops pragma that have
# been pushed (implicit) to be explicitly added to the template definition
# and misapplied to the body. see #18113
s.ast = n
if sfCustomPragma in s.flags:
if n[bodyPos].kind != nkEmpty:
localError(c.config, n[bodyPos].info, errImplOfXNotAllowed % s.name.s)

View File

@@ -586,9 +586,14 @@ proc semBranchRange(c: PContext, n, a, b: PNode, covered: var Int128): PNode =
let bc = semConstExpr(c, b)
if ac.kind in {nkStrLit..nkTripleStrLit} or bc.kind in {nkStrLit..nkTripleStrLit}:
localError(c.config, b.info, "range of string is invalid")
let at = fitNode(c, n[0].typ, ac, ac.info).skipConvTakeType
let bt = fitNode(c, n[0].typ, bc, bc.info).skipConvTakeType
var at = fitNode(c, n[0].typ, ac, ac.info).skipConvTakeType
var bt = fitNode(c, n[0].typ, bc, bc.info).skipConvTakeType
# the calls to fitNode may introduce calls to converters
# mirrored with semCaseBranch for single elements
if at.kind in {nkHiddenCallConv, nkHiddenStdConv, nkHiddenSubConv}:
at = semConstExpr(c, at)
if bt.kind in {nkHiddenCallConv, nkHiddenStdConv, nkHiddenSubConv}:
bt = semConstExpr(c, bt)
result = newNodeI(nkRange, a.info)
result.add(at)
result.add(bt)
@@ -619,6 +624,8 @@ proc semCaseBranch(c: PContext, n, branch: PNode, branchIndex: int,
var b = branch[i]
if b.kind == nkRange:
branch[i] = b
# same check as in semBranchRange for exhaustiveness
covered = covered + getOrdValue(b[1]) + 1 - getOrdValue(b[0])
elif isRange(b):
branch[i] = semCaseBranchRange(c, n, b, covered)
else:
@@ -634,8 +641,8 @@ proc semCaseBranch(c: PContext, n, branch: PNode, branchIndex: int,
checkMinSonsLen(n, 1, c.config)
var tmp = fitNode(c, n[0].typ, r, r.info)
# the call to fitNode may introduce a call to a converter
if tmp.kind == nkHiddenCallConv or
(tmp.kind == nkHiddenStdConv and n[0].typ.kind == tyCstring):
# mirrored with semBranchRange
if tmp.kind in {nkHiddenCallConv, nkHiddenStdConv, nkHiddenSubConv}:
tmp = semConstExpr(c, tmp)
branch[i] = skipConv(tmp)
inc(covered)
@@ -1864,8 +1871,8 @@ proc semStaticType(c: PContext, childNode: PNode, prev: PType): PType =
proc semTypeOf(c: PContext; n: PNode; prev: PType): PType =
openScope(c)
inc c.inTypeofContext
defer: dec c.inTypeofContext # compiles can raise an exception
let t = semExprWithType(c, n, {efInTypeof})
dec c.inTypeofContext
closeScope(c)
fixupTypeOf(c, prev, t)
result = t.typ
@@ -1882,8 +1889,8 @@ proc semTypeOf2(c: PContext; n: PNode; prev: PType): PType =
else:
m = mode.intVal
inc c.inTypeofContext
defer: dec c.inTypeofContext # compiles can raise an exception
let t = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
dec c.inTypeofContext
closeScope(c)
fixupTypeOf(c, prev, t)
result = t.typ
@@ -2160,7 +2167,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
if s.kind != skError: localError(c.config, n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
elif s.kind == skParam and s.typ.kind == tyTypeDesc:
internalAssert c.config, s.typ.base.kind != tyNone and prev == nil
internalAssert c.config, s.typ.base.kind != tyNone
result = s.typ.base
elif prev == nil:
result = s.typ
@@ -2184,7 +2191,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
if s.kind == skType:
s.typ
else:
internalAssert c.config, s.typ.base.kind != tyNone and prev == nil
internalAssert c.config, s.typ.base.kind != tyNone
s.typ.base
let alias = maybeAliasType(c, t, prev)
if alias != nil:

View File

@@ -1125,9 +1125,21 @@ proc inferStaticsInRange(c: var TCandidate,
doInferStatic(lowerBound, getInt(upperBound) + 1 - lengthOrd(c.c.config, concrete))
template subtypeCheck() =
if result <= isSubrange and f.last.skipTypes(abstractInst).kind in {
tyRef, tyPtr, tyVar, tyLent, tyOwned}:
case result
of isIntConv:
result = isNone
of isSubrange:
discard # XXX should be isNone with preview define, warnings
of isConvertible:
if f.last.skipTypes(abstractInst).kind != tyOpenArray:
# exclude var openarray which compiler supports
result = isNone
of isSubtype:
if f.last.skipTypes(abstractInst).kind in {
tyRef, tyPtr, tyVar, tyLent, tyOwned}:
# compiler can't handle subtype conversions with pointer indirection
result = isNone
else: discard
proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
# this proc is always called for a pair of matching types
@@ -1279,6 +1291,11 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
if prev == nil: body
else: return typeRel(c, prev, a, flags)
if c.c.inGenericContext > 0 and not c.isNoCall and
(tfUnresolved in a.flags or a.kind in tyTypeClasses):
# cheap check for unresolved arg, not nested
return isNone
case a.kind
of tyOr:
# XXX: deal with the current dual meaning of tyGenericParam
@@ -1523,7 +1540,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
reduceToBase(a)
if effectiveArgType.kind == tyObject:
if sameObjectTypes(f, effectiveArgType):
c.inheritancePenalty = 0
c.inheritancePenalty = if tfFinal in f.flags: -1 else: 0
result = isEqual
# elif tfHasMeta in f.flags: result = recordRel(c, f, a)
elif trIsOutParam notin flags:
@@ -1995,7 +2012,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
var r = tryResolvingStaticExpr(c, f.n)
if r == nil: r = f.n
if not exprStructuralEquivalent(r, aOrig.n) and
not (aOrig.n.kind == nkIntLit and
not (aOrig.n != nil and aOrig.n.kind == nkIntLit and
inferStaticParam(c, r, aOrig.n.intVal)):
result = isNone
elif f.base.kind == tyGenericParam:
@@ -2096,15 +2113,15 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
# not resolved
result = isNone
of tyTypeDesc:
result = typeRel(c, a, reevaluated.base, flags)
result = typeRel(c, reevaluated.base, a, flags)
of tyStatic:
result = typeRel(c, a, reevaluated.base, flags)
result = typeRel(c, reevaluated.base, a, flags)
if result != isNone and reevaluated.n != nil:
if not exprStructuralEquivalent(aOrig.n, reevaluated.n):
result = isNone
else:
# bug #14136: other types are just like 'tyStatic' here:
result = typeRel(c, a, reevaluated, flags)
result = typeRel(c, reevaluated, a, flags)
if result != isNone and reevaluated.n != nil:
if not exprStructuralEquivalent(aOrig.n, reevaluated.n):
result = isNone

View File

@@ -511,7 +511,12 @@ proc transformAddrDeref(c: PTransf, n: PNode, kinds: TNodeKinds): PNode =
if n[0].kind in kinds and
not (n[0][0].kind == nkSym and n[0][0].sym.kind == skForVar and
n[0][0].typ.skipTypes(abstractVar).kind == tyTuple
): # elimination is harmful to `for tuple unpack` because of newTupleAccess
) and not (n[0][0].kind == nkSym and n[0][0].sym.kind == skParam and
n.typ.kind == tyVar and
n.typ.skipTypes(abstractVar).kind == tyOpenArray and
n[0][0].typ.skipTypes(abstractVar).kind == tyString)
: # elimination is harmful to `for tuple unpack` because of newTupleAccess
# it is also harmful to openArrayLoc (var openArray) for strings
# addr ( deref ( x )) --> x
result = n[0][0]
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:

View File

@@ -1250,18 +1250,18 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
b = skipTypes(b.last, aliasSkipSet)
assert(a != nil)
assert(b != nil)
if a.kind != b.kind:
case c.cmp
of dcEq: return false
of dcEqIgnoreDistinct:
let distinctSkipSet = maybeSkipRange({tyDistinct, tyGenericInst})
a = a.skipTypes(distinctSkipSet)
b = b.skipTypes(distinctSkipSet)
if a.kind != b.kind: return false
of dcEqOrDistinctOf:
let distinctSkipSet = maybeSkipRange({tyDistinct, tyGenericInst})
a = a.skipTypes(distinctSkipSet)
if a.kind != b.kind: return false
case c.cmp
of dcEq:
if a.kind != b.kind: return false
of dcEqIgnoreDistinct:
let distinctSkipSet = maybeSkipRange({tyDistinct, tyGenericInst})
a = a.skipTypes(distinctSkipSet)
b = b.skipTypes(distinctSkipSet)
if a.kind != b.kind: return false
of dcEqOrDistinctOf:
let distinctSkipSet = maybeSkipRange({tyDistinct, tyGenericInst})
a = a.skipTypes(distinctSkipSet)
if a.kind != b.kind: return false
#[
The following code should not run in the case either side is an generic alias,
@@ -1269,7 +1269,8 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
objects ie `type A[T] = SomeObject`
]#
# this is required by tunique_type but makes no sense really:
if x.kind == tyGenericInst and IgnoreTupleFields notin c.flags and tyDistinct != y.kind:
if c.cmp == dcEq and x.kind == tyGenericInst and
IgnoreTupleFields notin c.flags and tyDistinct != y.kind:
let
lhs = x.skipGenericAlias
rhs = y.skipGenericAlias

View File

@@ -609,7 +609,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcYldVal: assert false
of opcAsgnInt:
decodeB(rkInt)
regs[ra].intVal = regs[rb].intVal
if regs[rb].kind == rkInt:
regs[ra].intVal = regs[rb].intVal
else:
stackTrace(c, tos, pc, "opcAsgnInt: got " & $regs[rb].kind)
of opcAsgnFloat:
decodeB(rkFloat)
regs[ra].floatVal = regs[rb].floatVal
@@ -676,16 +679,19 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
else:
assert regs[rb].kind == rkNode
let nb = regs[rb].node
case nb.kind
of nkCharLit..nkUInt64Lit:
ensureKind(rkInt)
regs[ra].intVal = nb.intVal
of nkFloatLit..nkFloat64Lit:
ensureKind(rkFloat)
regs[ra].floatVal = nb.floatVal
if nb == nil:
stackTrace(c, tos, pc, errNilAccess)
else:
ensureKind(rkNode)
regs[ra].node = nb
case nb.kind
of nkCharLit..nkUInt64Lit:
ensureKind(rkInt)
regs[ra].intVal = nb.intVal
of nkFloatLit..nkFloat64Lit:
ensureKind(rkFloat)
regs[ra].floatVal = nb.floatVal
else:
ensureKind(rkNode)
regs[ra].node = nb
of opcSlice:
# A bodge, but this takes in `toOpenArray(rb, rc, rc)` and emits
# nkTupleConstr(x, y, z) into the `regs[ra]`. These can later be used for calculating the slice we have taken.
@@ -850,25 +856,30 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcLdObj:
# a = b.c
decodeBC(rkNode)
let src = if regs[rb].kind == rkNode: regs[rb].node else: regs[rb].nodeAddr[]
case src.kind
of nkEmpty..nkNilLit:
# for nkPtrLit, this could be supported in the future, use something like:
# derefPtrToReg(src.intVal + offsetof(src.typ, rc), typ_field, regs[ra], isAssign = false)
# where we compute the offset in bytes for field rc
stackTrace(c, tos, pc, errNilAccess & " " & $("kind", src.kind, "typ", typeToString(src.typ), "rc", rc))
of nkObjConstr:
let n = src[rc + 1].skipColon
regs[ra].node = n
of nkTupleConstr:
let n = if src.typ != nil and tfTriggersCompileTime in src.typ.flags:
src[rc]
else:
src[rc].skipColon
regs[ra].node = n
if rb >= regs.len or regs[rb].kind == rkNone or
(regs[rb].kind == rkNode and regs[rb].node == nil) or
(regs[rb].kind == rkNodeAddr and regs[rb].nodeAddr[] == nil):
stackTrace(c, tos, pc, errNilAccess)
else:
let n = src[rc]
regs[ra].node = n
let src = if regs[rb].kind == rkNode: regs[rb].node else: regs[rb].nodeAddr[]
case src.kind
of nkEmpty..nkNilLit:
# for nkPtrLit, this could be supported in the future, use something like:
# derefPtrToReg(src.intVal + offsetof(src.typ, rc), typ_field, regs[ra], isAssign = false)
# where we compute the offset in bytes for field rc
stackTrace(c, tos, pc, errNilAccess & " " & $("kind", src.kind, "typ", typeToString(src.typ), "rc", rc))
of nkObjConstr:
let n = src[rc + 1].skipColon
regs[ra].node = n
of nkTupleConstr:
let n = if src.typ != nil and tfTriggersCompileTime in src.typ.flags:
src[rc]
else:
src[rc].skipColon
regs[ra].node = n
else:
let n = src[rc]
regs[ra].node = n
of opcLdObjAddr:
# a = addr(b.c)
decodeBC(rkNodeAddr)

View File

@@ -237,7 +237,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
of tySequence: result = mapTypeToBracket("seq", mSeq, t, info)
of tyProc:
if inst:
result = newNodeX(nkProcTy)
result = newNodeX(if tfIterator in t.flags: nkIteratorTy else: nkProcTy)
var fp = newNodeX(nkFormalParams)
if t.returnType == nil:
fp.add newNodeI(nkEmpty, info)
@@ -246,8 +246,15 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
for i in FirstParamAt..<t.kidsLen:
fp.add newIdentDefs(t.n[i], t[i])
result.add fp
result.add if t.n[0].len > 0: t.n[0][pragmasEffects].copyTree
else: newNodeI(nkEmpty, info)
var prag =
if t.n[0].len > 0:
t.n[0][pragmasEffects].copyTree
else:
newNodeI(nkEmpty, info)
if t.callConv != ccClosure or tfExplicitCallConv in t.flags:
if prag.kind == nkEmpty: prag = newNodeI(nkPragma, info)
prag.add newIdentNode(getIdent(cache, $t.callConv), info)
result.add prag
else:
result = mapTypeToBracket("proc", mNone, t, info)
of tyOpenArray: result = mapTypeToBracket("openArray", mOpenArray, t, info)

View File

@@ -53,6 +53,7 @@ type
gfNode # Affects how variables are loaded - always loads as rkNode
gfNodeAddr # Affects how variables are loaded - always loads as rkNodeAddr
gfIsParam # do not deepcopy parameters, they are immutable
gfIsSinkParam # deepcopy sink parameters
TGenFlags = set[TGenFlag]
proc debugInfo(c: PCtx; info: TLineInfo): string =
@@ -245,7 +246,7 @@ proc getTemp(cc: PCtx; tt: PType): TRegister =
proc freeTemp(c: PCtx; r: TRegister) =
let c = c.prc
if c.regInfo[r].kind in {slotSomeTemp..slotTempComplex}:
if r < c.regInfo.len and c.regInfo[r].kind in {slotSomeTemp..slotTempComplex}:
# this seems to cause https://github.com/nim-lang/Nim/issues/10647
c.regInfo[r].inUse = false
@@ -357,12 +358,13 @@ proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
#if c.prc.regInfo[i].kind in {slotFixedVar, slotFixedLet}:
if i != dest:
when not defined(release):
if c.prc.regInfo[i].inUse and c.prc.regInfo[i].kind in {slotTempUnknown,
slotTempInt,
slotTempFloat,
slotTempStr,
slotTempComplex}:
raiseAssert "leaking temporary " & $i & " " & $c.prc.regInfo[i].kind
if c.config.cmd != cmdCheck:
if c.prc.regInfo[i].inUse and c.prc.regInfo[i].kind in {slotTempUnknown,
slotTempInt,
slotTempFloat,
slotTempStr,
slotTempComplex}:
raiseAssert "leaking temporary " & $i & " " & $c.prc.regInfo[i].kind
c.prc.regInfo[i] = (inUse: false, kind: slotEmpty)
c.clearDest(n, dest)
@@ -619,10 +621,17 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) =
let fntyp = skipTypes(n[0].typ, abstractInst)
for i in 0..<n.len:
var r: TRegister = x+i
c.gen(n[i], r, {gfIsParam})
if i >= fntyp.signatureLen:
c.gen(n[i], r, {gfIsParam})
internalAssert c.config, tfVarargs in fntyp.flags
c.gABx(n, opcSetType, r, c.genType(n[i].typ))
else:
if fntyp[i] != nil and fntyp[i].kind == tySink and
fntyp[i].skipTypes({tySink}).kind in {tyObject, tyString, tySequence}:
c.gen(n[i], r, {gfIsSinkParam})
else:
c.gen(n[i], r, {gfIsParam})
if dest < 0:
c.gABC(n, opcIndCall, 0, x, n.len)
else:
@@ -696,6 +705,9 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
let dest = c.genx(le, {gfNodeAddr})
c.gABC(le, opcWrDeref, dest, 0, value)
c.freeTemp(dest)
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
if sameBackendType(le.typ, le[1].typ):
genAsgnPatch(c, le[1], value)
else:
discard
@@ -868,7 +880,7 @@ proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
genBinaryABC(c, n, dest, opc)
c.genNarrow(n, dest)
proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
proc genConv(c: PCtx; n, arg: PNode; dest: var TDest, flags: TGenFlags = {}; opc=opcConv) =
let t2 = n.typ.skipTypes({tyDistinct})
let targ2 = arg.typ.skipTypes({tyDistinct})
@@ -882,7 +894,7 @@ proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
result = false
if implicitConv():
gen(c, arg, dest)
gen(c, arg, dest, flags)
return
let tmp = c.genx(arg)
@@ -1050,7 +1062,7 @@ proc whichAsgnOpc(n: PNode; requiresCopy = true): TOpcode =
else:
(if requiresCopy: opcAsgnComplex else: opcFastAsgnComplex)
proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
proc genMagic(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}, m: TMagic) =
case m
of mAnd: c.genAndOr(n, opcFJmp, dest)
of mOr: c.genAndOr(n, opcTJmp, dest)
@@ -1189,7 +1201,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
of mCharToStr, mBoolToStr, mCStrToStr, mStrToStr, mEnumToStr:
genConv(c, n, n[1], dest)
genConv(c, n, n[1], dest, flags)
of mEqStr: genBinaryABC(c, n, dest, opcEqStr)
of mEqCString: genBinaryABC(c, n, dest, opcEqCString)
of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
@@ -1529,7 +1541,11 @@ proc setSlot(c: PCtx; v: PSym) =
if v.position == 0:
v.position = getFreeRegister(c, if v.kind == skLet: slotFixedLet else: slotFixedVar, start = 1)
proc cannotEval(c: PCtx; n: PNode) {.noinline.} =
template cannotEval(c: PCtx; n: PNode) =
if c.config.cmd == cmdCheck:
localError(c.config, n.info, "cannot evaluate at compile time: " &
n.renderTree)
return
globalError(c.config, n.info, "cannot evaluate at compile time: " &
n.renderTree)
@@ -1652,6 +1668,9 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
c.freeTemp(cc)
else:
gen(c, ri, dest)
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
if sameBackendType(le.typ, le[1].typ):
genAsgn(c, le[1], ri, requiresCopy)
else:
let dest = c.genx(le, {gfNodeAddr})
genAsgn(c, dest, ri, requiresCopy)
@@ -1729,6 +1748,8 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
c.gABx(n, opcLdGlobalAddr, dest, s.position)
elif isImportcVar:
c.gABx(n, opcLdGlobalDerefFFI, dest, s.position)
elif gfIsSinkParam in flags:
genAsgn(c, dest, n, requiresCopy = true)
elif fitsRegister(s.typ) and gfNode notin flags:
var cc = c.getTemp(n.typ)
c.gABx(n, opcLdGlobal, cc, s.position)
@@ -1742,7 +1763,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
s.kind in {skParam, skResult}):
if dest < 0:
dest = s.position + ord(s.kind == skParam)
internalAssert(c.config, c.prc.regInfo[dest].kind < slotSomeTemp)
internalAssert(c.config, c.prc.regInfo.len > dest and c.prc.regInfo[dest].kind < slotSomeTemp)
else:
# we need to generate an assignment:
let requiresCopy = c.prc.regInfo[dest].kind >= slotSomeTemp and
@@ -2164,7 +2185,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
if n[0].kind == nkSym:
let s = n[0].sym
if s.magic != mNone:
genMagic(c, n, dest, s.magic)
genMagic(c, n, dest, flags, s.magic)
elif s.kind == skMethod:
localError(c.config, n.info, "cannot call method " & s.name.s &
" at compile time")
@@ -2221,11 +2242,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
unused(c, n, dest)
gen(c, n[0])
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
genConv(c, n, n[1], dest)
genConv(c, n, n[1], dest, flags)
of nkObjDownConv:
genConv(c, n, n[0], dest)
genConv(c, n, n[0], dest, flags)
of nkObjUpConv:
genConv(c, n, n[0], dest)
genConv(c, n, n[0], dest, flags)
of nkVarSection, nkLetSection:
unused(c, n, dest)
genVarSection(c, n)
@@ -2235,7 +2256,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
genLit(c, newSymNode(n[namePos].sym), dest)
of nkChckRangeF, nkChckRange64, nkChckRange:
if skipTypes(n.typ, abstractVar).kind in {tyUInt..tyUInt64}:
genConv(c, n, n[0], dest)
genConv(c, n, n[0], dest, flags)
else:
let
tmp0 = c.genx(n[0])
@@ -2261,7 +2282,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
of nkPar, nkClosure, nkTupleConstr: genTupleConstr(c, n, dest)
of nkCast:
if allowCast in c.features:
genConv(c, n, n[1], dest, opcCast)
genConv(c, n, n[1], dest, flags, opcCast)
else:
genCastIntFloat(c, n, dest)
of nkTypeOfExpr:

View File

@@ -2533,8 +2533,7 @@ renaming the captured symbols should be used instead so that the code is not
affected by context changes.
Since this change may affect runtime behavior, the experimental switch
`openSym`, or `genericsOpenSym` and `templateOpenSym` for only the respective
routines, needs to be enabled; and a warning is given in the case where an
`openSym` needs to be enabled; and a warning is given in the case where an
injected symbol would replace a captured symbol not bound by `bind` and
the experimental switch isn't enabled.
@@ -2555,7 +2554,7 @@ template oldTempl(): string =
value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
echo oldTempl() # "captured"
{.experimental: "openSym".} # or {.experimental: "genericsOpenSym".} for just generic procs
{.experimental: "openSym".}
proc bar[T](): string =
foo(123):
@@ -2568,8 +2567,6 @@ proc baz[T](): string =
return value
assert baz[int]() == "captured"
# {.experimental: "templateOpenSym".} would be needed here if genericsOpenSym was used
template barTempl(): string =
block:
foo(123):
@@ -2590,6 +2587,34 @@ modified `nnkOpenSymChoice` node but macros that want to support the
experimental feature should still handle `nnkOpenSym`, as the node kind would
simply not be generated as opposed to being removed.
Another experimental switch `genericsOpenSym` exists that enables this behavior
at instantiation time, meaning templates etc can enable it specifically when
they are being called. However this does not generate `nnkOpenSym` nodes
(unless the other switch is enabled) and so doesn't reflect the regular
behavior of the switch.
```nim
const value = "captured"
template foo(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
{.push experimental: "genericsOpenSym".}
body
{.pop.}
proc bar[T](): string =
foo(123):
return value
echo bar[int]() # "injected"
template barTempl(): string =
block:
var res: string
foo(123):
res = value
res
assert barTempl() == "injected"
```
VTable for methods
==================

View File

@@ -61,43 +61,44 @@ Standard library modules
At least the following standard library modules are available:
* [macros](macros.html)
* [os](os.html)
* [strutils](strutils.html)
* [math](math.html)
* [distros](distros.html)
* [sugar](sugar.html)
* [algorithm](algorithm.html)
* [base64](base64.html)
* [bitops](bitops.html)
* [chains](chains.html)
* [colors](colors.html)
* [complex](complex.html)
* [distros](distros.html)
* [std/editdistance](editdistance.html)
* [htmlgen](htmlgen.html)
* [htmlparser](htmlparser.html)
* [httpcore](httpcore.html)
* [json](json.html)
* [lenientops](lenientops.html)
* [macros](macros.html)
* [math](math.html)
* [options](options.html)
* [os](os.html)
* [parsecfg](parsecfg.html)
* [parsecsv](parsecsv.html)
* [parsejson](parsejson.html)
* [parsesql](parsesql.html)
* [parseutils](parseutils.html)
* [punycode](punycode.html)
* [random](random.html)
* [ropes](ropes.html)
* [std/setutils](setutils.html)
* [stats](stats.html)
* [strformat](strformat.html)
* [strmisc](strmisc.html)
* [strscans](strscans.html)
* [unicode](unicode.html)
* [uri](uri.html)
* [std/editdistance](editdistance.html)
* [std/wordwrap](wordwrap.html)
* [parsecsv](parsecsv.html)
* [parsecfg](parsecfg.html)
* [parsesql](parsesql.html)
* [xmlparser](xmlparser.html)
* [htmlparser](htmlparser.html)
* [ropes](ropes.html)
* [json](json.html)
* [parsejson](parsejson.html)
* [strtabs](strtabs.html)
* [strutils](strutils.html)
* [sugar](sugar.html)
* [unicode](unicode.html)
* [unidecode](unidecode.html)
* [uri](uri.html)
* [std/wordwrap](wordwrap.html)
* [xmlparser](xmlparser.html)
In addition to the standard Nim syntax ([system](system.html) module),
NimScripts support the procs and templates defined in the

View File

@@ -1,12 +1,12 @@
#
#
# Maintenance program for Nim
# (c) Copyright 2017 Andreas Rumpf
# (c) Copyright 2024 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# See doc/koch.txt for documentation.
# See doc/koch.md for documentation.
#
const
@@ -52,7 +52,7 @@ const
+-----------------------------------------------------------------+
| Maintenance program for Nim |
| Version $1|
| (c) 2017 Andreas Rumpf |
| (c) 2024 Andreas Rumpf |
+-----------------------------------------------------------------+
Build time: $2, $3
@@ -77,6 +77,7 @@ Possible Commands:
doesn't require network connectivity
nimble builds the Nimble tool
atlas builds the Atlas tool
checksums installs the checksums dependency
fusion installs fusion via Nimble
Boot options:
@@ -344,8 +345,7 @@ proc boot(args: string, skipIntegrityCheck: bool) =
let smartNimcache = (if "release" in args or "danger" in args: "nimcache/r_" else: "nimcache/d_") &
hostOS & "_" & hostCPU
if not dirExists("dist/checksums"):
bundleChecksums(false)
bundleChecksums(false)
let usingLibFFI = "nimHasLibFFI" in args
if usingLibFFI and not dirExists("dist/libffi"):
@@ -508,8 +508,7 @@ proc temp(args: string) =
result[1].add " " & quoteShell(args[i])
inc i
if not dirExists("dist/checksums"):
bundleChecksums(false)
bundleChecksums(false)
let d = getAppDir()
let output = d / "compiler" / "nim".exe

View File

@@ -161,16 +161,6 @@ proc newAny(value: pointer, rawType: PNimType): Any {.inline.} =
result.value = value
result.rawType = rawType
when declared(system.VarSlot):
proc toAny*(x: VarSlot): Any {.inline.} =
## Constructs an `Any` object from a variable slot `x`.
## This captures `x`'s address, so `x` can be modified with its
## `Any` wrapper! The caller needs to ensure that the wrapper
## **does not** live longer than `x`!
## This is provided for easier reflection capabilities of a debugger.
result.value = x.address
result.rawType = x.typ
proc toAny*[T](x: var T): Any {.inline.} =
## Constructs an `Any` object from `x`. This captures `x`'s address, so
## `x` can be modified with its `Any` wrapper! The caller needs to ensure

View File

@@ -1526,7 +1526,7 @@ proc parseMarkdownCodeblockFields(p: var RstParser): PRstNode =
result = nil
else:
result = newRstNode(rnFieldList)
while currentTok(p).kind != tkIndent:
while currentTok(p).kind notin {tkIndent, tkEof}:
if currentTok(p).kind == tkWhite:
inc p.idx
else:

View File

@@ -10,6 +10,9 @@
## Types and operations for atomic operations and lockless algorithms.
##
## Unstable API.
##
## By default, C++ uses C11 atomic primitives. To use C++ `std::atomic`,
## `-d:nimUseCppAtomics` can be defined.
runnableExamples:
# Atomic
@@ -50,8 +53,7 @@ runnableExamples:
flag.clear(moRelaxed)
assert not flag.testAndSet
when defined(cpp) or defined(nimdoc):
when (defined(cpp) and defined(nimUseCppAtomics)) or defined(nimdoc):
# For the C++ backend, types and operations map directly to C++11 atomics.
{.push, header: "<atomic>".}
@@ -274,10 +276,17 @@ else:
cast[T](interlockedXor(addr(location.value), cast[nonAtomicType(T)](value)))
else:
{.push, header: "<stdatomic.h>".}
when defined(cpp):
{.push, header: "<atomic>".}
template maybeWrapStd(x: string): string =
"std::" & x
else:
{.push, header: "<stdatomic.h>".}
template maybeWrapStd(x: string): string =
x
type
MemoryOrder* {.importc: "memory_order".} = enum
MemoryOrder* {.importc: "memory_order".maybeWrapStd.} = enum
moRelaxed
moConsume
moAcquire
@@ -285,16 +294,25 @@ else:
moAcquireRelease
moSequentiallyConsistent
type
# Atomic*[T] {.importcpp: "_Atomic('0)".} = object
when defined(cpp):
type
# Atomic*[T] {.importcpp: "_Atomic('0)".} = object
AtomicInt8 {.importc: "_Atomic NI8".} = int8
AtomicInt16 {.importc: "_Atomic NI16".} = int16
AtomicInt32 {.importc: "_Atomic NI32".} = int32
AtomicInt64 {.importc: "_Atomic NI64".} = int64
AtomicInt8 {.importc: "std::atomic<NI8>".} = int8
AtomicInt16 {.importc: "std::atomic<NI16>".} = int16
AtomicInt32 {.importc: "std::atomic<NI32>".} = int32
AtomicInt64 {.importc: "std::atomic<NI64>".} = int64
else:
type
# Atomic*[T] {.importcpp: "_Atomic('0)".} = object
AtomicInt8 {.importc: "_Atomic NI8".} = int8
AtomicInt16 {.importc: "_Atomic NI16".} = int16
AtomicInt32 {.importc: "_Atomic NI32".} = int32
AtomicInt64 {.importc: "_Atomic NI64".} = int64
type
AtomicFlag* {.importc: "atomic_flag", size: 1.} = object
AtomicFlag* {.importc: "atomic_flag".maybeWrapStd, size: 1.} = object
Atomic*[T] = object
when T is Trivial:
@@ -308,27 +326,27 @@ else:
guard: AtomicFlag
#proc init*[T](location: var Atomic[T]; value: T): T {.importcpp: "atomic_init(@)".}
proc atomic_load_explicit[T, A](location: ptr A; order: MemoryOrder): T {.importc.}
proc atomic_store_explicit[T, A](location: ptr A; desired: T; order: MemoryOrder = moSequentiallyConsistent) {.importc.}
proc atomic_exchange_explicit[T, A](location: ptr A; desired: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
proc atomic_compare_exchange_strong_explicit[T, A](location: ptr A; expected: ptr T; desired: T; success, failure: MemoryOrder): bool {.importc.}
proc atomic_compare_exchange_weak_explicit[T, A](location: ptr A; expected: ptr T; desired: T; success, failure: MemoryOrder): bool {.importc.}
proc atomic_load_explicit[T, A](location: ptr A; order: MemoryOrder): T {.importc: "atomic_load_explicit".maybeWrapStd.}
proc atomic_store_explicit[T, A](location: ptr A; desired: T; order: MemoryOrder = moSequentiallyConsistent) {.importc: "atomic_store_explicit".maybeWrapStd.}
proc atomic_exchange_explicit[T, A](location: ptr A; desired: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_exchange_explicit".maybeWrapStd.}
proc atomic_compare_exchange_strong_explicit[T, A](location: ptr A; expected: ptr T; desired: T; success, failure: MemoryOrder): bool {.importc: "atomic_compare_exchange_strong_explicit".maybeWrapStd.}
proc atomic_compare_exchange_weak_explicit[T, A](location: ptr A; expected: ptr T; desired: T; success, failure: MemoryOrder): bool {.importc: "atomic_compare_exchange_weak_explicit".maybeWrapStd.}
# Numerical operations
proc atomic_fetch_add_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
proc atomic_fetch_sub_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
proc atomic_fetch_and_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
proc atomic_fetch_or_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
proc atomic_fetch_xor_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc.}
proc atomic_fetch_add_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_fetch_add_explicit".maybeWrapStd.}
proc atomic_fetch_sub_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_fetch_sub_explicit".maybeWrapStd.}
proc atomic_fetch_and_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_fetch_and_explicit".maybeWrapStd.}
proc atomic_fetch_or_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_fetch_or_explicit".maybeWrapStd.}
proc atomic_fetch_xor_explicit[T, A](location: ptr A; value: T; order: MemoryOrder = moSequentiallyConsistent): T {.importc: "atomic_fetch_xor_explicit".maybeWrapStd.}
# Flag operations
# var ATOMIC_FLAG_INIT {.importc, nodecl.}: AtomicFlag
# proc init*(location: var AtomicFlag) {.inline.} = location = ATOMIC_FLAG_INIT
proc testAndSet*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent): bool {.importc: "atomic_flag_test_and_set_explicit".}
proc clear*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent) {.importc: "atomic_flag_clear_explicit".}
proc testAndSet*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent): bool {.importc: "atomic_flag_test_and_set_explicit".maybeWrapStd.}
proc clear*(location: var AtomicFlag; order: MemoryOrder = moSequentiallyConsistent) {.importc: "atomic_flag_clear_explicit".maybeWrapStd.}
proc fence*(order: MemoryOrder) {.importc: "atomic_thread_fence".}
proc signalFence*(order: MemoryOrder) {.importc: "atomic_signal_fence".}
proc fence*(order: MemoryOrder) {.importc: "atomic_thread_fence".maybeWrapStd.}
proc signalFence*(order: MemoryOrder) {.importc: "atomic_signal_fence".maybeWrapStd.}
{.pop.}

View File

@@ -839,6 +839,7 @@ proc addHandler*(handler: Logger) =
## each of those threads.
##
## See also:
## * `removeHandler proc`_
## * `getHandlers proc<#getHandlers>`_
runnableExamples:
var logger = newConsoleLogger()
@@ -846,6 +847,16 @@ proc addHandler*(handler: Logger) =
doAssert logger in getHandlers()
handlers.add(handler)
proc removeHandler*(handler: Logger) =
## Removes a logger from the list of registered handlers.
##
## Note that for n times a logger is registered, n calls to this proc
## are required to remove that logger.
for i, hnd in handlers:
if hnd == handler:
handlers.delete(i)
return
proc getHandlers*(): seq[Logger] =
## Returns a list of all the registered handlers.
##

View File

@@ -97,6 +97,8 @@ type
length*: int
addrList*: seq[string]
const IPPROTO_NONE* = IPPROTO_IP ## Use this if your socket type requires a protocol value of zero (e.g. Unix sockets).
when useWinVersion:
let
osInvalidSocket* = winlean.INVALID_SOCKET

View File

@@ -97,7 +97,7 @@ import std/nativesockets
import std/[os, strutils, times, sets, options, monotimes]
import std/ssl_config
export nativesockets.Port, nativesockets.`$`, nativesockets.`==`
export Domain, SockType, Protocol
export Domain, SockType, Protocol, IPPROTO_NONE
const useWinVersion = defined(windows) or defined(nimdoc)
const useNimNetLite = defined(nimNetLite) or defined(freertos) or defined(zephyr) or

View File

@@ -446,13 +446,17 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1",
else:
discard existsOrCreateDir(p)
proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
proc copyDir*(source, dest: string, skipSpecial = false) {.rtl, extern: "nos$1",
tags: [ReadDirEffect, WriteIOEffect, ReadIOEffect], benign, noWeirdTarget.} =
## Copies a directory from `source` to `dest`.
##
## On non-Windows OSes, symlinks are copied as symlinks. On Windows, symlinks
## are skipped.
##
## If `skipSpecial` is true, then (besides all directories) only *regular*
## files (**without** special "file" objects like FIFOs, device files,
## etc) will be copied on Unix.
##
## If this fails, `OSError` is raised.
##
## On the Windows platform this proc will copy the attributes from
@@ -472,16 +476,17 @@ proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
## * `createDir proc`_
## * `moveDir proc`_
createDir(dest)
for kind, path in walkDir(source):
for kind, path in walkDir(source, skipSpecial = skipSpecial):
var noSource = splitPath(path).tail
if kind == pcDir:
copyDir(path, dest / noSource)
copyDir(path, dest / noSource, skipSpecial = skipSpecial)
else:
copyFile(path, dest / noSource, {cfSymlinkAsIs})
proc copyDirWithPermissions*(source, dest: string,
ignorePermissionErrors = true)
ignorePermissionErrors = true,
skipSpecial = false)
{.rtl, extern: "nos$1", tags: [ReadDirEffect, WriteIOEffect, ReadIOEffect],
benign, noWeirdTarget.} =
## Copies a directory from `source` to `dest` preserving file permissions.
@@ -489,6 +494,10 @@ proc copyDirWithPermissions*(source, dest: string,
## On non-Windows OSes, symlinks are copied as symlinks. On Windows, symlinks
## are skipped.
##
## If `skipSpecial` is true, then (besides all directories) only *regular*
## files (**without** special "file" objects like FIFOs, device files,
## etc) will be copied on Unix.
##
## If this fails, `OSError` is raised. This is a wrapper proc around
## `copyDir`_ and `copyFileWithPermissions`_ procs
## on non-Windows platforms.
@@ -518,10 +527,10 @@ proc copyDirWithPermissions*(source, dest: string,
except:
if not ignorePermissionErrors:
raise
for kind, path in walkDir(source):
for kind, path in walkDir(source, skipSpecial = skipSpecial):
var noSource = splitPath(path).tail
if kind == pcDir:
copyDirWithPermissions(path, dest / noSource, ignorePermissionErrors)
copyDirWithPermissions(path, dest / noSource, ignorePermissionErrors, skipSpecial = skipSpecial)
else:
copyFileWithPermissions(path, dest / noSource, ignorePermissionErrors, {cfSymlinkAsIs})

View File

@@ -240,7 +240,7 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}; bufferSize = 1
else:
# generic version of copyFile which works for any platform:
var d, s: File
if not open(s, source):raiseOSError(osLastError(), source)
if not open(s, source): raiseOSError(osLastError(), source)
if not open(d, dest, fmWrite):
close(s)
raiseOSError(osLastError(), dest)

View File

@@ -2085,7 +2085,8 @@ when notJSnotNims:
proc cmpMem(a, b: pointer, size: Natural): int =
nimCmpMem(a, b, size).int
when not defined(js):
when not defined(js) or defined(nimscript):
# nimscript can be defined if config file for js compilation
proc cmp(x, y: string): int =
when nimvm:
if x < y: result = -1
@@ -2365,7 +2366,8 @@ proc finished*[T: iterator {.closure.}](x: T): bool {.noSideEffect, inline, magi
from std/private/digitsutils import addInt
export addInt
when defined(js):
when defined(js) and not defined(nimscript):
# nimscript can be defined if config file for js compilation
include "system/jssys"
include "system/reprjs"

View File

@@ -1,4 +1,4 @@
proc succ*[T: Ordinal](x: T, y: int = 1): T {.magic: "Succ", noSideEffect.} =
proc succ*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Succ", noSideEffect.} =
## Returns the `y`-th successor (default: 1) of the value `x`.
##
## If such a value does not exist, `OverflowDefect` is raised
@@ -7,7 +7,7 @@ proc succ*[T: Ordinal](x: T, y: int = 1): T {.magic: "Succ", noSideEffect.} =
assert succ(5) == 6
assert succ(5, 3) == 8
proc pred*[T: Ordinal](x: T, y: int = 1): T {.magic: "Pred", noSideEffect.} =
proc pred*[T, V: Ordinal](x: T, y: V = 1): T {.magic: "Pred", noSideEffect.} =
## Returns the `y`-th predecessor (default: 1) of the value `x`.
##
## If such a value does not exist, `OverflowDefect` is raised
@@ -16,7 +16,7 @@ proc pred*[T: Ordinal](x: T, y: int = 1): T {.magic: "Pred", noSideEffect.} =
assert pred(5) == 4
assert pred(5, 3) == 2
proc inc*[T: Ordinal](x: var T, y: int = 1) {.magic: "Inc", noSideEffect.} =
proc inc*[T, V: Ordinal](x: var T, y: V = 1) {.magic: "Inc", noSideEffect.} =
## Increments the ordinal `x` by `y`.
##
## If such a value does not exist, `OverflowDefect` is raised or a compile
@@ -28,7 +28,7 @@ proc inc*[T: Ordinal](x: var T, y: int = 1) {.magic: "Inc", noSideEffect.} =
inc(i, 3)
assert i == 6
proc dec*[T: Ordinal](x: var T, y: int = 1) {.magic: "Dec", noSideEffect.} =
proc dec*[T, V: Ordinal](x: var T, y: V = 1) {.magic: "Dec", noSideEffect.} =
## Decrements the ordinal `x` by `y`.
##
## If such a value does not exist, `OverflowDefect` is raised or a compile

View File

@@ -6,11 +6,11 @@ const
## ```
# see also std/private/since
NimMinor* {.intdefine.}: int = 1
NimMinor* {.intdefine.}: int = 2
## is the minor number of Nim's version.
## Odd for devel, even for releases.
NimPatch* {.intdefine.}: int = 99
NimPatch* {.intdefine.}: int = 0
## is the patch number of Nim's version.
## Odd for devel, even for releases.

View File

@@ -0,0 +1,20 @@
# issue #24179
import sugar
type
Parser[T] = object
proc eatWhile[T](p: Parser[T], predicate: T -> bool): seq[T] =
return @[]
proc skipWs(p: Parser[char]) =
discard p.eatWhile((c: char) => c == 'a')
#[!]#
discard """
$nimsuggest --tester $file
>chk $1
chk;;skUnknown;;;;Hint;;???;;0;;-1;;">> (toplevel): import(dirty): tests/tarrowcrash.nim [Processing]";;0
chk;;skUnknown;;;;Hint;;$file;;11;;5;;"\'skipWs\' is declared but not used [XDeclaredButNotUsed]";;0
"""

View File

@@ -171,3 +171,16 @@ block: # bug #23858
return Object()
discard fn()
doAssert x == 1
block: # bug #24147
type
O = object of RootObj
val: string
OO = object of O
proc `=copy`(dest: var O, src: O) =
dest.val = src.val
let oo = OO(val: "hello world")
var ooCopy : OO
`=copy`(ooCopy, oo)

View File

@@ -820,3 +820,17 @@ block: # bug #23973
doAssert t == a
n()
block: # bug #24141
func reverse(s: var openArray[char]) =
s[0] = 'f'
func rev(s: var string) =
s.reverse
proc main =
var abc = "abc"
abc.rev
doAssert abc == "fbc"
main()

View File

@@ -41,6 +41,11 @@ block t8333:
case 0
of 'a': echo 0
else: echo 1
block: # issue #11422
var c: int = 5
case c
of 'a' .. 'c': discard
else: discard
block emptyset_when:

View File

@@ -0,0 +1,7 @@
block: # issue #22661
template foo(a: typed) =
a
foo:
case false
of false..true: discard

View File

@@ -22,3 +22,49 @@ block: # bug #23902
proc foo(a: sink string) =
var x = (a, a)
block: # bug #24175
block:
func mutate(o: sink string): string =
o[1] = '1'
result = o
static:
let s = "999"
let m = mutate(s)
doAssert s == "999"
doAssert m == "919"
func foo() =
let s = "999"
let m = mutate(s)
doAssert s == "999"
doAssert m == "919"
static:
foo()
foo()
block:
type O = object
a: int
func mutate(o: sink O): O =
o.a += 1
o
static:
let x = O(a: 1)
let y = mutate(x)
doAssert x.a == 1
doAssert y.a == 2
proc foo() =
let x = O(a: 1)
let y = mutate(x)
doAssert x.a == 1
doAssert y.a == 2
static:
foo()
foo()

View File

@@ -0,0 +1,21 @@
# issue #22523
from std/typetraits import distinctBase
type
V[p: static int] = distinct int
D[p: static int] = distinct int
T = V[1]
proc f(y: var T) = discard
var a: D[0]
static:
doAssert distinctBase(T) is distinctBase(D[0])
doAssert distinctBase(T) is int
doAssert distinctBase(D[0]) is int
doAssert T(a) is T
f(cast[ptr T](addr a)[])
f(T(a))

View File

@@ -1,9 +1,9 @@
discard """
errormsg: "for a 'var' type a variable needs to be passed; but 'uint16(x)' is immutable"
errormsg: "type mismatch: got <uint8>"
"""
proc toUInt16(x: var uint16) =
discard
var x = uint8(1)
toUInt16 x
toUInt16 x

View File

@@ -0,0 +1,13 @@
discard """
matrix: "-d:testsConciseTypeMismatch"
"""
template v[T](c: SomeOrdinal): T = T(c)
discard v[int, char]('A') #[tt.Error
^ type mismatch
Expression: v[int, char]('A')
[1] 'A': char
Expected one of (first mismatch at [position]):
[2] template v[T](c: SomeOrdinal): T
generic parameter mismatch, expected SomeOrdinal but got 'char' of type: char]#

View File

@@ -0,0 +1,10 @@
template v[T](c: SomeOrdinal): T = T(c)
discard v[int, char]('A') #[tt.Error
^ type mismatch: got <char>
but expected one of:
template v[T](c: SomeOrdinal): T
first type mismatch at position: 2 in generic parameters
required type for SomeOrdinal: SomeOrdinal
but expression 'char' is of type: char
expression: v[int, char]('A')]#

View File

@@ -9,7 +9,7 @@ tundeclared_routine.nim(29, 28) Error: invalid pragma: myPragma
tundeclared_routine.nim(36, 13) Error: undeclared field: 'bar3' for type tundeclared_routine.Foo [type declared in tundeclared_routine.nim(33, 8)]
found tundeclared_routine.bar3() [iterator declared in tundeclared_routine.nim(35, 12)]
tundeclared_routine.nim(41, 13) Error: undeclared field: 'bar4' for type tundeclared_routine.Foo [type declared in tundeclared_routine.nim(39, 8)]
tundeclared_routine.nim(44, 15) Error: attempting to call routine: 'bad5'
tundeclared_routine.nim(44, 11) Error: undeclared identifier: 'bad5'
'''
"""

View File

@@ -9,7 +9,7 @@ Expression: newImage[string](320, 200)
Expected one of (first mismatch at [position]):
[1] proc newImage[T: int32 | int64](w, h: int): ref Image[T]
generic parameter mismatch, expected int32 or int64 but got 'string' of type: typedesc[string]
generic parameter mismatch, expected int32 or int64 but got 'string' of type: string
'''
"""

View File

@@ -6,7 +6,7 @@ but expected one of:
proc newImage[T: int32 | int64](w, h: int): ref Image[T]
first type mismatch at position: 1 in generic parameters
required type for T: int32 or int64
but expression 'string' is of type: typedesc[string]
but expression 'string' is of type: string
expression: newImage[string](320, 200)
'''

View File

@@ -1,4 +1,4 @@
{.experimental: "genericsOpenSym".}
{.experimental: "openSym".}
import mopensymimport1

View File

@@ -0,0 +1,26 @@
# issue #16128
import std/[tables, hashes]
type
NodeId*[L] = object
isSource: bool
index: Table[NodeId[L], seq[NodeId[L]]]
func hash*[L](id: NodeId[L]): Hash = discard
func `==`[L](a, b: NodeId[L]): bool = discard
proc makeIndex*[T, L](tree: T) =
var parent = NodeId[L]()
var tmp: Table[NodeId[L], seq[NodeId[L]]]
tmp[parent] = @[parent]
proc simpleTreeDiff*[T, L](source, target: T) =
# Swapping these two lines makes error disappear
var m: Table[NodeId[L], NodeId[L]]
makeIndex[T, L](target)
var tmp: Table[string, seq[string]] # removing this forward declaration also removes error
proc diff(x1, x2: string): auto =
simpleTreeDiff[int, string](12, 12)

View File

@@ -44,3 +44,15 @@ block: # constant condition after dynamic one
doAssert y.a is int
var z: Foo[float]
doAssert z.a is string
block: # issue #4774, but not with threads
const hasThreadSupport = not defined(js)
when hasThreadSupport:
type Channel[T] = object
value: T
type
SomeObj[T] = object
when hasThreadSupport:
channel: ptr Channel[T]
var x: SomeObj[int]
doAssert compiles(x.channel) == hasThreadSupport

View File

@@ -1,4 +1,4 @@
{.experimental: "genericsOpenSym".}
{.experimental: "openSym".}
block: # issue #22605, normal call syntax
const error = "bad"

View File

@@ -451,3 +451,67 @@ block: # real version of above
proc foo[T](x: T, a = Opt.none(int)) = discard
foo(1, a = Opt.none(int))
foo(1)
block: # issue #20880
type
Child[n: static int] = object
data: array[n, int]
Parent[n: static int] = object
child: Child[3*n]
const n = 3
doAssert $(typeof Parent[n*3]()) == "Parent[9]"
doAssert $(typeof Parent[1]().child) == "Child[3]"
doAssert Parent[1]().child.data.len == 3
{.experimental: "dynamicBindSym".}
block: # issue #16774
type SecretWord = distinct uint64
const WordBitWidth = 8 * sizeof(uint64)
func wordsRequired(bits: int): int {.compileTime.} =
## Compute the number of limbs required
# from the **announced** bit length
(bits + WordBitWidth - 1) div WordBitWidth
type
Curve = enum BLS12_381
BigInt[bits: static int] = object
limbs: array[bits.wordsRequired, SecretWord]
const BLS12_381_Modulus = default(BigInt[381])
macro Mod(C: static Curve): untyped =
## Get the Modulus associated to a curve
result = bindSym($C & "_Modulus")
macro getCurveBitwidth(C: static Curve): untyped =
result = nnkDotExpr.newTree(
getAST(Mod(C)),
ident"bits"
)
type Fp[C: static Curve] = object
## Finite Fields / Modular arithmetic
## modulo the curve modulus
mres: BigInt[getCurveBitwidth(C)]
var x: Fp[BLS12_381]
doAssert x.mres.limbs.len == wordsRequired(getCurveBitWidth(BLS12_381))
# minimized, as if we haven't tested it already:
macro makeIntLit(c: static int): untyped =
result = newLit(c)
type Test[T: static int] = object
myArray: array[makeIntLit(T), int]
var y: Test[2]
doAssert y.myArray.len == 2
var z: Test[4]
doAssert z.myArray.len == 4
block: # issue #16175
type
Thing[D: static uint] = object
when D == 0:
kid: char
else:
kid: Thing[D-1]
var t2 = Thing[3]()
doAssert t2.kid is Thing[2.uint]
doAssert t2.kid.kid is Thing[1.uint]
doAssert t2.kid.kid.kid is Thing[0.uint]
doAssert t2.kid.kid.kid.kid is char
var s = Thing[1]()
doAssert s.kid is Thing[0.uint]
doAssert s.kid.kid is char

View File

@@ -32,3 +32,9 @@ block t4175:
const j = 0u - 1u
doAssert i == j
doAssert j + 1u == 0u
block: # https://forum.nim-lang.org/t/12465#76998
var a: int = 1
var x: uint8 = 1
a.inc(x) # Error: type mismatch
doAssert a == 2

View File

@@ -0,0 +1,16 @@
discard """
action: reject
nimout: '''
but expression 'int(a)' is immutable, not 'var'
'''
"""
proc `++`(n: var int) =
n += 1
var a: int32 = 15
++int(a) #[tt.Error
^ type mismatch: got <int>]#
echo a

View File

@@ -0,0 +1,9 @@
proc `++`(n: var int) =
n += 1
var a: int32 = 15
++a #[tt.Error
^ type mismatch: got <int32>]#
echo a

View File

@@ -0,0 +1 @@
import std/jsffi

View File

@@ -0,0 +1 @@
# test the condition where both `js` and `nimscript` are defined (nimscript receives priority)

21
tests/lent/tvm.nim Normal file
View File

@@ -0,0 +1,21 @@
block: # issue #17527
iterator items2[IX, T](a: array[IX, T]): lent T {.inline.} =
var i = low(IX)
if i <= high(IX):
while true:
yield a[i]
if i >= high(IX): break
inc(i)
proc main() =
var s: seq[string] = @[]
for i in 0..<3:
for (key, val) in items2([("any", "bar")]):
s.add $(i, key, val)
doAssert s == @[
"(0, \"any\", \"bar\")",
"(1, \"any\", \"bar\")",
"(2, \"any\", \"bar\")"
]
static: main()

View File

@@ -0,0 +1,2 @@
proc count*(s: string): int =
s.len

View File

@@ -0,0 +1 @@
var count*: int = 10

View File

@@ -0,0 +1 @@
const count* = 3.142

View File

@@ -0,0 +1,10 @@
# issue #12732
import std/macros
const getPrivate3_tmp* = 0
const foobar1* = 0 # comment this or make private and it'll compile fine
macro foobar4*(): untyped =
newLit "abc"
template currentPkgDir2*: string = foobar4()
macro currentPkgDir2*(dir: string): untyped =
newLit "abc2"

View File

@@ -0,0 +1,8 @@
# issue #15247
import mdisambsym1, mdisambsym2, mdisambsym3
proc twice(n: int): int =
n*2
doAssert twice(count) == 20

View File

@@ -0,0 +1,5 @@
# issue #12732
import mmacroamb
const s0 = currentPkgDir2 #[tt.Error
^ ambiguous identifier: 'currentPkgDir2' -- use one of the following:]#

View File

@@ -24,6 +24,9 @@ for i, (x, y) in pairs(data):
var (a, b) = (1, 2)
type
A* = object
var t04 = 1.0'f128
t04 = 2.0'f128
'''
"""
@@ -49,3 +52,7 @@ echoTypedAndUntypedRepr:
discard
var (a,b) = (1,2)
type A* = object # issue #22933
echoUntypedRepr:
var t04 = 1'f128
t04 = 2'f128

View File

@@ -1,9 +1,9 @@
discard """
nimout: '''intProc; ntyProc; proc[int, int, float]; proc (a: int; b: float): int
nimout: '''intProc; ntyProc; proc[int, int, float]; proc (a: int; b: float): int {.nimcall.}
void; ntyVoid; void; void
int; ntyInt; int; int
proc (); ntyProc; proc[void]; proc ()
voidProc; ntyProc; proc[void]; proc ()
proc () {.nimcall.}; ntyProc; proc[void]; proc () {.nimcall.}
voidProc; ntyProc; proc[void]; proc () {.nimcall.}
listing fields for ObjType
a: string
b: int

View File

@@ -0,0 +1,28 @@
discard """
nimout: '''
var x: proc () {.cdecl.} = foo
var x: iterator (): int {.closure.} = bar
'''
"""
# issue #19010
import macros
macro createVar(x: typed): untyped =
result = nnkVarSection.newTree:
newIdentDefs(ident"x", getTypeInst(x), copy(x))
echo repr result
block:
proc foo() {.cdecl.} = discard
createVar(foo)
x()
block:
iterator bar(): int {.closure.} = discard
createVar(bar)
for a in x(): discard

View File

@@ -157,3 +157,12 @@ block t3338:
var t2 = Bar[int32]()
t2.add()
doAssert t2.x == 5
block: # issue #24203
proc b(G: typedesc) =
type U = G
template s(h: untyped) = h
s(b(typeof (0, 0)))
b(seq[int])
b((int, int))
b(typeof (0, 0))

View File

@@ -7,12 +7,12 @@ mused2a.nim(12, 6) Hint: 'fn1' is declared but not used [XDeclaredButNotUsed]
mused2a.nim(16, 5) Hint: 'fn4' is declared but not used [XDeclaredButNotUsed]
mused2a.nim(20, 7) Hint: 'fn7' is declared but not used [XDeclaredButNotUsed]
mused2a.nim(23, 6) Hint: 'T1' is declared but not used [XDeclaredButNotUsed]
mused2a.nim(1, 11) Warning: imported and not used: 'strutils' [UnusedImport]
mused2a.nim(3, 9) Warning: imported and not used: 'os' [UnusedImport]
mused2a.nim(1, 12) Warning: imported and not used: 'strutils' [UnusedImport]
mused2a.nim(3, 10) Warning: imported and not used: 'os' [UnusedImport]
mused2a.nim(5, 23) Warning: imported and not used: 'typetraits2' [UnusedImport]
mused2a.nim(6, 9) Warning: imported and not used: 'setutils' [UnusedImport]
mused2a.nim(6, 10) Warning: imported and not used: 'setutils' [UnusedImport]
tused2.nim(42, 8) Warning: imported and not used: 'mused2a' [UnusedImport]
tused2.nim(45, 11) Warning: imported and not used: 'strutils' [UnusedImport]
tused2.nim(45, 12) Warning: imported and not used: 'strutils' [UnusedImport]
'''
"""

View File

@@ -0,0 +1,10 @@
discard """
errormsg: "The MPlayerObj type doesn't have a default value. The following fields must be initialized: foo."
"""
type
MPlayerObj* {.requiresInit.} = object
foo: range[5..10] = 5
var a: MPlayerObj
echo a.foo

View File

@@ -0,0 +1,145 @@
import
std/[macros, tables, hashes]
export
macros
type
FieldDescription* = object
name*: NimNode
isPublic*: bool
isDiscriminator*: bool
typ*: NimNode
pragmas*: NimNode
caseField*: NimNode
caseBranch*: NimNode
{.push raises: [].}
func isTuple*(t: NimNode): bool =
t.kind == nnkBracketExpr and t[0].kind == nnkSym and eqIdent(t[0], "tuple")
macro isTuple*(T: type): untyped =
newLit(isTuple(getType(T)[1]))
proc collectFieldsFromRecList(result: var seq[FieldDescription],
n: NimNode,
parentCaseField: NimNode = nil,
parentCaseBranch: NimNode = nil,
isDiscriminator = false) =
case n.kind
of nnkRecList:
for entry in n:
collectFieldsFromRecList result, entry,
parentCaseField, parentCaseBranch
of nnkRecWhen:
for branch in n:
case branch.kind:
of nnkElifBranch:
collectFieldsFromRecList result, branch[1],
parentCaseField, parentCaseBranch
of nnkElse:
collectFieldsFromRecList result, branch[0],
parentCaseField, parentCaseBranch
else:
doAssert false
of nnkRecCase:
collectFieldsFromRecList result, n[0],
parentCaseField,
parentCaseBranch,
isDiscriminator = true
for i in 1 ..< n.len:
let branch = n[i]
case branch.kind
of nnkOfBranch:
collectFieldsFromRecList result, branch[^1], n[0], branch
of nnkElse:
collectFieldsFromRecList result, branch[0], n[0], branch
else:
doAssert false
of nnkIdentDefs:
let fieldType = n[^2]
for i in 0 ..< n.len - 2:
var field: FieldDescription
field.name = n[i]
field.typ = fieldType
field.caseField = parentCaseField
field.caseBranch = parentCaseBranch
field.isDiscriminator = isDiscriminator
if field.name.kind == nnkPragmaExpr:
field.pragmas = field.name[1]
field.name = field.name[0]
if field.name.kind == nnkPostfix:
field.isPublic = true
field.name = field.name[1]
result.add field
of nnkSym:
result.add FieldDescription(
name: n,
typ: getType(n),
caseField: parentCaseField,
caseBranch: parentCaseBranch,
isDiscriminator: isDiscriminator)
of nnkNilLit, nnkDiscardStmt, nnkCommentStmt, nnkEmpty:
discard
else:
doAssert false, "Unexpected nodes in recordFields:\n" & n.treeRepr
proc collectFieldsInHierarchy(result: var seq[FieldDescription],
objectType: NimNode) =
var objectType = objectType
objectType.expectKind {nnkObjectTy, nnkRefTy}
if objectType.kind == nnkRefTy:
objectType = objectType[0]
objectType.expectKind nnkObjectTy
var baseType = objectType[1]
if baseType.kind != nnkEmpty:
baseType.expectKind nnkOfInherit
baseType = baseType[0]
baseType.expectKind nnkSym
baseType = getImpl(baseType)
baseType.expectKind nnkTypeDef
baseType = baseType[2]
baseType.expectKind {nnkObjectTy, nnkRefTy}
collectFieldsInHierarchy result, baseType
let recList = objectType[2]
collectFieldsFromRecList result, recList
proc recordFields*(typeImpl: NimNode): seq[FieldDescription] =
if typeImpl.isTuple:
for i in 1 ..< typeImpl.len:
result.add FieldDescription(typ: typeImpl[i], name: ident("Field" & $(i - 1)))
return
let objectType = case typeImpl.kind
of nnkObjectTy: typeImpl
of nnkTypeDef: typeImpl[2]
else:
macros.error("object type expected", typeImpl)
return
collectFieldsInHierarchy(result, objectType)
macro field*(obj: typed, fieldName: static string): untyped =
newDotExpr(obj, ident fieldName)
proc skipPragma*(n: NimNode): NimNode =
if n.kind == nnkPragmaExpr: n[0]
else: n
{.pop.}

View File

@@ -0,0 +1,13 @@
block: # issue #13799
type
X[A, B] = object
a: A
b: B
Y[A] = X[A, int]
template s(T: type X): X = T()
template t[A, B](T: type X[A, B]): X[A, B] = T()
proc works1(): Y[int] = s(X[int, int])
proc works2(): Y[int] = t(X[int, int])
proc works3(): Y[int] = t(Y[int])
proc broken(): Y[int] = s(Y[int])

View File

@@ -16,3 +16,26 @@ block: # bug #8568
proc g(a: D|E): string = "foo D|E"
proc g(a: D): string = "foo D"
doAssert g(D[int]()) == "foo D"
type Obj1[T] = object
v: T
converter toObj1[T](t: T): Obj1[T] = return Obj1[T](v: t)
block: # issue #10019
proc fun1[T](elements: seq[T]): string = "fun1 seq"
proc fun1(o: object|tuple): string = "fun1 object|tuple"
proc fun2[T](elements: openArray[T]): string = "fun2 openarray"
proc fun2(o: object): string = "fun2 object"
proc fun_bug[T](elements: openArray[T]): string = "fun_bug openarray"
proc fun_bug(o: object|tuple):string = "fun_bug object|tuple"
proc main() =
var x = @["hello", "world"]
block:
# no ambiguity error shown here even though this would compile if we remove either 1st or 2nd overload of fun1
doAssert fun1(x) == "fun1 seq"
block:
# ditto
doAssert fun2(x) == "fun2 openarray"
block:
# Error: ambiguous call; both t0065.fun_bug(elements: openarray[T])[declared in t0065.nim(17, 5)] and t0065.fun_bug(o: object or tuple)[declared in t0065.nim(20, 5)] match for: (array[0..1, string])
doAssert fun_bug(x) == "fun_bug openarray"
main()

View File

@@ -0,0 +1,19 @@
import macros
block: # issue #7385
type CustomSeq[T] = object
data: seq[T]
macro `[]`[T](s: CustomSeq[T], args: varargs[untyped]): untyped =
## The end goal is to replace the joker "_" by something else
result = newIntLitNode(10)
proc foo1(): CustomSeq[int] =
result.data.newSeq(10)
# works since no overload matches first argument with type `CustomSeq`
# except magic `[]`, which always matches without checking arguments
doAssert result[_] == 10
doAssert foo1() == CustomSeq[int](data: newSeq[int](10))
proc foo2[T](): CustomSeq[T] =
result.data.newSeq(10)
# works fine with generic return type
doAssert result[_] == 10
doAssert foo2[int]() == CustomSeq[int](data: newSeq[int](10))

View File

@@ -0,0 +1,207 @@
discard """
action: compile
"""
# https://github.com/status-im/nimbus-eth2/pull/6554#issuecomment-2354977102
# failed with "for a 'var' type a variable needs to be passed; but 'uint64(result)' is immutable"
import
std/[typetraits, macros]
type
DefaultFlavor = object
template serializationFormatImpl(Name: untyped) {.dirty.} =
type Name = object
template serializationFormat(Name: untyped) =
serializationFormatImpl(Name)
template setReader(Format, FormatReader: distinct type) =
when arity(FormatReader) > 1:
template Reader(T: type Format, F: distinct type = DefaultFlavor): type = FormatReader[F]
else:
template ReaderType(T: type Format): type = FormatReader
template Reader(T: type Format): type = FormatReader
template useDefaultReaderIn(T: untyped, Flavor: type) =
mixin Reader
template readValue(r: var Reader(Flavor), value: var T) =
mixin readRecordValue
readRecordValue(r, value)
import mvaruintconv
type
FieldTag[RecordType: object; fieldName: static string] = distinct void
func declval*(T: type): T {.compileTime.} =
default(ptr T)[]
macro enumAllSerializedFieldsImpl(T: type, body: untyped): untyped =
var typeAst = getType(T)[1]
var typeImpl: NimNode
let isSymbol = not typeAst.isTuple
if not isSymbol:
typeImpl = typeAst
else:
typeImpl = getImpl(typeAst)
result = newStmtList()
var i = 0
for field in recordFields(typeImpl):
let
fieldIdent = field.name
realFieldName = newLit($fieldIdent.skipPragma)
fieldName = realFieldName
fieldIndex = newLit(i)
let fieldNameDefs =
if isSymbol:
quote:
const fieldName {.inject, used.} = `fieldName`
const realFieldName {.inject, used.} = `realFieldName`
else:
quote:
const fieldName {.inject, used.} = $`fieldIndex`
const realFieldName {.inject, used.} = $`fieldIndex`
let field =
if isSymbol:
quote do: declval(`T`).`fieldIdent`
else:
quote do: declval(`T`)[`fieldIndex`]
result.add quote do:
block:
`fieldNameDefs`
template FieldType: untyped {.inject, used.} = typeof(`field`)
`body`
# echo repr(result)
template enumAllSerializedFields(T: type, body): untyped =
enumAllSerializedFieldsImpl(T, body)
type
FieldReader[RecordType, Reader] = tuple[
fieldName: string,
reader: proc (rec: var RecordType, reader: var Reader)
{.gcsafe, nimcall.}
]
proc totalSerializedFieldsImpl(T: type): int =
mixin enumAllSerializedFields
enumAllSerializedFields(T): inc result
template totalSerializedFields(T: type): int =
(static(totalSerializedFieldsImpl(T)))
template GetFieldType(FT: type FieldTag): type =
typeof field(declval(FT.RecordType), FT.fieldName)
proc makeFieldReadersTable(RecordType, ReaderType: distinct type,
numFields: static[int]):
array[numFields, FieldReader[RecordType, ReaderType]] =
mixin enumAllSerializedFields, handleReadException
var idx = 0
enumAllSerializedFields(RecordType):
proc readField(obj: var RecordType, reader: var ReaderType)
{.gcsafe, nimcall.} =
mixin readValue
type F = FieldTag[RecordType, realFieldName]
field(obj, realFieldName) = reader.readValue(GetFieldType(F))
result[idx] = (fieldName, readField)
inc idx
proc fieldReadersTable(RecordType, ReaderType: distinct type): auto =
mixin readValue
type T = RecordType
const numFields = totalSerializedFields(T)
var tbl {.threadvar.}: ref array[numFields, FieldReader[RecordType, ReaderType]]
if tbl == nil:
tbl = new typeof(tbl)
tbl[] = makeFieldReadersTable(RecordType, ReaderType, numFields)
return addr(tbl[])
proc readValue(reader: var auto, T: type): T =
mixin readValue
reader.readValue(result)
template decode(Format: distinct type,
input: string,
RecordType: distinct type): auto =
mixin Reader
block: # https://github.com/nim-lang/Nim/issues/22874
var reader: Reader(Format)
reader.readValue(RecordType)
template readValue(Format: type,
ValueType: type): untyped =
mixin Reader, init, readValue
var reader: Reader(Format)
readValue reader, ValueType
template parseArrayImpl(numElem: untyped,
actionValue: untyped) =
actionValue
serializationFormat Json
template createJsonFlavor(FlavorName: untyped,
skipNullFields = false) {.dirty.} =
type FlavorName = object
template Reader(T: type FlavorName): type = Reader(Json, FlavorName)
type
JsonReader[Flavor = DefaultFlavor] = object
Json.setReader JsonReader
template parseArray(r: var JsonReader; body: untyped) =
parseArrayImpl(idx): body
template parseArray(r: var JsonReader; idx: untyped; body: untyped) =
parseArrayImpl(idx): body
proc readRecordValue[T](r: var JsonReader, value: var T) =
type
ReaderType {.used.} = type r
T = type value
discard T.fieldReadersTable(ReaderType)
proc readValue[T](r: var JsonReader, value: var T) =
mixin readValue
when value is seq:
r.parseArray:
readValue(r, value[0])
elif value is object:
readRecordValue(r, value)
type
RemoteSignerInfo = object
id: uint32
RemoteKeystore = object
proc readValue(reader: var JsonReader, value: var RemoteKeystore) =
discard reader.readValue(seq[RemoteSignerInfo])
createJsonFlavor RestJson
useDefaultReaderIn(RemoteSignerInfo, RestJson)
proc readValue(reader: var JsonReader[RestJson], value: var uint64) =
discard reader.readValue(string)
discard Json.decode("", RemoteKeystore)
block: # https://github.com/nim-lang/Nim/issues/22874
var reader: Reader(RestJson)
discard reader.readValue(RemoteSignerInfo)

View File

@@ -0,0 +1,3 @@
type Foo = ref int
not nil #[tt.Error
^ invalid indentation]#

View File

@@ -0,0 +1,10 @@
# issue #23565
func foo: bool =
true
const bar = block:
type T = int
not foo()
doAssert not bar

View File

@@ -531,3 +531,10 @@ block:
check(a)
check(b)
block: # https://forum.nim-lang.org/t/12522, backticks
template `mypragma`() {.pragma.}
# Error: invalid pragma: `mypragma`
type Test = object
field {.`mypragma`.}: int
doAssert Test().field.hasCustomPragma(mypragma)

View File

@@ -124,3 +124,21 @@ foo31()
foo41()
{.pop.}
import macros
block:
{.push deprecated.}
template test() = discard
test()
{.pop.}
macro foo(): bool =
let ast = getImpl(bindSym"test")
var found = false
if ast[4].kind == nnkPragma:
for x in ast[4]:
if x.eqIdent"deprecated":
found = true
break
result = newLit(found)
doAssert foo()

View File

@@ -43,3 +43,13 @@ block: # ditto but may be wrong minimization
# alternative version, also causes instantiation issue
proc baz[T](x: typeof(foo[T]())) = discard
baz[int](Foo[int]())
block: # issue #21346
type K[T] = object
template s[T](x: int) = doAssert T is K[K[int]]
proc b1(n: bool | bool) = s[K[K[int]]](3)
proc b2(n: bool) = s[K[K[int]]](3)
template b3(n: bool) = s[K[K[int]]](3)
b1(false) # Error: cannot instantiate K; got: <T> but expected: <T>
b2(false) # Builds, on its own
b3(false)

View File

@@ -67,3 +67,32 @@ block: # issue #24099, modified to work but using float32
## Compares colors with given accuracy.
abs(a[0] - b[0]) < e and abs(a[1] - b[1]) < e and abs(a[2] - b[2]) < e
doAssert ColorRGBU([1.float32, 1, 1]) ~= ColorRGBU([1.float32, 1, 1])
block: # issue #13270
type
A = object
B = object
proc f(a: A) = discard
proc g[T](value: T, cb: (proc(a: T)) = f) =
cb value
g A()
# This should fail because there is no f(a: B) overload available
doAssert not compiles(g B())
block: # issue #24121
type
Foo = distinct int
Bar = distinct int
FooBar = Foo | Bar
proc foo[T: distinct](x: T): string = "a"
proc foo(x: Foo): string = "b"
proc foo(x: Bar): string = "c"
proc bar(x: FooBar, y = foo(x)): string = y
doAssert bar(Foo(123)) == "b"
doAssert bar(Bar(123)) == "c"
proc baz[T: FooBar](x: T, y = foo(x)): string = y
doAssert baz(Foo(123)) == "b"
doAssert baz(Bar(123)) == "c"

View File

@@ -250,3 +250,19 @@ block: # `when` in static signature
proc foo[T](): T = test()
proc bar[T](x = foo[T]()): T = x
doAssert bar[int]() == 123
block: # issue #22276
type Foo = enum A, B
macro test(y: static[Foo]): untyped =
if y == A:
result = parseExpr("proc (x: int)")
else:
result = parseExpr("proc (x: float)")
proc foo(y: static[Foo], x: test(y)) = # We want to make the type of `x` depend on what `y` is
x(9)
foo(A, proc (x: int) = doAssert x == 9)
var a: int
foo(A, proc (x: int) =
a = x * 2)
doAssert a == 18
foo(B, proc (x: float) = doAssert x == 9)

View File

@@ -1,5 +1,7 @@
discard """
matrix: "--mm:refc; --mm:orc"
# test C with -d:nimUseCppAtomics as well to check nothing breaks
matrix: "--mm:refc; --mm:orc; --mm:refc -d:nimUseCppAtomics; --mm:orc -d:nimUseCppAtomics"
targets: "c cpp"
"""
# test atomic operations

View File

@@ -1,5 +1,6 @@
discard """
matrix: "--mm:refc; --mm:orc"
# test C with -d:nimUseCppAtomics as well to check nothing breaks
matrix: "--mm:refc; --mm:orc; --mm:refc -d:nimUseCppAtomics; --mm:orc -d:nimUseCppAtomics"
targets: "c cpp"
"""
import std/atomics
@@ -17,4 +18,4 @@ block testSize: # issue 12726
f: AtomicFlag
static:
doAssert sizeof(Node) == sizeof(pointer)
doAssert sizeof(MyChannel) == sizeof(pointer) * 2
doAssert sizeof(MyChannel) == sizeof(pointer) * 2

View File

@@ -0,0 +1,54 @@
# issue #12405
import std/[marshal, streams, times, tables, os, assertions]
type AiredEpisodeState * = ref object
airedAt * : DateTime
tvShowId * : string
seasonNumber * : int
number * : int
title * : string
type ShowsWatchlistState * = ref object
aired * : seq[AiredEpisodeState]
type UiState * = ref object
shows: ShowsWatchlistState
# Helpers to marshal and unmarshal
proc load * ( state : var UiState, file : string ) =
var strm = newFileStream( file, fmRead )
strm.load( state )
strm.close()
proc store * ( state : UiState, file : string ) =
var strm = newFileStream( file, fmWrite )
strm.store( state )
strm.close()
# 1. We fill the state initially
var state : UiState = UiState( shows: ShowsWatchlistState( aired: @[] ) )
# VERY IMPORTANT: For some reason, small numbers (like 2 or 3) don't trigger the bug. Anything above 7 or 8 on my machine triggers though
for i in 0..30:
var episode = AiredEpisodeState( airedAt: now(), tvShowId: "1", seasonNumber: 1, number: 1, title: "string" )
state.shows.aired.add( episode )
# 2. Store it in a file with the marshal module, and then load it back up
store( state, "tmarshalsegfault_data" )
load( state, "tmarshalsegfault_data" )
removeFile("tmarshalsegfault_data")
# 3. VERY IMPORTANT: Without this line, for some reason, everything works fine
state.shows.aired[ 0 ] = AiredEpisodeState( airedAt: now(), tvShowId: "1", seasonNumber: 1, number: 1, title: "string" )
# 4. And formatting the airedAt date will now trigger the exception
for ep in state.shows.aired:
let x = $ep.seasonNumber & "x" & $ep.number & " (" & $ep.airedAt & ")"
let y = $ep.seasonNumber & "x" & $ep.number & " (" & $ep.airedAt & ")"
doAssert x == y

View File

@@ -27,9 +27,8 @@ Raises
"""
# test os path creation, iteration, and deletion
import os, strutils, pathnorm
from stdtest/specialpaths import buildDir
import std/[syncio, assertions]
import std/[syncio, assertions, osproc, os, strutils, pathnorm]
block fileOperations:
let files = @["these.txt", "are.x", "testing.r", "files.q"]
@@ -161,6 +160,18 @@ block fileOperations:
# createDir should not fail if `dir` is empty
createDir("")
when defined(linux): # bug #24174
createDir("a/b")
open("a/file.txt", fmWrite).close
if not fileExists("a/fifoFile"):
doAssert execCmd("mkfifo -m 600 a/fifoFile") == 0
copyDir("a/", "../dest/a/", skipSpecial = true)
copyDirWithPermissions("a/", "../dest2/a/", skipSpecial = true)
removeDir("a")
# Symlink handling in `copyFile`, `copyFileWithPermissions`, `copyFileToDir`,
# `copyDir`, `copyDirWithPermissions`, `moveFile`, and `moveDir`.
block:

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