Compare commits

...

19 Commits

Author SHA1 Message Date
zah
2b6b080323 Remove the use of usrToCell in gcMark [backport:1.2] (#17709)
* Remove the use of usrToCell in gcMark [backport:1.2]

Recently, we've discovered a GC crash resulting from inlining of
the memory allocation procs that allowed the compiler to avoid
maintaining any references to the "user pointer" on the stack.
Instead, a "cell pointer" appeared there and all field accesses
were performed with adjusted offsets. This interfered with the
ability of the GC to mark the correct cell in the conservative
stack scans which lead to premature collection of objects.

More details here:
af69b3ceae

This commit closes another theoretical loophole that may lead to
the same problem. If a short proc is accessing both the object and
its reference count in a short sequence of instructions, the compiler
may be enticed to reduce the number of registers being used by storing
only a single pointer to the object and using offsets when reading
and writing fields. A perfectly good strategy would be to store only
the cell pointer, so the reference count updates can be performed
without applying offsets. Accessing the fields of the object requires
offsets anyway, but these can be adjusted at compile-time without any
loss. Following this strategy will lead to the same problem of marking
a wrong cell during the conservative stack scan, leading to premature
collection.

The problem is avoided by not using `usrToCell` in `gcMark`. Since
the cell discovery logic can already handle interior pointers, the
user pointers don't need to be adjusted for the GC to function correctly.

(cherry picked from commit 3b47a689cf)
2021-04-14 12:10:29 +02:00
narimiran
ab1ae92587 bump NimVersion to 1.4.6 2021-04-13 21:51:50 +02:00
narimiran
5dd88ca1a4 [ci skip] minor: fix indentation in manual.rst
(cherry picked from commit d3529d0d5a)
2021-03-31 13:42:11 +02:00
Miran
598d9f8402 [backport:1.2] Avoid inlining of newObj and newObjRC1 calls (#17582)
This is taken from:
af69b3ceae

Full original comment:

This is to avoid heavy inlining happening when two allocation calls
would occur shortly after each other.

This inlining would sometimes be accompanied with an optimisation
as the compiler is able to see that cellToUsr ending the first
allocation call is shortly followed by an usrToCell call. The
pointer arithmetic is redundant and the compiler can eliminate it,
leaving only the cell address in a register (and later the stack)
instead of the actual pointer to the user data, as one would expect.

This combined with a GC collect cycle will cause the stack scan to
only notice the cell address, which is of no good due to a usrToCell
in the gcMark call which shifts that address to an adjacent cell.
This means that the actual cell of importance will not get marked
and thus cause a premature collection of that cell. BOOM.

(cherry picked from commit 40093b4a93)
2021-03-30 11:47:28 +02:00
Danil Yarantsev
f7f7a02915 Free the certificate after checking in checkCertName (#17558) [backport:1.2]
* Fix small leak in checkCertName
* Size is not needed either
* Free the certificate after checking

(cherry picked from commit b36182b0a4)
2021-03-29 15:31:30 +02:00
Timothee Cour
28b301cbaa fix #17454 (#17461)
(cherry picked from commit d78ebe4a0e)
2021-03-29 15:27:09 +02:00
narimiran
69c2c05463 bump NimVersion to 1.4.5 2021-03-26 09:02:30 +01:00
Andreas Rumpf
cc6bc8960d closes #17085; boehm has problems with large allocations, that is expected and we don't care (#17487)
(cherry picked from commit 8ccde68f13)
2021-03-24 18:20:19 +01:00
narimiran
05991805fb change back part of the test 2021-03-24 18:19:42 +01:00
narimiran
82561f31eb backport json-related part of #17469 2021-03-24 17:48:39 +01:00
Timothee Cour
e5027dc3da fix #17383: json.%,to and jsonutils.formJson,toJson now works with uint|uint64 (#17389) [backport:1.2]
* fix #17383: json.%,to and jsonutils.formJson,toJson now works with uint|uint64
* fixup
* fix for js

(cherry picked from commit 895a40d1ac)
2021-03-19 15:49:56 +01:00
Igor Ribeiro de Assis
f97d840f96 Fix FutureStream memory usage (#17395) [backport:1.2]
(cherry picked from commit 9bb0e55749)
2021-03-18 17:23:06 +01:00
xioren
560800246e Relocate 4xx/5xx exception in downloadFile (#17332) [backport:1.2]
Move 4xx/5xx exception to before disk i/o. As it stands an empty file is created on http error 4xx/5xx.

(cherry picked from commit 3d198fdcc2)
2021-03-18 14:08:54 +01:00
Andreas Rumpf
cf1ecee794 fixes #11225; generic sandwich problems; [backport:1.2] (#17255)
* fixes #11225; generic sandwich problems; [backport:1.2]
* progress
* delegating these symbols must be done via 'bind'

(cherry picked from commit 2f213db7ee)
2021-03-18 14:08:54 +01:00
flywind
6b00463074 Add unsafeIsolate and extract to std/isolation [backport:1.4] (#17263)
(cherry picked from commit 19be5eb1eb)
2021-03-18 14:08:54 +01:00
flywind
e996d98a8a fix #16384 and #17144 (#17126) [backport]
(cherry picked from commit 6391f6e861)
2021-03-18 14:08:54 +01:00
flywind
5c88067953 fix #17264 [backport:1.4] (#17266)
* fix #17264
* fix vm
* fix js and add tests

(cherry picked from commit 171b03c386)
2021-03-18 13:13:51 +01:00
alaviss
061d106671 compiler/installer.ini: package cacert.pem on Windows [backport:1.2] (#17172)
Follow up of 5dc544e1f5

After updating windeps.zip, it appears that Windows' build was
unchanged. As it turns out, cacert.pem is not set for packaging by the
compiler package manifest.

This commit add cacert.pem to the Windows package.

(cherry picked from commit d35f366d6f)
2021-03-18 08:33:16 +01:00
Andreas Rumpf
c2e2f50d35 fixes yet another SSL problem on Windows [backport:1.2] (#17167)
(cherry picked from commit b48a32053f)
2021-03-18 08:32:40 +01:00
43 changed files with 332 additions and 109 deletions

View File

@@ -44,5 +44,7 @@
- Added `unsafeIsolate` and `extract` to `std/isolation`.
## Tool changes

View File

@@ -2307,7 +2307,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mCharToStr: genDollar(p, e, d, "#nimCharToStr($1)")
of mFloatToStr: genDollar(p, e, d, "#nimFloatToStr($1)")
of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)")
of mStrToStr, mUnown, mIsolate: expr(p, e[1], d)
of mStrToStr, mUnown: expr(p, e[1], d)
of mIsolate: genCall(p, e, d)
of mEnumToStr:
if optTinyRtti in p.config.globalOptions:
genEnumToStr(p, e, d)
@@ -2851,6 +2852,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
inc p.splitDecls
genGotoState(p, n)
of nkBreakState: genBreakState(p, n, d)
of nkMixinStmt, nkBindStmt: discard
else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind")
proc genNamedConstExpr(p: BProc, n: PNode; isConst: bool): Rope =

View File

@@ -855,7 +855,8 @@ proc containsResult(n: PNode): bool =
for i in 0..<n.safeLen:
if containsResult(n[i]): return true
const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef, nkMacroDef} +
const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef,
nkMacroDef, nkMixinStmt, nkBindStmt} +
declarativeDefs
proc easyResultAsgn(n: PNode): PNode =

View File

@@ -156,7 +156,7 @@ type
const
nkSkip = {nkEmpty..nkNilLit, nkTemplateDef, nkTypeSection, nkStaticStmt,
nkCommentStmt} + procDefs
nkCommentStmt, nkMixinStmt, nkBindStmt} + procDefs
proc newStateAccess(ctx: var Ctx): PNode =
if ctx.stateVarSym.isNil:

View File

@@ -843,7 +843,8 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode): PNode =
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr:
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
result = n
of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange, nkPragmaBlock:

View File

@@ -110,6 +110,7 @@ Download: r"Aporia Text Editor|dist|aporia.zip|97997|https://nim-lang.org/downlo
Files: "bin/makelink.exe"
Files: "bin/7zG.exe"
Files: "bin/*.dll"
Files: "bin/cacert.pem"
[UnixBin]
Files: "bin/nim"

View File

@@ -1427,7 +1427,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
s.name.s)
discard mangleName(p.module, s)
r.res = s.loc.r
if lfNoDecl in s.loc.flags or s.magic != mNone or
if lfNoDecl in s.loc.flags or s.magic notin {mNone, mIsolate} or
{sfImportc, sfInfixCall} * s.flags != {}:
discard
elif s.kind == skMethod and s.getBody.kind == nkEmpty:
@@ -2551,7 +2551,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
let s = n[namePos].sym
discard mangleName(p.module, s)
r.res = s.loc.r
if lfNoDecl in s.loc.flags or s.magic != mNone: discard
if lfNoDecl in s.loc.flags or s.magic notin {mNone, mIsolate}: discard
elif not p.g.generatedSyms.containsOrIncl(s.id):
p.locals.add(genProc(p, s))
of nkType: r.res = genTypeInfo(p, n.typ)
@@ -2588,7 +2588,8 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkRaiseStmt: genRaiseStmt(p, n)
of nkTypeSection, nkCommentStmt, nkIncludeStmt,
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt: discard
nkFromStmt, nkTemplateDef, nkMacroDef, nkStaticStmt,
nkMixinStmt, nkBindStmt: discard
of nkIteratorDef:
if n[0].sym.typ.callConv == TCallingConvention.ccClosure:
globalError(p.config, n.info, "Closure iterators are not supported by JS backend!")

View File

@@ -495,7 +495,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
w = up
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit,
nkTemplateDef, nkTypeSection, nkProcDef, nkMethodDef,
nkConverterDef, nkMacroDef, nkFuncDef, nkCommentStmt, nkTypeOfExpr:
nkConverterDef, nkMacroDef, nkFuncDef, nkCommentStmt,
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
discard
of nkLambdaKinds, nkIteratorDef:
if n.typ != nil:
@@ -750,7 +751,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
result = accessViaEnvVar(n, owner, d, c)
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom,
nkTemplateDef, nkTypeSection, nkProcDef, nkMethodDef, nkConverterDef,
nkMacroDef, nkFuncDef:
nkMacroDef, nkFuncDef, nkMixinStmt, nkBindStmt:
discard
of nkClosure:
if n[1].kind == nkNilLit:

View File

@@ -42,7 +42,7 @@ proc liftLocals(n: PNode; i: int; c: var Ctx) =
of nkSym:
if interestingVar(it.sym):
n[i] = lookupOrAdd(c, it.sym, it.info)
of procDefs, nkTypeSection: discard
of procDefs, nkTypeSection, nkMixinStmt, nkBindStmt: discard
else:
for i in 0..<it.safeLen:
liftLocals(it, i, c)

View File

@@ -150,7 +150,8 @@ proc analyse(c: var Con; b: var BasicBlock; n: PNode) =
of nkNone..pred(nkSym), succ(nkSym)..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr:
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
nkTypeOfExpr, nkMixinStmt, nkBindStmt:
discard "do not follow the construct"
of nkAsgn, nkFastAsgn:
@@ -249,7 +250,8 @@ proc opt(c: Con; n, parent: PNode; parentPos: int) =
of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef,
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr:
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr,
nkMixinStmt, nkBindStmt:
parent[parentPos] = n
else:

View File

@@ -105,6 +105,7 @@ proc computeDeps(cache: IdentCache; n: PNode, declares, uses: var IntSet; topLev
decl(a[1])
else:
for i in 0..<n.safeLen: deps(n[i])
of nkMixinStmt, nkBindStmt: discard
else:
for i in 0..<n.safeLen: deps(n[i])

View File

@@ -38,6 +38,7 @@ type
mappingExists*: bool
mapping*: TIdTable
caseContext*: seq[tuple[n: PNode, idx: int]]
localBindStmts*: seq[PNode]
TMatchedConcept* = object
candidateType*: PType

View File

@@ -2901,6 +2901,13 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
for i in 0..<n.len:
n[i] = semExpr(c, n[i])
of nkComesFrom: discard "ignore the comes from information for now"
of nkMixinStmt: discard
of nkBindStmt:
if c.p != nil:
c.p.localBindStmts.add n
else:
localError(c.config, n.info, "invalid context for 'bind' statement: " &
renderTree(n, {renderNoComments}))
else:
localError(c.config, n.info, "invalid expression: " &
renderTree(n, {renderNoComments}))

View File

@@ -319,6 +319,14 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
prc.typ = result
popInfoContext(c.config)
proc fillMixinScope(c: PContext) =
var p = c.p
while p != nil:
for bnd in p.localBindStmts:
for n in bnd:
addSym(c.currentScope, n.sym)
p = p.next
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym {.nosinks.} =
## Generates a new instance of a generic procedure.
@@ -345,6 +353,10 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
result.ast = n
pushOwner(c, result)
# mixin scope:
openScope(c)
fillMixinScope(c)
openScope(c)
let gp = n[genericParamsPos]
internalAssert c.config, gp.kind != nkEmpty
@@ -395,6 +407,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
popProcCon(c)
popInfoContext(c.config)
closeScope(c) # close scope for parameters
closeScope(c) # close scope for 'mixin' declarations
popOwner(c)
c.currentScope = oldScope
discard c.friendModules.pop()

View File

@@ -391,7 +391,8 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
addFactNeg(c.guards, canon(n[0], c.guards.o))
dec c.inLoop
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef:
nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef,
nkMixinStmt, nkBindStmt, nkExportStmt:
discard
else:
analyseSons(c, n)

View File

@@ -1822,8 +1822,8 @@ proc semMethodPrototype(c: PContext; s: PSym; n: PNode) =
let t = tt[col]
if t != nil and t.kind == tyGenericInvocation:
var x = skipTypes(t[0], {tyVar, tyLent, tyPtr, tyRef, tyGenericInst,
tyGenericInvocation, tyGenericBody,
tyAlias, tySink, tyOwned})
tyGenericInvocation, tyGenericBody,
tyAlias, tySink, tyOwned})
if x.kind == tyObject and t.len-1 == n[genericParamsPos].len:
foundObj = true
x.methods.add((col,s))

View File

@@ -86,6 +86,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule;
a = nextOverloadIter(o, c, n)
proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
result = copyNode(n)
for i in 0..<n.len:
var a = n[i]
# If 'a' is an overloaded symbol, we used to use the first symbol
@@ -99,16 +100,19 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
let sc = symChoice(c, n, s, scClosed)
if sc.kind == nkSym:
toBind.incl(sc.sym.id)
result.add sc
else:
for x in items(sc): toBind.incl(x.sym.id)
for x in items(sc):
toBind.incl(x.sym.id)
result.add x
else:
illFormedAst(a, c.config)
result = newNodeI(nkEmpty, n.info)
proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
result = copyNode(n)
for i in 0..<n.len:
toMixin.incl(considerQuotedIdent(c, n[i]).id)
result = newNodeI(nkEmpty, n.info)
result.add symChoice(c, n[i], nil, scForceOpen)
proc replaceIdentBySym(c: PContext; n: var PNode, s: PNode) =
case n.kind

View File

@@ -966,7 +966,7 @@ proc transform(c: PTransf, n: PNode): PNode =
of nkConstSection:
# do not replace ``const c = 3`` with ``const 3 = 3``
return transformConstSection(c, n)
of nkTypeSection, nkTypeOfExpr:
of nkTypeSection, nkTypeOfExpr, nkMixinStmt, nkBindStmt:
# no need to transform type sections:
return n
of nkVarSection, nkLetSection:

View File

@@ -631,7 +631,8 @@ const
nkTypeSection, nkProcDef, nkConverterDef,
nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo,
nkFuncDef, nkConstSection, nkConstDef, nkIncludeStmt, nkImportStmt,
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState, nkTypeOfExpr}
nkExportStmt, nkPragma, nkCommentStmt, nkBreakState,
nkTypeOfExpr, nkMixinStmt, nkBindStmt}
proc potentialMutationViaArg(c: var Partitions; n: PNode; callee: PType) =
if constParameters in c.goals and tfNoSideEffect in callee.flags:

