Compare commits

..

32 Commits

Author SHA1 Message Date
ringabout
e1b62d4442 fixes documentation 2024-09-27 11:31:02 +08: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
90 changed files with 1392 additions and 311 deletions

View File

@@ -128,8 +128,7 @@ is often an easy workaround.
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.
@@ -150,7 +149,7 @@ is often an easy workaround.
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):
@@ -163,8 +162,6 @@ is often an easy workaround.
return value
assert baz[int]() == "captured"
# {.experimental: "templateOpenSym".} would be needed here if genericsOpenSym was used
template barTempl(): string =
block:
foo(123):
@@ -185,6 +182,34 @@ is often an easy workaround.
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.

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:

View File

@@ -1,19 +0,0 @@
type
Snippet = string
Builder = string
template newBuilder(s: string): Builder =
s
proc addField(obj: var Builder; field: Snippet;) =
obj.add field
obj.add ";\n"
template withStruct(obj: var Builder; structOrUnion: string; name: string; inheritance: string; body: typed) =
if inheritance.len > 0:
obj.add "$1 $2 : public $1 {$n" % [structOrUnion, name, inheritance]
else:
obj.add "$1 $2 {$n" % [structOrUnion, name]
body
obj.add("};\n")

View File

@@ -798,59 +798,36 @@ proc fillObjectFields*(m: BModule; typ: PType) =
proc mangleDynLibProc(sym: PSym): Rope
when defined(nimUseCBuilder):
proc getRecordDescAux(result: var Builder; m: BModule; typ: PType, name, baseType: Rope,
check: var IntSet, hasField: var bool) =
if typ.kind == tyObject:
if typ.baseClass == nil:
if lacksMTypeField(typ):
discard
else:
if optTinyRtti in m.config.globalOptions:
var field = "" # TODO: handle #
appcg(m, field, "#TNimTypeV2* m_type", [])
result.addField field
else:
var field = ""
appcg(m, field, "#TNimType* m_type", [])
result.addField field
hasField = true
else:
result.addField "$1 Sup" % [baseType]
hasField = true
else:
discard
else:
proc getRecordDescAux(m: BModule; typ: PType, name, baseType: 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
result = ""
if typ.kind == tyObject:
if typ.baseClass == nil:
if lacksMTypeField(typ):
appcg(m, result, " {$n", [])
else:
appcg(m, result, " {$n $1 Sup;$n", [baseType])
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:
result.addf(" {$n", [name])
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 =
@@ -868,52 +845,21 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope,
if typ.baseClass != nil:
baseType = getTypeDescAux(m, typ.baseClass.skipTypes(skipPtrs), check, dkField)
if typ.sym == nil or sfCodegenDecl notin typ.sym.flags:
when defined(nimUseCBuilder):
result = newBuilder("")
let isCppInheritance = typ.kind == tyObject and m.compileToCpp and typ.baseClass != nil
withStruct(result, structOrUnion, name, if isCppInheritance: baseType else: ""):
if isCppInheritance:
hasField = true
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])
else:
getRecordDescAux(result, 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")
else:
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 = 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")
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.add(desc)
else:
result.add(desc)
result.add("};\L")
else:
let desc = getRecordFields(m, typ, check)
result = runtimeFormat(typ.sym.cgDeclFrmt, [name, desc, baseType])
@@ -922,15 +868,14 @@ proc getRecordDesc(m: BModule; typ: PType, name: Rope,
proc getTupleDesc(m: BModule; typ: PType, name: Rope,
check: var IntSet): Rope =
if kidsLen(typ) > 0:
result = newBuilder("")
withStruct(result, structOrUnion(typ), name, ""):
for i, a in typ.ikids:
result.addField "$1 Field$2" % [getTypeDescAux(m, a, check, dkField), rope(i)]
else:
result = newBuilder("")
withStruct(result, structOrUnion(typ), name, ""):
result.addField "char dummy"
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")
proc scanCppGenericSlot(pat: string, cursor, outIdx, outStars: var int): bool =
# A helper proc for handling cppimport patterns, involving numeric
@@ -987,12 +932,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,7 +373,6 @@ proc dataField(p: BProc): Rope =
proc genProcPrototype(m: BModule, sym: PSym)
include cbuilder
include ccgliterals
include ccgtypes
@@ -784,15 +783,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

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

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

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

@@ -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
@@ -3293,8 +3296,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 +3314,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

@@ -619,6 +619,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:
@@ -1864,8 +1866,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 +1884,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

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

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

@@ -245,7 +245,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 +357,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)
@@ -696,6 +697,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 +872,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 +886,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 +1054,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 +1193,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 +1533,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 +1660,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)
@@ -1742,7 +1753,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 +2175,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 +2232,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 +2246,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 +2272,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:

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

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

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

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

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

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

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

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