View File

@@ -995,7 +995,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let nc = regs[rc].node
if nb.kind != nc.kind: discard
elif (nb == nc) or (nb.kind == nkNilLit): ret = true # intentional
elif sameConstant(nb, nc): ret = true
elif (nb.kind in {nkSym, nkTupleConstr, nkClosure} and nb.typ.kind == tyProc) and sameConstant(nb, nc):
ret = true
# this also takes care of procvar's, represented as nkTupleConstr, e.g. (nil, nil)
elif nb.kind == nkIntLit and nc.kind == nkIntLit and nb.intVal == nc.intVal: # TODO: nkPtrLit
let tb = nb.getTyp

View File

@@ -1003,7 +1003,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.genNarrow(n[1], d)
c.genAsgnPatch(n[1], d)
c.freeTemp(d)
of mOrd, mChr, mArrToSeq, mUnown, mIsolate: c.gen(n[1], dest)
of mOrd, mChr, mArrToSeq, mUnown: c.gen(n[1], dest)
of mIsolate:
genCall(c, n, dest)
of mNew, mNewFinalize:
unused(c, n, dest)
c.genNew(n)
@@ -2101,7 +2103,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
else:
dest = tmp0
of nkEmpty, nkCommentStmt, nkTypeSection, nkConstSection, nkPragma,
nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt, nkExportStmt:
nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt, nkExportStmt,
nkMixinStmt, nkBindStmt:
unused(c, n, dest)
of nkStringToCString, nkCStringToString:
gen(c, n[0], dest)

View File

@@ -5029,6 +5029,50 @@ scope is the default.
``bind`` statements only make sense in templates and generics.
Delegating bind statements
--------------------------
The following example outlines a problem that can arise when generic
instantiations cross multiple different modules:
.. code-block:: nim
# module A
proc genericA*[T](x: T) =
mixin init
init(x)
.. code-block:: nim
import C
# module B
proc genericB*[T](x: T) =
# Without the `bind init` statement C's init proc is
# not available when `genericB` is instantiated:
bind init
genericA(x)
.. code-block:: nim
# module C
type O = object
proc init*(x: var O) = discard
.. code-block:: nim
# module main
import B, C
genericB O()
In module B has an `init` proc from module C in its scope that is not
taken into account when `genericB` is instantiated which leads to the
instantiation of `genericA`. The solution is to `forward`:idx these
symbols by a `bind` statement inside `genericB`.
Templates
=========
@@ -5940,12 +5984,12 @@ avoid ambiguity when there are multiple modules with the same path.
There are two pseudo directories:
1. ``std``: The ``std`` pseudo directory is the abstract location of Nim's standard
library. For example, the syntax ``import std / strutils`` is used to unambiguously
refer to the standard library's ``strutils`` module.
library. For example, the syntax ``import std / strutils`` is used to unambiguously
refer to the standard library's ``strutils`` module.
2. ``pkg``: The ``pkg`` pseudo directory is used to unambiguously refer to a Nimble
package. However, for technical details that lie outside of the scope of this document
its semantics are: *Use the search path to look for module name but ignore the standard
library locations*. In other words, it is the opposite of ``std``.
package. However, for technical details that lie outside of the scope of this document
its semantics are: *Use the search path to look for module name but ignore the standard
library locations*. In other words, it is the opposite of ``std``.
From import statement