@@ -16,6 +16,8 @@ discard """
[Suite] RST escaping
[Suite] RST inline markup
[Suite] Misc isssues
'''
matrix: "--mm:refc; --mm:orc"
"""
@@ -1980,3 +1982,13 @@ suite "RST inline markup":
rnLeaf ')'
""")
check(warnings[] == @["input(1, 5) Warning: broken link 'f'"])
suite "Misc isssues":
test "Markdown CodeblockFields in one line (lacking enclosing ```)":
let message = """
```llvm-profdata merge first.profraw second.profraw third.profraw <more stuff maybe> -output data.profdata```"""
try:
echo rstgen.rstToHtml(message, {roSupportMarkdown}, nil)
except EParseError:
discard

View File

@@ -0,0 +1,35 @@
import std/[assertions, net, os, osproc]
# XXX: Make this test run on Windows too when we add support for Unix sockets on Windows
when defined(posix) and not defined(nimNetLite):
const nim = getCurrentCompilerExe()
let
dir = currentSourcePath().parentDir()
serverPath = dir / "unixsockettest"
let (_, err) = execCmdEx(nim & " c " & quoteShell(dir / "unixsockettest.nim"))
doAssert err == 0
let svproc = startProcess(serverPath, workingDir = dir)
doAssert svproc.running()
# Wait for the server to open the socket and listen from it
sleep(400)
block unixSocketSendRecv:
let
unixSocketPath = dir / "usox"
socket = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_NONE)
socket.connectUnix(unixSocketPath)
# for a blocking Unix socket this should never fail
socket.send("data sent through the socket\c\l", maxRetries = 0)
var resp: string
socket.readLine(resp)
doAssert resp == "Hello from server"
socket.send("bye\c\l")
socket.readLine(resp)
doAssert resp == "bye"
socket.close()
svproc.close()

View File

@@ -0,0 +1,26 @@
import std/[assertions, net, os]
let unixSocketPath = getCurrentDir() / "usox"
removeFile(unixSocketPath)
let socket = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_NONE)
socket.bindUnix(unixSocketPath)
socket.listen()
var
clientSocket: Socket
data: string
socket.accept(clientSocket)
clientSocket.readLine(data)
doAssert data == "data sent through the socket"
clientSocket.send("Hello from server\c\l")
clientSocket.readLine(data)
doAssert data == "bye"
clientSocket.send("bye\c\l")
clientSocket.close()
socket.close()
removeFile(unixSocketPath)

View File

@@ -0,0 +1,2 @@
template foo*(x: untyped) =
echo "got: ", x

View File

@@ -0,0 +1,2 @@
proc foo*(a: string) =
echo "got string: ", a

19
tests/template/t19277.nim Normal file
View File

@@ -0,0 +1,19 @@
discard """
output: '''
got: 0
'''
"""
# issue #19277
import m19277_1, m19277_2
template injector(val: untyped): untyped =
template subtemplate: untyped = val
subtemplate()
template methodCall(val: untyped): untyped = val
{.push raises: [Defect].}
foo(injector(0).methodCall())

19
tests/template/t24112.nim Normal file
View File

@@ -0,0 +1,19 @@
discard """
matrix: "--skipParentCfg --filenames:legacyRelProj --hints:off"
action: reject
"""
# issue #24112, needs --experimental:openSym disabled
block: # simplified
type
SomeObj = ref object # Doesn't error if you make SomeObj be non-ref
template foo = yield SomeObj()
when compiles(foo): discard
import std/asyncdispatch
block:
proc someProc(): Future[void] {.async.} = discard
proc foo() =
await someProc() #[tt.Error
^ Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead]#

View File

@@ -1,4 +1,4 @@
{.experimental: "templateOpenSym".}
{.experimental: "openSym".}
block: # issue #24002
type Result[T, E] = object

View File

@@ -0,0 +1,39 @@
discard """
matrix: "--skipParentCfg --filenames:legacyRelProj"
"""
const value = "captured"
template fooOld(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
body
template foo(x: int, body: untyped): untyped =
let value {.inject.} = "injected"
{.push experimental: "genericsOpenSym".}
body
{.pop.}
proc old[T](): string =
fooOld(123):
return value
doAssert old[int]() == "captured"
template oldTempl(): string =
block:
var res: string
fooOld(123):
res = value
res
doAssert oldTempl() == "captured"
proc bar[T](): string =
foo(123):
return value
doAssert bar[int]() == "injected"
template barTempl(): string =
block:
var res: string
foo(123):
res = value
res
doAssert barTempl() == "injected"

View File

@@ -1,9 +1,12 @@
discard """
cmd: '''nim c --hint:Processing:off $file'''
nimout: '''
tunused_imports.nim(11, 10) Warning: BEGIN [User]
tunused_imports.nim(36, 10) Warning: END [User]
tunused_imports.nim(34, 8) Warning: imported and not used: 'strutils' [UnusedImport]
tunused_imports.nim(14, 10) Warning: BEGIN [User]
tunused_imports.nim(41, 10) Warning: END [User]
tunused_imports.nim(37, 8) Warning: imported and not used: 'strutils' [UnusedImport]
tunused_imports.nim(38, 13) Warning: imported and not used: 'strtabs' [UnusedImport]
tunused_imports.nim(38, 22) Warning: imported and not used: 'cstrutils' [UnusedImport]
tunused_imports.nim(39, 12) Warning: imported and not used: 'macrocache' [UnusedImport]
'''
action: "compile"
"""
@@ -32,5 +35,7 @@ macro bar(): untyped =
bar()
import strutils
import std/[strtabs, cstrutils]
import std/macrocache
{.warning: "END".}

View File

@@ -325,3 +325,9 @@ block: # bug #22180
else:
(ref A)(nil)
doAssert y.isNil
block: # issue #24164, related regression
proc foo(x: proc ()) = discard
template bar(x: untyped = nil) =
foo(x)
bar()

View File

@@ -2,7 +2,7 @@ discard """
errormsg: "type mismatch: got <int>"
nimout: '''tprevent_forloopvar_mutations.nim(16, 3) Error: type mismatch: got <int>
but expected one of:
proc inc[T: Ordinal](x: var T; y: int = 1)
proc inc[T, V: Ordinal](x: var T; y: V = 1)
first type mismatch at position: 1
required type for x: var T: Ordinal
but expression 'i' is immutable, not 'var'

49
tests/vm/tconvaddr.nim Normal file
View File

@@ -0,0 +1,49 @@
block: # issue #24097
type Foo = distinct int
proc foo(x: var Foo) =
int(x) += 1
proc bar(x: var int) =
x += 1
static:
var x = Foo(1)
int(x) = int(x) + 1
doAssert x.int == 2
int(x) += 1
doAssert x.int == 3
foo(x)
doAssert x.int == 4
bar(int(x)) # need vmgen flags propagated for this
doAssert x.int == 5
type Bar = object
x: Foo
static:
var obj = Bar(x: Foo(1))
int(obj.x) = int(obj.x) + 1
doAssert obj.x.int == 2
int(obj.x) += 1
doAssert obj.x.int == 3
foo(obj.x)
doAssert obj.x.int == 4
bar(int(obj.x)) # need vmgen flags propagated for this
doAssert obj.x.int == 5
static:
var arr = @[Foo(1)]
int(arr[0]) = int(arr[0]) + 1
doAssert arr[0].int == 2
int(arr[0]) += 1
doAssert arr[0].int == 3
foo(arr[0])
doAssert arr[0].int == 4
bar(int(arr[0])) # need vmgen flags propagated for this
doAssert arr[0].int == 5
proc testResult(): Foo =
result = Foo(1)
int(result) = int(result) + 1
doAssert result.int == 2
int(result) += 1
doAssert result.int == 3
foo(result)
doAssert result.int == 4
bar(int(result)) # need vmgen flags propagated for this
doAssert result.int == 5
doAssert testResult().int == 5

View File

@@ -27,3 +27,10 @@ block:
proc p(x: int): int = x
type Foo = typeof(p(fail(123)))
block: # issue #24150, related regression
proc w(T: type): T {.compileTime.} = default(ptr T)[]
template y(v: auto): auto = typeof(v) is int
discard compiles(y(w int))
proc s(): int {.compileTime.} = discard
discard s()