View File

@@ -1256,7 +1256,15 @@ proc `body=`*(someProc: NimNode, val: NimNode) {.compileTime.} =
else:
badNodeKind someProc, "body="
proc basename*(a: NimNode): NimNode {.compileTime, benign.}
proc basename*(a: NimNode): NimNode {.raises: [].} =
## Pull an identifier from prefix/postfix expressions.
case a.kind
of nnkIdent: result = a
of nnkPostfix, nnkPrefix: result = a[1]
of nnkPragmaExpr: result = basename(a[0])
else:
error("Do not know how to get basename of (" & treeRepr(a) & ")\n" &
repr(a), a)
proc `$`*(node: NimNode): string {.compileTime.} =
## Get the string of an identifier node.
@@ -1316,16 +1324,6 @@ proc insert*(a: NimNode; pos: int; b: NimNode) {.compileTime.} =
a[i + 1] = a[i]
a[pos] = b
proc basename*(a: NimNode): NimNode =
## Pull an identifier from prefix/postfix expressions.
case a.kind
of nnkIdent: result = a
of nnkPostfix, nnkPrefix: result = a[1]
of nnkPragmaExpr: result = basename(a[0])
else:
error("Do not know how to get basename of (" & treeRepr(a) & ")\n" &
repr(a), a)
proc `basename=`*(a: NimNode; val: string) {.compileTime.}=
case a.kind
of nnkIdent:

View File

@@ -110,7 +110,11 @@ proc read*[T](future: FutureStream[T]): owned(Future[(bool, T)]) =
resFut.complete(res)
# If the saved callback isn't nil then let's call it.
if not savedCb.isNil: savedCb()
if not savedCb.isNil:
if fs.queue.len > 0:
savedCb()
else:
future.cb = savedCb
if future.queue.len > 0 or future.finished:
newCb(future)

View File

@@ -1155,15 +1155,15 @@ proc downloadFile*(client: HttpClient, url: string, filename: string) =
client.getBody = true
let resp = client.get(url)
if resp.code.is4xx or resp.code.is5xx:
raise newException(HttpRequestError, resp.status)
client.bodyStream = newFileStream(filename, fmWrite)
if client.bodyStream.isNil:
fileError("Unable to open file")
parseBody(client, resp.headers, resp.version)
client.bodyStream.close()
if resp.code.is4xx or resp.code.is5xx:
raise newException(HttpRequestError, resp.status)
proc downloadFile*(client: AsyncHttpClient, url: string,
filename: string): Future[void] =
proc downloadFileEx(client: AsyncHttpClient,

View File

@@ -304,7 +304,10 @@ proc `%`*(s: string): JsonNode =
proc `%`*(n: uint): JsonNode =
## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
result = JsonNode(kind: JInt, num: BiggestInt(n))
if n > cast[uint](int.high):
result = newJRawNumber($n)
else:
result = JsonNode(kind: JInt, num: BiggestInt(n))
proc `%`*(n: int): JsonNode =
## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
@@ -312,7 +315,10 @@ proc `%`*(n: int): JsonNode =
proc `%`*(n: BiggestUInt): JsonNode =
## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
result = JsonNode(kind: JInt, num: BiggestInt(n))
if n > cast[BiggestUInt](BiggestInt.high):
result = newJRawNumber($n)
else:
result = JsonNode(kind: JInt, num: BiggestInt(n))
proc `%`*(n: BiggestInt): JsonNode =
## Generic constructor for JSON data. Creates a new `JInt JsonNode`.
@@ -1058,8 +1064,17 @@ when defined(nimFixedForwardGeneric):
dst = jsonNode.copy
proc initFromJson[T: SomeInteger](dst: var T; jsonNode: JsonNode, jsonPath: var string) =
verifyJsonKind(jsonNode, {JInt}, jsonPath)
dst = T(jsonNode.num)
when T is uint|uint64 or (not defined(js) and int.sizeof == 4):
verifyJsonKind(jsonNode, {JInt, JString}, jsonPath)
case jsonNode.kind
of JString:
let x = parseBiggestUInt(jsonNode.str)
dst = cast[T](x)
else:
dst = T(jsonNode.num)
else:
verifyJsonKind(jsonNode, {JInt}, jsonPath)
dst = cast[T](jsonNode.num)
proc initFromJson[T: SomeFloat](dst: var T; jsonNode: JsonNode; jsonPath: var string) =
verifyJsonKind(jsonNode, {JInt, JFloat}, jsonPath)

View File

@@ -622,7 +622,7 @@ when defineSsl:
if newCTX.SSL_CTX_set_ecdh_auto(1) != 1:
raiseSSLError()
when defined(nimDisableCertificateValidation) or defined(windows):
when defined(nimDisableCertificateValidation):
newCTX.SSL_CTX_set_verify(SSL_VERIFY_NONE, nil)
else:
case verifyMode
@@ -769,10 +769,11 @@ when defineSsl:
raiseSSLError("No SSL certificate found.")
const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT = 0x1.cuint
const size = 1024
var peername: string = newString(size)
# https://www.openssl.org/docs/man1.1.1/man3/X509_check_host.html
let match = certificate.X509_check_host(hostname.cstring, hostname.len.cint,
X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT, peername)
X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT, nil)
# https://www.openssl.org/docs/man1.1.1/man3/SSL_get_peer_certificate.html
X509_free(certificate)
if match != 1:
raiseSSLError("SSL Certificate check failed.")

View File

@@ -25,7 +25,16 @@ proc `=destroy`*[T](dest: var Isolated[T]) {.inline.} =
# delegate to value's destroy operation
`=destroy`(dest.value)
func isolate*[T](value: sink T): Isolated[T] {.magic: "Isolate".}
func isolate*[T](value: sink T): Isolated[T] {.magic: "Isolate".} =
## Create an isolated subgraph from the expression `value`.
## Please read https://github.com/nim-lang/RFCs/issues/244
## for more details.
Isolated[T](value: value)
func unsafeIsolate*[T](value: sink T): Isolated[T] =
## Creates an isolated subgraph from the expression `value`.
Isolated[T](value: value)
func extract*[T](src: var Isolated[T]): T =
## Returns the internal value of `src`.
result = move(src.value)

View File

@@ -187,7 +187,8 @@ proc fromJson*[T](a: var T, b: JsonNode, opt = Joptions()) =
of JInt: a = T(b.getBiggestInt())
of JString: a = parseEnum[T](b.getStr())
else: checkJson false, $($T, " ", b)
elif T is Ordinal: a = T(to(b, int))
elif T is uint|uint64: a = T(to(b, uint64))
elif T is Ordinal: a = cast[T](to(b, int))
elif T is pointer: a = cast[pointer](to(b, int))
elif T is distinct:
when nimvm:
@@ -270,6 +271,7 @@ proc toJson*[T](a: T): JsonNode =
# in simpler code for `toJson` and `fromJson`.
elif T is distinct: result = toJson(a.distinctBase)
elif T is bool: result = %(a)
elif T is SomeInteger: result = %a
elif T is Ordinal: result = %(a.ord)
else: result = %a

View File

@@ -2121,7 +2121,7 @@ const
## is the minor number of Nim's version.
## Odd for devel, even for releases.
NimPatch* {.intdefine.}: int = 4
NimPatch* {.intdefine.}: int = 6
## is the patch number of Nim's version.
## Odd for devel, even for releases.

View File

@@ -435,7 +435,7 @@ proc newObjNoInit(typ: PNimType, size: int): pointer {.compilerRtl.} =
result = rawNewObj(typ, size, gch)
when defined(memProfiler): nimProfile(size)
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} =
result = rawNewObj(typ, size, gch)
zeroMem(result, size)
when defined(memProfiler): nimProfile(size)
@@ -450,7 +450,7 @@ proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
when defined(memProfiler): nimProfile(size)
{.pop.}
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl, noinline.} =
# generates a new object and sets its reference counter to 1
incTypeSize typ, size
sysAssert(allocInv(gch.region), "newObjRC1 begin")
@@ -663,16 +663,16 @@ proc collectCycles(gch: var GcHeap) =
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
# the addresses are not as cells on the stack, so turn them to cells:
sysAssert(allocInv(gch.region), "gcMark begin")
var cell = usrToCell(p)
var c = cast[ByteAddress](cell)
var c = cast[ByteAddress](p)
if c >% PageSize:
# fast check: does it look like a cell?
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, p))
if objStart != nil:
# mark the cell:
incRef(objStart)
add(gch.decStack, objStart)
when false:
let cell = usrToCell(p)
if isAllocatedPtr(gch.region, cell):
sysAssert false, "allocated pointer but not interior?"
# mark the cell:

View File

@@ -455,11 +455,10 @@ proc markGlobals(gch: var GcHeap) =
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
# the addresses are not as cells on the stack, so turn them to cells:
var cell = usrToCell(p)
var c = cast[ByteAddress](cell)
var c = cast[ByteAddress](p)
if c >% PageSize:
# fast check: does it look like a cell?
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
var objStart = cast[PCell](interiorAllocatedPtr(gch.region, p))
if objStart != nil:
mark(gch, objStart)

View File

@@ -809,6 +809,8 @@ when not defined(nimDisableCertificateValidation) and not defined(windows):
proc X509_check_host*(cert: PX509, name: cstring, namelen: cint, flags:cuint, peername: cstring): cint {.cdecl, dynlib: DLLSSLName, importc.}
proc X509_free*(cert: PX509) {.cdecl, dynlib: DLLSSLName, importc.}
# Certificates store
type PX509_STORE* = SslPtr

View File

@@ -216,7 +216,7 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
test "stackrefleak"
test "cyclecollector"
test "trace_globals"
testWithoutBoehm "trace_globals"
proc longGCTests(r: var TResults, cat: Category, options: string) =
when defined(windows):

View File

@@ -0,0 +1,6 @@
proc libraryFunc*[T](x: T) =
mixin mixedIn, indirectlyMixedIn
echo mixedIn()
echo indirectlyMixedIn()

View File

@@ -0,0 +1,3 @@
proc indirectlyMixedIn*: int =
200

View File

@@ -0,0 +1,12 @@
import
generic_library, helper_module
proc mixedIn: int = 100
proc makeUseOfLibrary*[T](x: T) =
bind mixedIn, indirectlyMixedIn
libraryFunc(x)
when isMainModule:
makeUseOfLibrary "test"

9
tests/sandwich/tmain.nim Normal file
View File

@@ -0,0 +1,9 @@
discard """
output: '''100
200'''
"""
import
module_using_generic_library
makeUseOfLibrary "test"

View File

@@ -0,0 +1,16 @@
discard """
targets: "c cpp js"
"""
import std/[json, isolation]
proc main() =
var x: seq[Isolated[JsonNode]]
x.add isolate(newJString("1234"))
doAssert $x == """@[(value: "1234")]"""
static: main()
main()

View File

@@ -2,7 +2,14 @@
Note: Macro tests are in tests/stdlib/tjsonmacro.nim
]#
import std/[json,parsejson,strutils,streams]
import std/[json,parsejson,strutils]
when not defined(js):
import std/streams
proc testRoundtrip[T](t: T, expected: string) =
let j = %t
doAssert $j == expected, $j
doAssert %(j.to(T)) == j
let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd", "c": "\ud83c\udf83", "d": "\u00E6"}"""
# nil passthrough
@@ -235,3 +242,16 @@ doAssert isRefSkipDistinct(MyOtherDistinct)
let x = parseJson("9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999")
doAssert x.kind == JString
block: # bug #17383
testRoundtrip(int32.high): "2147483647"
testRoundtrip(uint32.high): "4294967295"
when int.sizeof == 4:
testRoundtrip(int.high): "2147483647"
testRoundtrip(uint.high): "4294967295"
else:
testRoundtrip(int.high): "9223372036854775807"
testRoundtrip(uint.high): "18446744073709551615"
when not defined(js):
testRoundtrip(int64.high): "9223372036854775807"
testRoundtrip(uint64.high): "18446744073709551615"

View File

@@ -68,6 +68,21 @@ template fn() =
doAssert b2.ord == 1 # explains the `1`
testRoundtrip(a): """[1,2,3]"""
block: # bug #17383
block:
let a = (int32.high, uint32.high)
testRoundtrip(a): "[2147483647,4294967295]"
when int.sizeof > 4:
block:
let a = (int64.high, uint64.high)
testRoundtrip(a): "[9223372036854775807,18446744073709551615]"
block:
let a = (int.high, uint.high)
when int.sizeof == 4:
testRoundtrip(a): "[2147483647,4294967295]"
else:
testRoundtrip(a): "[9223372036854775807,18446744073709551615]"
block: # case object
type Foo = object
x0: float

View File

@@ -1,67 +1,88 @@
discard """
output: '''true'''
targets: "c js"
"""
import lists
import std/[lists, sequtils]
const
data = [1, 2, 3, 4, 5, 6]
block SinglyLinkedListTest1:
var L: SinglyLinkedList[int]
for d in items(data): L.prepend(d)
for d in items(data): L.append(d)
assert($L == "[6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6]")
assert(4 in L)
template main =
block SinglyLinkedListTest1:
var L: SinglyLinkedList[int]
for d in items(data): L.prepend(d)
for d in items(data): L.append(d)
doAssert($L == "[6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6]")
block SinglyLinkedListTest2:
var L: SinglyLinkedList[string]
for d in items(data): L.prepend($d)
assert($L == """["6", "5", "4", "3", "2", "1"]""")
doAssert(4 in L)
assert("4" in L)
block SinglyLinkedListTest2:
var L: SinglyLinkedList[string]
for d in items(data): L.prepend($d)
doAssert($L == """["6", "5", "4", "3", "2", "1"]""")
doAssert("4" in L)
block DoublyLinkedListTest1:
var L: DoublyLinkedList[int]
for d in items(data): L.prepend(d)
for d in items(data): L.append(d)
L.remove(L.find(1))
assert($L == "[6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6]")
block DoublyLinkedListTest1:
var L: DoublyLinkedList[int]
for d in items(data): L.prepend(d)
for d in items(data): L.append(d)
L.remove(L.find(1))
doAssert($L == "[6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6]")
assert(4 in L)
doAssert(4 in L)
block SinglyLinkedRingTest1:
var L: SinglyLinkedRing[int]
L.prepend(4)
assert($L == "[4]")
L.prepend(4)
block SinglyLinkedRingTest1:
var L: SinglyLinkedRing[int]
L.prepend(4)
doAssert($L == "[4]")
L.prepend(4)
assert($L == "[4, 4]")
assert(4 in L)
doAssert($L == "[4, 4]")
doAssert(4 in L)
block DoublyLinkedRingTest1:
var L: DoublyLinkedRing[int]
L.prepend(4)
assert($L == "[4]")
L.prepend(4)
block DoublyLinkedRingTest1:
var L: DoublyLinkedRing[int]
L.prepend(4)
doAssert($L == "[4]")
L.prepend(4)
assert($L == "[4, 4]")
assert(4 in L)
doAssert($L == "[4, 4]")
doAssert(4 in L)
L.append(3)
L.append(5)
assert($L == "[4, 4, 3, 5]")
L.append(3)
L.append(5)
doAssert($L == "[4, 4, 3, 5]")
L.remove(L.find(3))
L.remove(L.find(5))
L.remove(L.find(4))
L.remove(L.find(4))
assert($L == "[]")
assert(4 notin L)
L.remove(L.find(3))
L.remove(L.find(5))
L.remove(L.find(4))
L.remove(L.find(4))
doAssert($L == "[]")
doAssert(4 notin L)
block tlistsToString:
block:
var l = initDoublyLinkedList[int]()
l.append(1)
l.append(2)
l.append(3)
doAssert $l == "[1, 2, 3]"
block:
var l = initDoublyLinkedList[string]()
l.append("1")
l.append("2")
l.append("3")
doAssert $l == """["1", "2", "3"]"""
block:
var l = initDoublyLinkedList[char]()
l.append('1')
l.append('2')
l.append('3')
doAssert $l == """['1', '2', '3']"""
echo "true"
static: main()
main()

4
tests/stdlib/tmacros.nim Normal file
View File

@@ -0,0 +1,4 @@
import macros
block: # bug #17454
proc f(v: NimNode): string {.raises: [].} = $v