mirror of
https://github.com/nim-lang/Nim.git
synced 2026-09-01 11:23:40 +00:00
Compare commits
1 Commits
pr_copy_23
...
pr_recursi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f75bf972a5 |
@@ -17,8 +17,6 @@
|
||||
|
||||
- `bindMethod` in `std/jsffi` is deprecated, don't use it with closures.
|
||||
|
||||
- JS backend now supports lambda lifting for closures. Use `--legacy:jsNoLambdaLifting` to emulate old behavior.
|
||||
|
||||
## Standard library additions and changes
|
||||
|
||||
[//]: # "Changes:"
|
||||
@@ -39,9 +37,6 @@ slots when enlarging a sequence.
|
||||
objects the cyclic collector did free. If the number is zero that is a strong indicator that you can use `--mm:arc`
|
||||
instead of `--mm:orc`.
|
||||
- A `$` template is provided for `Path` in `std/paths`.
|
||||
- `nimPreviewHashFarm` has been added to `lib/pure/hashes.nim` to default to a
|
||||
64-bit string `Hash` (based upon Google's Farm Hash) which is also faster than
|
||||
the present one. At present, this is incompatible with `--jsbigint=off` mode.
|
||||
|
||||
[//]: # "Deprecations:"
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ type
|
||||
TNodeKinds* = set[TNodeKind]
|
||||
|
||||
type
|
||||
TSymFlag* = enum # 52 flags!
|
||||
TSymFlag* = enum # 51 flags!
|
||||
sfUsed, # read access of sym (for warnings) or simply used
|
||||
sfExported, # symbol is exported from module
|
||||
sfFromGeneric, # symbol is instantiation of a generic; this is needed
|
||||
@@ -126,7 +126,6 @@ type
|
||||
sfByCopy # param is marked as pass bycopy
|
||||
sfMember # proc is a C++ member of a type
|
||||
sfCodegenDecl # type, proc, global or proc param is marked as codegenDecl
|
||||
sfWasGenSym # symbol was 'gensym'ed
|
||||
|
||||
TSymFlags* = set[TSymFlag]
|
||||
|
||||
@@ -332,7 +331,7 @@ type
|
||||
nfOpenSym # node is a captured sym but can be overriden by local symbols
|
||||
|
||||
TNodeFlags* = set[TNodeFlag]
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 47)
|
||||
TTypeFlag* = enum # keep below 32 for efficiency reasons (now: 48)
|
||||
tfVarargs, # procedure has C styled varargs
|
||||
# tyArray type represeting a varargs list
|
||||
tfNoSideEffect, # procedure type does not allow side effects
|
||||
@@ -404,6 +403,7 @@ type
|
||||
tfIsOutParam
|
||||
tfSendable
|
||||
tfImplicitStatic
|
||||
tfTrackedProc # used for delayedEffects
|
||||
|
||||
TTypeFlags* = set[TTypeFlag]
|
||||
|
||||
|
||||
@@ -76,23 +76,6 @@ proc isHarmlessStore(p: BProc; canRaise: bool; d: TLoc): bool =
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc cleanupTemp(p: BProc; returnType: PType, tmp: TLoc): bool =
|
||||
if returnType.kind in {tyVar, tyLent}:
|
||||
# we don't need to worry about var/lent return types
|
||||
result = false
|
||||
elif hasDestructor(returnType) and getAttachedOp(p.module.g.graph, returnType, attachedDestructor) != nil:
|
||||
let dtor = getAttachedOp(p.module.g.graph, returnType, attachedDestructor)
|
||||
var op = initLocExpr(p, newSymNode(dtor))
|
||||
var callee = rdLoc(op)
|
||||
let destroy = if dtor.typ.firstParamType.kind == tyVar:
|
||||
callee & "(&" & rdLoc(tmp) & ")"
|
||||
else:
|
||||
callee & "(" & rdLoc(tmp) & ")"
|
||||
raiseExitCleanup(p, destroy)
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
callee, params: Rope) =
|
||||
let canRaise = p.config.exc == excGoto and canRaiseDisp(p, ri[0])
|
||||
@@ -145,25 +128,18 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
if canRaise: raiseExit(p)
|
||||
|
||||
elif isHarmlessStore(p, canRaise, d):
|
||||
var useTemp = false
|
||||
if d.k == locNone:
|
||||
useTemp = true
|
||||
d = getTemp(p, typ.returnType)
|
||||
if d.k == locNone: d = getTemp(p, typ.returnType)
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.r = pl
|
||||
genAssignment(p, d, list, flags) # no need for deep copying
|
||||
if canRaise:
|
||||
if not (useTemp and cleanupTemp(p, typ.returnType, d)):
|
||||
raiseExit(p)
|
||||
if canRaise: raiseExit(p)
|
||||
else:
|
||||
var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
|
||||
var list = initLoc(locCall, d.lode, OnUnknown)
|
||||
list.r = pl
|
||||
genAssignment(p, tmp, list, flags) # no need for deep copying
|
||||
if canRaise:
|
||||
if not cleanupTemp(p, typ.returnType, tmp):
|
||||
raiseExit(p)
|
||||
if canRaise: raiseExit(p)
|
||||
genAssignment(p, d, tmp, {})
|
||||
else:
|
||||
pl.add(");\n")
|
||||
|
||||
@@ -3239,8 +3239,7 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
|
||||
getNullValueAux(p, t, it, constOrNil, result, count, isConst, info)
|
||||
of nkRecCase:
|
||||
getNullValueAux(p, t, obj[0], constOrNil, result, count, isConst, info)
|
||||
var res = ""
|
||||
if count > 0: res.add ", "
|
||||
if count > 0: result.add ", "
|
||||
var branch = Zero
|
||||
if constOrNil != nil:
|
||||
## find kind value, default is zero if not specified
|
||||
@@ -3254,21 +3253,18 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
|
||||
break
|
||||
|
||||
let selectedBranch = caseObjDefaultBranch(obj, branch)
|
||||
res.add "{"
|
||||
result.add "{"
|
||||
var countB = 0
|
||||
let b = lastSon(obj[selectedBranch])
|
||||
# designated initilization is the only way to init non first element of unions
|
||||
# branches are allowed to have no members (b.len == 0), in this case they don't need initializer
|
||||
if b.kind == nkRecList and not isEmptyCaseObjectBranch(b):
|
||||
res.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {"
|
||||
getNullValueAux(p, t, b, constOrNil, res, countB, isConst, info)
|
||||
res.add "}"
|
||||
result.add "._" & mangleRecFieldName(p.module, obj[0].sym) & "_" & $selectedBranch & " = {"
|
||||
getNullValueAux(p, t, b, constOrNil, result, countB, isConst, info)
|
||||
result.add "}"
|
||||
elif b.kind == nkSym:
|
||||
res.add "." & mangleRecFieldName(p.module, b.sym) & " = "
|
||||
getNullValueAux(p, t, b, constOrNil, res, countB, isConst, info)
|
||||
else:
|
||||
return
|
||||
result.add res
|
||||
result.add "." & mangleRecFieldName(p.module, b.sym) & " = "
|
||||
getNullValueAux(p, t, b, constOrNil, result, countB, isConst, info)
|
||||
result.add "}"
|
||||
|
||||
of nkSym:
|
||||
|
||||
@@ -301,13 +301,13 @@ proc genCppParamsForCtor(p: BProc; call: PNode; didGenTemp: var bool): string =
|
||||
result.add genCppInitializer(p.module, p, call[i][0].sym.typ, didGenTemp)
|
||||
else:
|
||||
#We need to test for temp in globals, see: #23657
|
||||
let param =
|
||||
let param =
|
||||
if typ[i].kind in {tyVar} and call[i].kind == nkHiddenAddr:
|
||||
call[i][0]
|
||||
else:
|
||||
call[i]
|
||||
if param.kind != nkBracketExpr or param.typ.kind in
|
||||
{tyRef, tyPtr, tyUncheckedArray, tyArray, tyOpenArray,
|
||||
if param.kind != nkBracketExpr or param.typ.kind in
|
||||
{tyRef, tyPtr, tyUncheckedArray, tyArray, tyOpenArray,
|
||||
tyVarargs, tySequence, tyString, tyCstring, tyTuple}:
|
||||
let tempLoc = initLocExprSingleUse(p, param)
|
||||
didGenTemp = didGenTemp or tempLoc.k == locTemp
|
||||
@@ -755,18 +755,6 @@ proc raiseExit(p: BProc) =
|
||||
lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto LA$1_;$n",
|
||||
[p.nestedTryStmts[^1].label])
|
||||
|
||||
proc raiseExitCleanup(p: BProc, destroy: string) =
|
||||
assert p.config.exc == excGoto
|
||||
if nimErrorFlagDisabled notin p.flags:
|
||||
p.flags.incl nimErrorFlagAccessed
|
||||
if p.nestedTryStmts.len == 0:
|
||||
p.flags.incl beforeRetNeeded
|
||||
# easy case, simply goto 'ret':
|
||||
lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) {$1; goto BeforeRet_;}$n", [destroy])
|
||||
else:
|
||||
lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) {$2; goto LA$1_;}$n",
|
||||
[p.nestedTryStmts[^1].label, destroy])
|
||||
|
||||
proc finallyActions(p: BProc) =
|
||||
if p.config.exc != excGoto and p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept:
|
||||
# if the current try stmt have a finally block,
|
||||
@@ -796,14 +784,10 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
var e = rdLoc(a)
|
||||
discard getTypeDesc(p.module, t[0].typ)
|
||||
var typ = skipTypes(t[0].typ, abstractPtrs)
|
||||
case p.config.exc
|
||||
of excCpp:
|
||||
# XXX For reasons that currently escape me, this is only required by the new
|
||||
# C++ based exception handling:
|
||||
if p.config.exc == excCpp:
|
||||
blockLeaveActions(p, howManyTrys = 0, howManyExcepts = p.inExceptBlockLen)
|
||||
of excGoto:
|
||||
blockLeaveActions(p, howManyTrys = 0,
|
||||
howManyExcepts = (if p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept: 1 else: 0))
|
||||
else:
|
||||
discard
|
||||
genLineDir(p, t)
|
||||
if isImportedException(typ, p.config):
|
||||
lineF(p, cpsStmts, "throw $1;$n", [e])
|
||||
@@ -1582,14 +1566,14 @@ proc genAsmStmt(p: BProc, t: PNode) =
|
||||
if whichPragma(i) == wAsmSyntax:
|
||||
asmSyntax = i[1].strVal
|
||||
|
||||
if asmSyntax != "" and
|
||||
if asmSyntax != "" and
|
||||
not (
|
||||
asmSyntax == "gcc" and hasGnuAsm in CC[p.config.cCompiler].props or
|
||||
asmSyntax == "vcc" and hasGnuAsm notin CC[p.config.cCompiler].props):
|
||||
localError(
|
||||
p.config, t.info,
|
||||
p.config, t.info,
|
||||
"Your compiler does not support the specified inline assembler")
|
||||
|
||||
|
||||
genAsmOrEmitStmt(p, t, isAsmStmt=true, s)
|
||||
# see bug #2362, "top level asm statements" seem to be a mis-feature
|
||||
# but even if we don't do this, the example in #2362 cannot possibly
|
||||
|
||||
@@ -277,12 +277,9 @@ proc isInvalidReturnType(conf: ConfigRef; typ: PType, isProc = true): bool =
|
||||
if rettype.isImportedCppType or t.isImportedCppType or
|
||||
(typ.callConv == ccCDecl and conf.selectedGC in {gcArc, gcAtomicArc, gcOrc}):
|
||||
# prevents nrvo for cdecl procs; # bug #23401
|
||||
result = false
|
||||
else:
|
||||
result = containsGarbageCollectedRef(t) or
|
||||
(t.kind == tyObject and not isObjLackingTypeField(t)) or
|
||||
(getSize(conf, rettype) == szUnknownSize and (t.sym == nil or sfImportc notin t.sym.flags))
|
||||
|
||||
return false
|
||||
result = containsGarbageCollectedRef(t) or
|
||||
(t.kind == tyObject and not isObjLackingTypeField(t))
|
||||
else: result = false
|
||||
|
||||
const
|
||||
|
||||
@@ -90,9 +90,6 @@ proc ccgIntroducedPtr*(conf: ConfigRef; s: PSym, retType: PType): bool =
|
||||
if s.typ.sym != nil and sfForward in s.typ.sym.flags:
|
||||
# forwarded objects are *always* passed by pointers for consistency!
|
||||
result = true
|
||||
elif s.typ.kind == tySink and conf.selectedGC notin {gcArc, gcAtomicArc, gcOrc, gcHooks}:
|
||||
# bug #23354:
|
||||
result = false
|
||||
elif (optByRef in s.options) or (getSize(conf, pt) > conf.target.floatSize * 3):
|
||||
result = true # requested anyway
|
||||
elif (tfFinal in pt.flags) and (pt[0] == nil):
|
||||
|
||||
@@ -752,7 +752,6 @@ proc intLiteral(i: BiggestInt; result: var Rope)
|
||||
proc genLiteral(p: BProc, n: PNode; result: var Rope)
|
||||
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType; result: var Rope; argsCounter: var int)
|
||||
proc raiseExit(p: BProc)
|
||||
proc raiseExitCleanup(p: BProc, destroy: string)
|
||||
|
||||
proc initLocExpr(p: BProc, e: PNode, flags: TLocFlags = {}): TLoc =
|
||||
result = initLoc(locNone, e, OnUnknown, flags)
|
||||
|
||||
@@ -166,4 +166,3 @@ proc initDefines*(symbols: StringTableRef) =
|
||||
defineSymbol("nimHasWarnStdPrefix")
|
||||
|
||||
defineSymbol("nimHasVtables")
|
||||
defineSymbol("nimHasJsNoLambdaLifting")
|
||||
|
||||
@@ -56,7 +56,6 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
|
||||
# internalAssert c.config, false
|
||||
idTablePut(c.mapping, s, x)
|
||||
if sfGenSym in s.flags:
|
||||
# TODO: getIdent(c.ic, "`" & x.name.s & "`gensym" & $c.instID)
|
||||
result.add newIdentNode(getIdent(c.ic, x.name.s & "`gensym" & $c.instID),
|
||||
if c.instLines: actual.info else: templ.info)
|
||||
else:
|
||||
|
||||
@@ -59,8 +59,8 @@ type
|
||||
emittedTypeInfo*: seq[string]
|
||||
backendFlags*: set[ModuleBackendFlag]
|
||||
|
||||
syms*: OrderedTable[int32, PackedSym]
|
||||
types*: OrderedTable[int32, PackedType]
|
||||
syms*: seq[PackedSym]
|
||||
types*: seq[PackedType]
|
||||
strings*: BiTable[string] # we could share these between modules.
|
||||
numbers*: BiTable[BiggestInt] # we also store floats in here so
|
||||
# that we can assure that every bit is kept
|
||||
@@ -362,10 +362,10 @@ proc storeType(t: PType; c: var PackedEncoder; m: var PackedModule): PackedItemI
|
||||
result = PackedItemId(module: toLitId(t.uniqueId.module.FileIndex, c, m), item: t.uniqueId.item)
|
||||
|
||||
if t.uniqueId.module == c.thisModule and not c.typeMarker.containsOrIncl(t.uniqueId.item):
|
||||
#if t.uniqueId.item >= m.types.len:
|
||||
# setLen m.types, t.uniqueId.item+1
|
||||
if t.uniqueId.item >= m.types.len:
|
||||
setLen m.types, t.uniqueId.item+1
|
||||
|
||||
var p = PackedType(id: t.uniqueId.item, kind: t.kind, flags: t.flags, callConv: t.callConv,
|
||||
var p = PackedType(kind: t.kind, flags: t.flags, callConv: t.callConv,
|
||||
size: t.size, align: t.align, nonUniqueId: t.itemId.item,
|
||||
paddingAtEnd: t.paddingAtEnd)
|
||||
storeNode(p, t, n)
|
||||
@@ -396,12 +396,12 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
|
||||
result = PackedItemId(module: toLitId(s.itemId.module.FileIndex, c, m), item: s.itemId.item)
|
||||
|
||||
if s.itemId.module == c.thisModule and not c.symMarker.containsOrIncl(s.itemId.item):
|
||||
#if s.itemId.item >= m.syms.len:
|
||||
# setLen m.syms, s.itemId.item+1
|
||||
if s.itemId.item >= m.syms.len:
|
||||
setLen m.syms, s.itemId.item+1
|
||||
|
||||
assert sfForward notin s.flags
|
||||
|
||||
var p = PackedSym(id: s.itemId.item, kind: s.kind, flags: s.flags, info: s.info.toPackedInfo(c, m), magic: s.magic,
|
||||
var p = PackedSym(kind: s.kind, flags: s.flags, info: s.info.toPackedInfo(c, m), magic: s.magic,
|
||||
position: s.position, offset: s.offset, disamb: s.disamb, options: s.options,
|
||||
name: s.name.s.toLitId(m))
|
||||
|
||||
@@ -613,10 +613,6 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef
|
||||
f.loadSection section
|
||||
f.loadSeq data
|
||||
|
||||
template loadTableSection(section, data) {.dirty.} =
|
||||
f.loadSection section
|
||||
f.loadOrderedTable data
|
||||
|
||||
template loadTabSection(section, data) {.dirty.} =
|
||||
f.loadSection section
|
||||
f.load data
|
||||
@@ -649,8 +645,8 @@ proc loadRodFile*(filename: AbsoluteFile; m: var PackedModule; config: ConfigRef
|
||||
loadTabSection topLevelSection, m.topLevel
|
||||
|
||||
loadTabSection bodiesSection, m.bodies
|
||||
loadTableSection symsSection, m.syms
|
||||
loadTableSection typesSection, m.types
|
||||
loadSeqSection symsSection, m.syms
|
||||
loadSeqSection typesSection, m.types
|
||||
|
||||
loadSeqSection typeInstCacheSection, m.typeInstCache
|
||||
loadSeqSection procInstCacheSection, m.procInstCache
|
||||
@@ -695,10 +691,6 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac
|
||||
f.storeSection section
|
||||
f.store data
|
||||
|
||||
template storeTableSection(section, data) {.dirty.} =
|
||||
f.storeSection section
|
||||
f.storeOrderedTable data
|
||||
|
||||
storeTabSection stringsSection, m.strings
|
||||
|
||||
storeSeqSection checkSumsSection, m.includes
|
||||
@@ -722,9 +714,9 @@ proc saveRodFile*(filename: AbsoluteFile; encoder: var PackedEncoder; m: var Pac
|
||||
storeTabSection topLevelSection, m.topLevel
|
||||
|
||||
storeTabSection bodiesSection, m.bodies
|
||||
storeTableSection symsSection, m.syms
|
||||
storeSeqSection symsSection, m.syms
|
||||
|
||||
storeTableSection typesSection, m.types
|
||||
storeSeqSection typesSection, m.types
|
||||
|
||||
storeSeqSection typeInstCacheSection, m.typeInstCache
|
||||
storeSeqSection procInstCacheSection, m.procInstCache
|
||||
@@ -775,8 +767,8 @@ type
|
||||
status*: ModuleStatus
|
||||
symsInit, typesInit, loadedButAliveSetChanged*: bool
|
||||
fromDisk*: PackedModule
|
||||
syms: OrderedTable[int32, PSym] # indexed by itemId
|
||||
types: OrderedTable[int32, PType]
|
||||
syms: seq[PSym] # indexed by itemId
|
||||
types: seq[PType]
|
||||
module*: PSym # the one true module symbol.
|
||||
iface, ifaceHidden: Table[PIdent, seq[PackedItemId]]
|
||||
# PackedItemId so that it works with reexported symbols too
|
||||
@@ -969,11 +961,11 @@ proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s:
|
||||
loadToReplayNodes(g, c.config, c.cache, m, g[int m])
|
||||
|
||||
assert g[si].status in {loaded, storing, stored}
|
||||
#if not g[si].symsInit:
|
||||
# g[si].symsInit = true
|
||||
# setLen g[si].syms, g[si].fromDisk.syms.len
|
||||
if not g[si].symsInit:
|
||||
g[si].symsInit = true
|
||||
setLen g[si].syms, g[si].fromDisk.syms.len
|
||||
|
||||
if g[si].syms.getOrDefault(s.item) == nil:
|
||||
if g[si].syms[s.item] == nil:
|
||||
if g[si].fromDisk.syms[s.item].kind != skModule:
|
||||
result = symHeaderFromPacked(c, g, g[si].fromDisk.syms[s.item], si, s.item)
|
||||
# store it here early on, so that recursions work properly:
|
||||
@@ -1020,11 +1012,11 @@ proc loadType(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; t
|
||||
assert g[si].status in {loaded, storing, stored}
|
||||
assert t.item > 0
|
||||
|
||||
#if not g[si].typesInit:
|
||||
# g[si].typesInit = true
|
||||
# setLen g[si].types, g[si].fromDisk.types.len
|
||||
if not g[si].typesInit:
|
||||
g[si].typesInit = true
|
||||
setLen g[si].types, g[si].fromDisk.types.len
|
||||
|
||||
if g[si].types.getOrDefault(t.item) == nil:
|
||||
if g[si].types[t.item] == nil:
|
||||
result = typeHeaderFromPacked(c, g, g[si].fromDisk.types[t.item], si, t.item)
|
||||
# store it here early on, so that recursions work properly:
|
||||
g[si].types[t.item] = result
|
||||
@@ -1163,7 +1155,10 @@ proc loadProcBody*(config: ConfigRef, cache: IdentCache;
|
||||
proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
|
||||
g: var PackedModuleGraph; module: int; id: PackedItemId): PType =
|
||||
bench g.loadType:
|
||||
result = g[module].types.getOrDefault(id.item)
|
||||
if id.item < g[module].types.len:
|
||||
result = g[module].types[id.item]
|
||||
else:
|
||||
result = nil
|
||||
if result == nil:
|
||||
var decoder = PackedDecoder(
|
||||
lastModule: int32(-1),
|
||||
@@ -1176,7 +1171,10 @@ proc loadTypeFromId*(config: ConfigRef, cache: IdentCache;
|
||||
proc loadSymFromId*(config: ConfigRef, cache: IdentCache;
|
||||
g: var PackedModuleGraph; module: int; id: PackedItemId): PSym =
|
||||
bench g.loadSym:
|
||||
result = g[module].syms.getOrDefault(id.item)
|
||||
if id.item < g[module].syms.len:
|
||||
result = g[module].syms[id.item]
|
||||
else:
|
||||
result = nil
|
||||
if result == nil:
|
||||
var decoder = PackedDecoder(
|
||||
lastModule: int32(-1),
|
||||
@@ -1192,6 +1190,19 @@ proc translateId*(id: PackedItemId; g: PackedModuleGraph; thisModule: int; confi
|
||||
else:
|
||||
ItemId(module: toFileIndex(id.module, g[thisModule].fromDisk, config).int32, item: id.item)
|
||||
|
||||
proc checkForHoles(m: PackedModule; config: ConfigRef; moduleId: int) =
|
||||
var bugs = 0
|
||||
for i in 1 .. high(m.syms):
|
||||
if m.syms[i].kind == skUnknown:
|
||||
echo "EMPTY ID ", i, " module ", moduleId, " ", toFullPath(config, FileIndex(moduleId))
|
||||
inc bugs
|
||||
assert bugs == 0
|
||||
when false:
|
||||
var nones = 0
|
||||
for i in 1 .. high(m.types):
|
||||
inc nones, m.types[i].kind == tyNone
|
||||
assert nones < 1
|
||||
|
||||
proc simulateLoadedModule*(g: var PackedModuleGraph; conf: ConfigRef; cache: IdentCache;
|
||||
moduleSym: PSym; m: PackedModule) =
|
||||
# For now only used for heavy debugging. In the future we could use this to reduce the
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
## Integrity checking for a set of .rod files.
|
||||
## The set must cover a complete Nim project.
|
||||
|
||||
import std/[sets, tables]
|
||||
import std/sets
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
@@ -108,18 +108,18 @@ proc checkModule(c: var CheckedContext; m: PackedModule) =
|
||||
# We check that:
|
||||
# - Every symbol references existing types and symbols.
|
||||
# - Every tree node references existing types and symbols.
|
||||
for _, v in pairs(m.syms):
|
||||
checkLocalSym c, v.id
|
||||
for i in 0..high(m.syms):
|
||||
checkLocalSym c, int32(i)
|
||||
|
||||
checkTree c, m.toReplay
|
||||
checkTree c, m.topLevel
|
||||
|
||||
for e in m.exports:
|
||||
#assert e[1] >= 0 and e[1] < m.syms.len
|
||||
assert e[1] >= 0 and e[1] < m.syms.len
|
||||
assert e[0] == m.syms[e[1]].name
|
||||
|
||||
for e in m.compilerProcs:
|
||||
#assert e[1] >= 0 and e[1] < m.syms.len
|
||||
assert e[1] >= 0 and e[1] < m.syms.len
|
||||
assert e[0] == m.syms[e[1]].name
|
||||
|
||||
checkLocalSymIds c, m, m.converters
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
## IDE-like features. It uses the set of .rod files to accomplish
|
||||
## its task. The set must cover a complete Nim project.
|
||||
|
||||
import std/[sets, tables]
|
||||
import std/sets
|
||||
|
||||
from std/os import nil
|
||||
from std/private/miscdollars import toLocation
|
||||
|
||||
@@ -47,7 +47,6 @@ type
|
||||
path*: NodeId
|
||||
|
||||
PackedSym* = object
|
||||
id*: int32
|
||||
kind*: TSymKind
|
||||
name*: LitId
|
||||
typ*: PackedItemId
|
||||
@@ -72,7 +71,6 @@ type
|
||||
instantiatedFrom*: PackedItemId
|
||||
|
||||
PackedType* = object
|
||||
id*: int32
|
||||
kind*: TTypeKind
|
||||
callConv*: TCallingConvention
|
||||
#nodekind*: TNodeKind
|
||||
|
||||
@@ -19,8 +19,6 @@ from std/typetraits import supportsCopyMem
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[syncio, assertions]
|
||||
|
||||
import std / tables
|
||||
|
||||
## Overview
|
||||
## ========
|
||||
## `RodFile` represents a Rod File (versioned binary format), and the
|
||||
@@ -172,18 +170,6 @@ proc storeSeq*[T](f: var RodFile; s: seq[T]) =
|
||||
for i in 0..<s.len:
|
||||
storePrim(f, s[i])
|
||||
|
||||
proc storeOrderedTable*[K, T](f: var RodFile; s: OrderedTable[K, T]) =
|
||||
if f.err != ok: return
|
||||
if s.len >= high(int32):
|
||||
setError f, tooBig
|
||||
return
|
||||
var lenPrefix = int32(s.len)
|
||||
if writeBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
|
||||
setError f, ioFailure
|
||||
else:
|
||||
for _, v in s:
|
||||
storePrim(f, v)
|
||||
|
||||
proc loadPrim*(f: var RodFile; s: var string) =
|
||||
## Read a string, the length was stored as a prefix
|
||||
if f.err != ok: return
|
||||
@@ -225,19 +211,6 @@ proc loadSeq*[T](f: var RodFile; s: var seq[T]) =
|
||||
for i in 0..<lenPrefix:
|
||||
loadPrim(f, s[i])
|
||||
|
||||
proc loadOrderedTable*[K, T](f: var RodFile; s: var OrderedTable[K, T]) =
|
||||
## `T` must be compatible with `copyMem`, see `loadPrim`
|
||||
if f.err != ok: return
|
||||
var lenPrefix = int32(0)
|
||||
if readBuffer(f.f, addr lenPrefix, sizeof(lenPrefix)) != sizeof(lenPrefix):
|
||||
setError f, ioFailure
|
||||
else:
|
||||
s = initOrderedTable[K, T](lenPrefix)
|
||||
for i in 0..<lenPrefix:
|
||||
var x = default T
|
||||
loadPrim(f, x)
|
||||
s[x.id] = x
|
||||
|
||||
proc storeHeader*(f: var RodFile; cookie = defaultCookie) =
|
||||
## stores the header which is described by `cookie`.
|
||||
if f.err != ok: return
|
||||
|
||||
@@ -872,8 +872,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
for i in 1..<n.len:
|
||||
if n[i].kind == nkExprColonExpr:
|
||||
let field = lookupFieldAgain(t, n[i][0].sym)
|
||||
if field != nil and (sfCursor in field.flags or field.typ.kind in {tyOpenArray, tyVarargs}):
|
||||
# don't sink fields with openarray types
|
||||
if field != nil and sfCursor in field.flags:
|
||||
result[i][1] = p(n[i][1], c, s, normal)
|
||||
else:
|
||||
result[i][1] = p(n[i][1], c, s, m)
|
||||
|
||||
@@ -111,25 +111,13 @@ type
|
||||
blocks: seq[TBlock]
|
||||
extraIndent: int
|
||||
previousFileName: string # For frameInfo inside templates.
|
||||
# legacy: generatedParamCopies and up fields are used for jsNoLambdaLifting
|
||||
generatedParamCopies: IntSet
|
||||
up: PProc # up the call chain; required for closure support
|
||||
|
||||
template config*(p: PProc): ConfigRef = p.module.config
|
||||
|
||||
proc indentLine(p: PProc, r: Rope): Rope =
|
||||
var p = p
|
||||
if jsNoLambdaLifting in p.config.legacyFeatures:
|
||||
var ind = 0
|
||||
while true:
|
||||
inc ind, p.blocks.len + p.extraIndent
|
||||
if p.up == nil or p.up.prc != p.prc.owner:
|
||||
break
|
||||
p = p.up
|
||||
result = repeat(' ', ind*2) & r
|
||||
else:
|
||||
let ind = p.blocks.len + p.extraIndent
|
||||
result = repeat(' ', ind*2) & r
|
||||
let ind = p.blocks.len + p.extraIndent
|
||||
result = repeat(' ', ind*2) & r
|
||||
|
||||
template line(p: PProc, added: string) =
|
||||
p.body.add(indentLine(p, rope(added)))
|
||||
@@ -1212,13 +1200,12 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
||||
proc generateHeader(p: PProc, prc: PSym): Rope =
|
||||
result = ""
|
||||
let typ = prc.typ
|
||||
if jsNoLambdaLifting notin p.config.legacyFeatures:
|
||||
if typ.callConv == ccClosure:
|
||||
# we treat Env as the `this` parameter of the function
|
||||
# to keep it simple
|
||||
let env = prc.ast[paramsPos].lastSon
|
||||
assert env.kind == nkSym, "env is missing"
|
||||
env.sym.loc.r = "this"
|
||||
if typ.callConv == ccClosure:
|
||||
# we treat Env as the `this` parameter of the function
|
||||
# to keep it simple
|
||||
let env = prc.ast[paramsPos].lastSon
|
||||
assert env.kind == nkSym, "env is missing"
|
||||
env.sym.loc.r = "this"
|
||||
|
||||
for i in 1..<typ.n.len:
|
||||
assert(typ.n[i].kind == nkSym)
|
||||
@@ -1252,8 +1239,7 @@ const
|
||||
|
||||
proc needsNoCopy(p: PProc; y: PNode): bool =
|
||||
return y.kind in nodeKindsNeedNoCopy or
|
||||
((mapType(y.typ) != etyBaseIndex or
|
||||
(jsNoLambdaLifting in p.config.legacyFeatures and y.kind == nkSym and y.sym.kind == skParam)) and
|
||||
((mapType(y.typ) != etyBaseIndex) and
|
||||
(skipTypes(y.typ, abstractInst).kind in
|
||||
{tyRef, tyPtr, tyLent, tyVar, tyCstring, tyProc, tyOwned, tyOpenArray} + IntegralTypes))
|
||||
|
||||
@@ -1604,30 +1590,7 @@ proc attachProc(p: PProc; s: PSym) =
|
||||
|
||||
proc genProcForSymIfNeeded(p: PProc, s: PSym) =
|
||||
if not p.g.generatedSyms.containsOrIncl(s.id):
|
||||
if jsNoLambdaLifting in p.config.legacyFeatures:
|
||||
let newp = genProc(p, s)
|
||||
var owner = p
|
||||
while owner != nil and owner.prc != s.owner:
|
||||
owner = owner.up
|
||||
if owner != nil: owner.locals.add(newp)
|
||||
else: attachProc(p, newp, s)
|
||||
else:
|
||||
attachProc(p, s)
|
||||
|
||||
proc genCopyForParamIfNeeded(p: PProc, n: PNode) =
|
||||
let s = n.sym
|
||||
if p.prc == s.owner or needsNoCopy(p, n):
|
||||
return
|
||||
var owner = p.up
|
||||
while true:
|
||||
if owner == nil:
|
||||
internalError(p.config, n.info, "couldn't find the owner proc of the closed over param: " & s.name.s)
|
||||
if owner.prc == s.owner:
|
||||
if not owner.generatedParamCopies.containsOrIncl(s.id):
|
||||
let copy = "$1 = nimCopy(null, $1, $2);$n" % [s.loc.r, genTypeInfo(p, s.typ)]
|
||||
owner.locals.add(owner.indentLine(copy))
|
||||
return
|
||||
owner = owner.up
|
||||
attachProc(p, s)
|
||||
|
||||
proc genVarInit(p: PProc, v: PSym, n: PNode)
|
||||
|
||||
@@ -1639,8 +1602,6 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
|
||||
if sfCompileTime in s.flags:
|
||||
genVarInit(p, s, if s.astdef != nil: s.astdef else: newNodeI(nkEmpty, s.info))
|
||||
if jsNoLambdaLifting in p.config.legacyFeatures and s.kind == skParam:
|
||||
genCopyForParamIfNeeded(p, n)
|
||||
let k = mapType(p, s.typ)
|
||||
if k == etyBaseIndex:
|
||||
r.typ = etyBaseIndex
|
||||
@@ -2727,7 +2688,6 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||
#if gVerbosity >= 3:
|
||||
# echo "BEGIN generating code for: " & prc.name.s
|
||||
var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options)
|
||||
p.up = oldProc
|
||||
var returnStmt: Rope = ""
|
||||
var resultAsgn: Rope = ""
|
||||
var name = mangleName(p.module, prc)
|
||||
@@ -2951,17 +2911,14 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
else:
|
||||
genCall(p, n, r)
|
||||
of nkClosure:
|
||||
if jsNoLambdaLifting in p.config.legacyFeatures:
|
||||
gen(p, n[0], r)
|
||||
else:
|
||||
let tmp = getTemp(p)
|
||||
var a: TCompRes = default(TCompRes)
|
||||
var b: TCompRes = default(TCompRes)
|
||||
gen(p, n[0], a)
|
||||
gen(p, n[1], b)
|
||||
lineF(p, "$1 = $2.bind($3); $1.ClP_0 = $2; $1.ClE_0 = $3;$n", [tmp, a.rdLoc, b.rdLoc])
|
||||
r.res = tmp
|
||||
r.kind = resVal
|
||||
let tmp = getTemp(p)
|
||||
var a: TCompRes = default(TCompRes)
|
||||
var b: TCompRes = default(TCompRes)
|
||||
gen(p, n[0], a)
|
||||
gen(p, n[1], b)
|
||||
lineF(p, "$1 = $2.bind($3); $1.ClP_0 = $2; $1.ClE_0 = $3;$n", [tmp, a.rdLoc, b.rdLoc])
|
||||
r.res = tmp
|
||||
r.kind = resVal
|
||||
of nkCurly: genSetConstr(p, n, r)
|
||||
of nkBracket: genArrayConstr(p, n, r)
|
||||
of nkPar, nkTupleConstr: genTupleConstr(p, n, r)
|
||||
|
||||
@@ -239,11 +239,6 @@ proc interestingIterVar(s: PSym): bool {.inline.} =
|
||||
template isIterator*(owner: PSym): bool =
|
||||
owner.kind == skIterator and owner.typ.callConv == ccClosure
|
||||
|
||||
template liftingHarmful(conf: ConfigRef; owner: PSym): bool =
|
||||
## lambda lifting can be harmful for JS-like code generators.
|
||||
let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro
|
||||
jsNoLambdaLifting in conf.legacyFeatures and conf.backend == backendJs and not isCompileTime
|
||||
|
||||
proc createTypeBoundOpsLL(g: ModuleGraph; refType: PType; info: TLineInfo; idgen: IdGenerator; owner: PSym) =
|
||||
if owner.kind != skMacro:
|
||||
createTypeBoundOps(g, nil, refType.elementType, info, idgen)
|
||||
@@ -260,7 +255,6 @@ proc genCreateEnv(env: PNode): PNode =
|
||||
|
||||
proc liftIterSym*(g: ModuleGraph; n: PNode; idgen: IdGenerator; owner: PSym): PNode =
|
||||
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
|
||||
if liftingHarmful(g.config, owner): return n
|
||||
let iter = n.sym
|
||||
assert iter.isIterator
|
||||
|
||||
@@ -885,8 +879,7 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
|
||||
idgen: IdGenerator; flags: TransformFlags): PNode =
|
||||
let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro
|
||||
|
||||
if body.kind == nkEmpty or (jsNoLambdaLifting in g.config.legacyFeatures and
|
||||
g.config.backend == backendJs and not isCompileTime) or
|
||||
if body.kind == nkEmpty or
|
||||
(fn.skipGenericOwner.kind != skModule and force notin flags):
|
||||
|
||||
# ignore forward declaration:
|
||||
@@ -946,7 +939,6 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; idgen: IdGenerator; owner: PSym):
|
||||
break
|
||||
...
|
||||
"""
|
||||
if liftingHarmful(g.config, owner): return body
|
||||
if not (body.kind == nkForStmt and body[^2].kind in nkCallKinds):
|
||||
localError(g.config, body.info, "ignored invalid for loop")
|
||||
return body
|
||||
|
||||
@@ -157,7 +157,7 @@ proc genWasMovedCall(c: var TLiftCtx; op: PSym; x: PNode): PNode =
|
||||
result.add(newSymNode(op))
|
||||
result.add genAddr(c, x)
|
||||
|
||||
proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool, enforceWasMoved = false) =
|
||||
proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool) =
|
||||
case n.kind
|
||||
of nkSym:
|
||||
if c.filterDiscriminator != nil: return
|
||||
@@ -167,8 +167,6 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool,
|
||||
enforceDefaultOp:
|
||||
defaultOp(c, f.typ, body, x.dotField(f), b)
|
||||
else:
|
||||
if enforceWasMoved:
|
||||
body.add genBuiltin(c, mWasMoved, "`=wasMoved`", x.dotField(f))
|
||||
fillBody(c, f.typ, body, x.dotField(f), b)
|
||||
of nkNilLit: discard
|
||||
of nkRecCase:
|
||||
@@ -207,7 +205,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool,
|
||||
branch[^1] = newNodeI(nkStmtList, c.info)
|
||||
|
||||
fillBodyObj(c, n[i].lastSon, branch[^1], x, y,
|
||||
enforceDefaultOp = localEnforceDefaultOp, enforceWasMoved = c.kind == attachedAsgn)
|
||||
enforceDefaultOp = localEnforceDefaultOp)
|
||||
if branch[^1].len == 0: inc emptyBranches
|
||||
caseStmt.add(branch)
|
||||
if emptyBranches != n.len-1:
|
||||
@@ -218,7 +216,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool,
|
||||
fillBodyObj(c, n[0], body, x, y, enforceDefaultOp = false)
|
||||
c.filterDiscriminator = oldfilterDiscriminator
|
||||
of nkRecList:
|
||||
for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp, enforceWasMoved)
|
||||
for t in items(n): fillBodyObj(c, t, body, x, y, enforceDefaultOp)
|
||||
else:
|
||||
illFormedAstLocal(n, c.g.config)
|
||||
|
||||
@@ -284,7 +282,6 @@ proc fillBodyObjT(c: var TLiftCtx; t: PType, body, x, y: PNode) =
|
||||
c.kind = attachedDestructor
|
||||
fillBodyObjTImpl(c, t, body, blob, y)
|
||||
c.kind = prevKind
|
||||
|
||||
else:
|
||||
fillBodyObjTImpl(c, t, body, x, y)
|
||||
|
||||
|
||||
@@ -436,10 +436,10 @@ template getPContext(): untyped =
|
||||
else: c.c
|
||||
|
||||
when defined(nimsuggest):
|
||||
template onUse*(info: TLineInfo; s: PSym; isGenericInstance = false) = discard
|
||||
template onUse*(info: TLineInfo; s: PSym) = discard
|
||||
template onDefResolveForward*(info: TLineInfo; s: PSym) = discard
|
||||
else:
|
||||
template onUse*(info: TLineInfo; s: PSym; isGenericInstance = false) = discard
|
||||
template onUse*(info: TLineInfo; s: PSym) = discard
|
||||
template onDef*(info: TLineInfo; s: PSym) = discard
|
||||
template onDefResolveForward*(info: TLineInfo; s: PSym) = discard
|
||||
|
||||
|
||||
@@ -246,8 +246,6 @@ type
|
||||
emitGenerics
|
||||
## generics are emitted in the module that contains them.
|
||||
## Useful for libraries that rely on local passC
|
||||
jsNoLambdaLifting
|
||||
## Old transformation for closures in JS backend
|
||||
|
||||
SymbolFilesOption* = enum
|
||||
disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest
|
||||
|
||||
@@ -222,7 +222,66 @@ proc shouldCheckCaseCovered(caseTyp: PType): bool =
|
||||
else:
|
||||
discard
|
||||
|
||||
proc endsInNoReturn(n: PNode): bool
|
||||
proc endsInNoReturn(n: PNode): bool =
|
||||
## check if expr ends the block like raising or call of noreturn procs do
|
||||
result = false # assume it does return
|
||||
|
||||
template checkBranch(branch) =
|
||||
if not endsInNoReturn(branch):
|
||||
# proved a branch returns
|
||||
return false
|
||||
|
||||
var it = n
|
||||
# skip these beforehand, no special handling needed
|
||||
while it.kind in {nkStmtList, nkStmtListExpr} and it.len > 0:
|
||||
it = it.lastSon
|
||||
|
||||
case it.kind
|
||||
of nkIfStmt:
|
||||
var hasElse = false
|
||||
for branch in it:
|
||||
checkBranch:
|
||||
if branch.len == 2:
|
||||
branch[1]
|
||||
elif branch.len == 1:
|
||||
hasElse = true
|
||||
branch[0]
|
||||
else:
|
||||
raiseAssert "Malformed `if` statement during endsInNoReturn"
|
||||
# none of the branches returned
|
||||
result = hasElse # Only truly a no-return when it's exhaustive
|
||||
of nkCaseStmt:
|
||||
let caseTyp = skipTypes(it[0].typ, abstractVar-{tyTypeDesc})
|
||||
# semCase should already have checked for exhaustiveness in this case
|
||||
# effectively the same as having an else
|
||||
var hasElse = caseTyp.shouldCheckCaseCovered()
|
||||
|
||||
# actual noreturn checks
|
||||
for i in 1 ..< it.len:
|
||||
let branch = it[i]
|
||||
checkBranch:
|
||||
case branch.kind
|
||||
of nkOfBranch:
|
||||
branch[^1]
|
||||
of nkElifBranch:
|
||||
branch[1]
|
||||
of nkElse:
|
||||
hasElse = true
|
||||
branch[0]
|
||||
else:
|
||||
raiseAssert "Malformed `case` statement in endsInNoReturn"
|
||||
# Can only guarantee a noreturn if there is an else or it's exhaustive
|
||||
result = hasElse
|
||||
of nkTryStmt:
|
||||
checkBranch(it[0])
|
||||
for i in 1 ..< it.len:
|
||||
let branch = it[i]
|
||||
checkBranch(branch[^1])
|
||||
# none of the branches returned
|
||||
result = true
|
||||
else:
|
||||
result = it.kind in nkLastBlockStmts or
|
||||
it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
|
||||
|
||||
proc commonType*(c: PContext; x: PType, y: PNode): PType =
|
||||
# ignore exception raising branches in case/if expressions
|
||||
@@ -254,8 +313,6 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||
result.owner = getCurrOwner(c)
|
||||
else:
|
||||
result = newSym(kind, considerQuotedIdent(c, n), c.idgen, getCurrOwner(c), n.info)
|
||||
if find(result.name.s, '`') >= 0:
|
||||
result.flags.incl sfWasGenSym
|
||||
#if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule:
|
||||
# incl(result.flags, sfGlobal)
|
||||
when defined(nimsuggest):
|
||||
@@ -265,7 +322,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags): PSym
|
||||
# identifier with visibility
|
||||
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags, fromTopLevel = false): PSym
|
||||
allowed: TSymFlags): PSym
|
||||
|
||||
proc typeAllowedCheck(c: PContext; info: TLineInfo; typ: PType; kind: TSymKind;
|
||||
flags: TTypeAllowedFlags = {}) =
|
||||
|
||||
@@ -683,12 +683,10 @@ proc semResolvedCall(c: PContext, x: var TCandidate,
|
||||
assert x.state == csMatch
|
||||
var finalCallee = x.calleeSym
|
||||
let info = getCallLineInfo(n)
|
||||
markUsed(c, info, finalCallee, isGenericInstance = false)
|
||||
onUse(info, finalCallee, isGenericInstance = false)
|
||||
markUsed(c, info, finalCallee)
|
||||
onUse(info, finalCallee)
|
||||
assert finalCallee.ast != nil
|
||||
if x.hasFauxMatch:
|
||||
markUsed(c, info, finalCallee, isGenericInstance = true)
|
||||
onUse(info, finalCallee, isGenericInstance = true)
|
||||
result = x.call
|
||||
result[0] = newSymNode(finalCallee, getCallLineInfo(result[0]))
|
||||
if containsGenericType(result.typ) or x.fauxMatch == tyUnknown:
|
||||
@@ -723,8 +721,6 @@ proc semResolvedCall(c: PContext, x: var TCandidate,
|
||||
x.call.add tn
|
||||
else:
|
||||
internalAssert c.config, false
|
||||
markUsed(c, info, finalCallee, isGenericInstance = true)
|
||||
onUse(info, finalCallee, isGenericInstance = true)
|
||||
|
||||
result = x.call
|
||||
instGenericConvertersSons(c, result, x)
|
||||
@@ -791,10 +787,8 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
||||
var newInst = generateInstance(c, s, m.bindings, n.info)
|
||||
newInst.typ.flags.excl tfUnresolved
|
||||
let info = getCallLineInfo(n)
|
||||
markUsed(c, info, s, isGenericInstance = false)
|
||||
onUse(info, s, isGenericInstance = false)
|
||||
markUsed(c, info, newInst, isGenericInstance = true)
|
||||
onUse(info, newInst, isGenericInstance = true)
|
||||
markUsed(c, info, s)
|
||||
onUse(info, s)
|
||||
result = newSymNode(newInst, info)
|
||||
|
||||
proc setGenericParams(c: PContext, n, expectedParams: PNode) =
|
||||
|
||||
@@ -168,6 +168,8 @@ type
|
||||
inUncheckedAssignSection*: int
|
||||
importModuleLookup*: Table[int, seq[int]] # (module.ident.id, [module.id])
|
||||
skipTypes*: seq[PNode] # used to skip types between passes in type section. So far only used for inheritance, sets and generic bodies.
|
||||
delayedEffects*: Table[ItemId, seq[PSym]]
|
||||
delayedEffectsInverted*: Table[ItemId, ItemId]
|
||||
TBorrowState* = enum
|
||||
bsNone, bsReturnNotMatch, bsNoDistinct, bsGeneric, bsNotSupported, bsMatch
|
||||
|
||||
|
||||
@@ -771,8 +771,7 @@ proc getConstExpr(m: PSym, n: PNode; idgen: IdGenerator; g: ModuleGraph): PNode
|
||||
of nkCast:
|
||||
var a = getConstExpr(m, n[1], idgen, g)
|
||||
if a == nil: return
|
||||
if n.typ != nil and n.typ.kind in NilableTypes and
|
||||
not (n.typ.kind == tyProc and a.typ.kind == tyProc):
|
||||
if n.typ != nil and n.typ.kind in NilableTypes:
|
||||
# we allow compile-time 'cast' for pointer types:
|
||||
result = a
|
||||
result.typ = n.typ
|
||||
|
||||
@@ -56,11 +56,8 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TypeMapping): PS
|
||||
elif t.kind in {tyGenericParam, tyConcept}:
|
||||
localError(c.config, a.info, errCannotInstantiateX % q.name.s)
|
||||
t = errorType(c)
|
||||
elif isUnresolvedStatic(t) and (q.typ.kind == tyStatic or
|
||||
(q.typ.kind == tyGenericParam and
|
||||
q.typ.genericParamHasConstraints and
|
||||
q.typ.genericConstraint.kind == tyStatic)) and
|
||||
c.inGenericContext == 0 and c.matchedConcept == nil:
|
||||
elif isUnresolvedStatic(t) and c.inGenericContext == 0 and
|
||||
c.matchedConcept == nil:
|
||||
# generic/concept type bodies will try to instantiate static values but
|
||||
# won't actually use them
|
||||
localError(c.config, a.info, errCannotInstantiateX % q.name.s)
|
||||
@@ -399,7 +396,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: TypeMapping,
|
||||
for _, param in paramTypes(result.typ):
|
||||
entry.concreteTypes[i] = param
|
||||
inc i
|
||||
#echo "INSTAN ", fn.name.s, " ", typeToString(result.typ), " ", entry.concreteTypes.len
|
||||
if tfTriggersCompileTime in result.typ.flags:
|
||||
incl(result.flags, sfCompileTime)
|
||||
n[genericParamsPos] = c.graph.emptyNode
|
||||
@@ -428,9 +424,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TypeMapping,
|
||||
if result.magic notin {mSlice, mTypeOf}:
|
||||
# 'toOpenArray' is special and it is allowed to return 'openArray':
|
||||
paramsTypeCheck(c, result.typ)
|
||||
#echo "INSTAN ", fn.name.s, " ", typeToString(result.typ), " <-- NEW PROC!", " ", entry.concreteTypes.len
|
||||
else:
|
||||
#echo "INSTAN ", fn.name.s, " ", typeToString(result.typ), " <-- CACHED! ", typeToString(oldPrc.typ), " ", entry.concreteTypes.len
|
||||
result = oldPrc
|
||||
popProcCon(c)
|
||||
popInfoContext(c.config)
|
||||
|
||||
@@ -957,7 +957,7 @@ proc checkForSink(tracked: PEffects; n: PNode) =
|
||||
proc markCaughtExceptions(tracked: PEffects; g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym) =
|
||||
when defined(nimsuggest):
|
||||
proc internalMarkCaughtExceptions(tracked: PEffects; q: var SuggestFileSymbolDatabase; info: TLineInfo) =
|
||||
var si = q.findSymInfoIndex(info, true)
|
||||
var si = q.findSymInfoIndex(info)
|
||||
if si != -1:
|
||||
q.caughtExceptionsSet[si] = true
|
||||
for w1 in tracked.caughtExceptions.nodes:
|
||||
@@ -1024,7 +1024,14 @@ proc trackCall(tracked: PEffects; n: PNode) =
|
||||
else:
|
||||
if laxEffects notin tracked.c.config.legacyFeatures and a.kind == nkSym and
|
||||
a.sym.kind in routineKinds:
|
||||
propagateEffects(tracked, n, a.sym)
|
||||
if tfTrackedProc in a.sym.typ.flags:
|
||||
propagateEffects(tracked, n, a.sym)
|
||||
else:
|
||||
if a.sym.typ.itemId notin tracked.c.delayedEffects:
|
||||
tracked.c.delayedEffects[a.sym.typ.itemId] = @[tracked.owner]
|
||||
else:
|
||||
tracked.c.delayedEffects[a.sym.typ.itemId].add tracked.owner
|
||||
tracked.c.delayedEffectsInverted[tracked.owner.typ.itemId] = a.sym.typ.itemId
|
||||
else:
|
||||
mergeRaises(tracked, effectList[exceptionEffects], n)
|
||||
mergeTags(tracked, effectList[tagEffects], n)
|
||||
@@ -1728,6 +1735,14 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
|
||||
if strictNotNil in c.features and s.kind in {skProc, skFunc, skMethod, skConverter}:
|
||||
checkNil(s, body, g.config, c.idgen)
|
||||
|
||||
if s.typ.itemId notin c.delayedEffectsInverted:
|
||||
s.typ.flags.incl tfTrackedProc
|
||||
|
||||
if s.typ.itemId in c.delayedEffects:
|
||||
for sym in c.delayedEffects[s.typ.itemId]:
|
||||
trackProc(c, sym, sym.ast[bodyPos])
|
||||
# todo call track delayedEffects recursively
|
||||
|
||||
proc trackStmt*(c: PContext; module: PSym; n: PNode, isTopLevel: bool) =
|
||||
case n.kind
|
||||
of {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef,
|
||||
|
||||
@@ -132,140 +132,17 @@ proc semExprBranchScope(c: PContext, n: PNode; expectedType: PType = nil): PNode
|
||||
closeScope(c)
|
||||
|
||||
const
|
||||
skipForDiscardable = {nkStmtList, nkStmtListExpr,
|
||||
nkOfBranch, nkElse, nkFinally, nkExceptBranch,
|
||||
skipForDiscardable = {nkIfStmt, nkIfExpr, nkCaseStmt, nkOfBranch,
|
||||
nkElse, nkStmtListExpr, nkTryStmt, nkFinally, nkExceptBranch,
|
||||
nkElifBranch, nkElifExpr, nkElseExpr, nkBlockStmt, nkBlockExpr,
|
||||
nkHiddenStdConv, nkHiddenDeref}
|
||||
|
||||
proc implicitlyDiscardable(n: PNode): bool =
|
||||
# same traversal as endsInNoReturn
|
||||
template checkBranch(branch) =
|
||||
if not implicitlyDiscardable(branch):
|
||||
return false
|
||||
|
||||
var it = n
|
||||
# skip these beforehand, no special handling needed
|
||||
while it.kind in skipForDiscardable and it.len > 0:
|
||||
it = it.lastSon
|
||||
|
||||
case it.kind
|
||||
of nkIfExpr, nkIfStmt:
|
||||
for branch in it:
|
||||
checkBranch:
|
||||
if branch.len == 2:
|
||||
branch[1]
|
||||
elif branch.len == 1:
|
||||
branch[0]
|
||||
else:
|
||||
raiseAssert "Malformed `if` statement during implicitlyDiscardable"
|
||||
# all branches are discardable
|
||||
result = true
|
||||
of nkCaseStmt:
|
||||
for i in 1 ..< it.len:
|
||||
let branch = it[i]
|
||||
checkBranch:
|
||||
case branch.kind
|
||||
of nkOfBranch:
|
||||
branch[^1]
|
||||
of nkElifBranch:
|
||||
branch[1]
|
||||
of nkElse:
|
||||
branch[0]
|
||||
else:
|
||||
raiseAssert "Malformed `case` statement in endsInNoReturn"
|
||||
# all branches are discardable
|
||||
result = true
|
||||
of nkTryStmt:
|
||||
checkBranch(it[0])
|
||||
for i in 1 ..< it.len:
|
||||
let branch = it[i]
|
||||
if branch.kind != nkFinally:
|
||||
checkBranch(branch[^1])
|
||||
# all branches are discardable
|
||||
result = true
|
||||
of nkCallKinds:
|
||||
result = it[0].kind == nkSym and {sfDiscardable, sfNoReturn} * it[0].sym.flags != {}
|
||||
of nkLastBlockStmts:
|
||||
result = true
|
||||
else:
|
||||
result = false
|
||||
|
||||
proc endsInNoReturn(n: PNode, returningNode: var PNode): bool =
|
||||
## check if expr ends the block like raising or call of noreturn procs do
|
||||
result = false # assume it does return
|
||||
|
||||
template checkBranch(branch) =
|
||||
if not endsInNoReturn(branch, returningNode):
|
||||
# proved a branch returns
|
||||
return false
|
||||
|
||||
var it = n
|
||||
# skip these beforehand, no special handling needed
|
||||
while it.kind in skipForDiscardable and it.len > 0:
|
||||
it = it.lastSon
|
||||
|
||||
case it.kind
|
||||
of nkIfExpr, nkIfStmt:
|
||||
var hasElse = false
|
||||
for branch in it:
|
||||
checkBranch:
|
||||
if branch.len == 2:
|
||||
branch[1]
|
||||
elif branch.len == 1:
|
||||
hasElse = true
|
||||
branch[0]
|
||||
else:
|
||||
raiseAssert "Malformed `if` statement during endsInNoReturn"
|
||||
# none of the branches returned
|
||||
result = hasElse # Only truly a no-return when it's exhaustive
|
||||
of nkCaseStmt:
|
||||
let caseTyp = skipTypes(it[0].typ, abstractVar-{tyTypeDesc})
|
||||
# semCase should already have checked for exhaustiveness in this case
|
||||
# effectively the same as having an else
|
||||
var hasElse = caseTyp.shouldCheckCaseCovered()
|
||||
|
||||
# actual noreturn checks
|
||||
for i in 1 ..< it.len:
|
||||
let branch = it[i]
|
||||
checkBranch:
|
||||
case branch.kind
|
||||
of nkOfBranch:
|
||||
branch[^1]
|
||||
of nkElifBranch:
|
||||
branch[1]
|
||||
of nkElse:
|
||||
hasElse = true
|
||||
branch[0]
|
||||
else:
|
||||
raiseAssert "Malformed `case` statement in endsInNoReturn"
|
||||
# Can only guarantee a noreturn if there is an else or it's exhaustive
|
||||
result = hasElse
|
||||
of nkTryStmt:
|
||||
checkBranch(it[0])
|
||||
var lastIndex = it.len - 1
|
||||
if it[lastIndex].kind == nkFinally:
|
||||
# if finally is noreturn, then the entire statement is noreturn
|
||||
if endsInNoReturn(it[lastIndex][^1], returningNode):
|
||||
return true
|
||||
dec lastIndex
|
||||
for i in 1 .. lastIndex:
|
||||
let branch = it[i]
|
||||
checkBranch(branch[^1])
|
||||
# none of the branches returned
|
||||
result = true
|
||||
of nkLastBlockStmts:
|
||||
result = true
|
||||
of nkCallKinds:
|
||||
result = it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
|
||||
if not result:
|
||||
returningNode = it
|
||||
else:
|
||||
result = false
|
||||
returningNode = it
|
||||
|
||||
proc endsInNoReturn(n: PNode): bool =
|
||||
var dummy: PNode = nil
|
||||
result = endsInNoReturn(n, dummy)
|
||||
var n = n
|
||||
while n.kind in skipForDiscardable: n = n.lastSon
|
||||
result = n.kind in nkLastBlockStmts or
|
||||
(isCallExpr(n) and n[0].kind == nkSym and
|
||||
sfDiscardable in n[0].sym.flags)
|
||||
|
||||
proc fixNilType(c: PContext; n: PNode) =
|
||||
if isAtom(n):
|
||||
@@ -288,9 +165,13 @@ proc discardCheck(c: PContext, result: PNode, flags: TExprFlags) =
|
||||
localError(c.config, result.info, "expression has no type: " &
|
||||
renderTree(result, {renderNoComments}))
|
||||
else:
|
||||
# Ignore noreturn procs since they don't have a type
|
||||
var n = result
|
||||
if result.endsInNoReturn(n):
|
||||
while n.kind in skipForDiscardable:
|
||||
if n.kind == nkTryStmt: n = n[0]
|
||||
else: n = n.lastSon
|
||||
|
||||
# Ignore noreturn procs since they don't have a type
|
||||
if n.endsInNoReturn:
|
||||
return
|
||||
|
||||
var s = "expression '" & $n & "' is of type '" &
|
||||
@@ -480,7 +361,7 @@ proc identWithin(n: PNode, s: PIdent): bool =
|
||||
|
||||
proc semIdentDef(c: PContext, n: PNode, kind: TSymKind, reportToNimsuggest = true): PSym =
|
||||
if isTopLevel(c):
|
||||
result = semIdentWithPragma(c, kind, n, {sfExported}, fromTopLevel = true)
|
||||
result = semIdentWithPragma(c, kind, n, {sfExported})
|
||||
incl(result.flags, sfGlobal)
|
||||
#if kind in {skVar, skLet}:
|
||||
# echo "global variable here ", n.info, " ", result.name.s
|
||||
|
||||
@@ -540,7 +540,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||
result = newSymG(kind, n, c)
|
||||
|
||||
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags, fromTopLevel = false): PSym =
|
||||
allowed: TSymFlags): PSym =
|
||||
if n.kind == nkPragmaExpr:
|
||||
checkSonsLen(n, 2, c.config)
|
||||
result = semIdentVis(c, kind, n[0], allowed)
|
||||
@@ -555,15 +555,11 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||
else: discard
|
||||
else:
|
||||
result = semIdentVis(c, kind, n, allowed)
|
||||
let invalidPragmasForPush = if fromTopLevel and sfWasGenSym notin result.flags:
|
||||
{}
|
||||
else:
|
||||
{wExportc, wExportCpp, wDynlib}
|
||||
case kind
|
||||
of skField: implicitPragmas(c, result, n.info, fieldPragmas)
|
||||
of skVar: implicitPragmas(c, result, n.info, varPragmas-invalidPragmasForPush)
|
||||
of skLet: implicitPragmas(c, result, n.info, letPragmas-invalidPragmasForPush)
|
||||
of skConst: implicitPragmas(c, result, n.info, constPragmas-invalidPragmasForPush)
|
||||
of skVar: implicitPragmas(c, result, n.info, varPragmas)
|
||||
of skLet: implicitPragmas(c, result, n.info, letPragmas)
|
||||
of skConst: implicitPragmas(c, result, n.info, constPragmas)
|
||||
else: discard
|
||||
|
||||
proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
|
||||
|
||||
@@ -96,7 +96,7 @@ type
|
||||
const
|
||||
isNilConversion = isConvertible # maybe 'isIntConv' fits better?
|
||||
|
||||
proc markUsed*(c: PContext; info: TLineInfo, s: PSym; checkStyle = true; isGenericInstance = false)
|
||||
proc markUsed*(c: PContext; info: TLineInfo, s: PSym; checkStyle = true)
|
||||
proc markOwnerModuleAsUsed*(c: PContext; s: PSym)
|
||||
|
||||
template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
|
||||
@@ -2491,7 +2491,7 @@ proc arrayConstr(c: PContext, n: PNode): PType =
|
||||
result = newTypeS(tyArray, c)
|
||||
rawAddSon(result, makeRangeType(c, 0, 0, n.info))
|
||||
addSonSkipIntLit(result, skipTypes(n.typ,
|
||||
{tyVar, tyLent, tyOrdinal}), c.idgen)
|
||||
{tyGenericInst, tyVar, tyLent, tyOrdinal}), c.idgen)
|
||||
|
||||
proc arrayConstr(c: PContext, info: TLineInfo): PType =
|
||||
result = newTypeS(tyArray, c)
|
||||
|
||||
@@ -618,43 +618,41 @@ proc ensureIdx[T](x: var T, y: int) =
|
||||
proc ensureSeq[T](x: var seq[T]) =
|
||||
if x == nil: newSeq(x, 0)
|
||||
|
||||
proc suggestSym*(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true; isGenericInstance=false) {.inline.} =
|
||||
proc suggestSym*(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.inline.} =
|
||||
## misnamed: should be 'symDeclared'
|
||||
let conf = g.config
|
||||
when defined(nimsuggest):
|
||||
if optIdeExceptionInlayHints in conf.globalOptions or not isGenericInstance:
|
||||
g.suggestSymbols.add SymInfoPair(sym: s, info: info, isDecl: isDecl, isGenericInstance: isGenericInstance), optIdeExceptionInlayHints in g.config.globalOptions
|
||||
g.suggestSymbols.add SymInfoPair(sym: s, info: info, isDecl: isDecl), optIdeExceptionInlayHints in g.config.globalOptions
|
||||
|
||||
if not isGenericInstance:
|
||||
if conf.suggestVersion == 0:
|
||||
if s.allUsages.len == 0:
|
||||
s.allUsages = @[info]
|
||||
else:
|
||||
s.addNoDup(info)
|
||||
if conf.suggestVersion == 0:
|
||||
if s.allUsages.len == 0:
|
||||
s.allUsages = @[info]
|
||||
else:
|
||||
s.addNoDup(info)
|
||||
|
||||
if conf.ideCmd == ideUse:
|
||||
findUsages(g, info, s, usageSym)
|
||||
elif conf.ideCmd == ideDef:
|
||||
findDefinition(g, info, s, usageSym)
|
||||
elif conf.ideCmd == ideDus and s != nil:
|
||||
if isTracked(info, conf.m.trackPos, s.name.s.len):
|
||||
suggestResult(conf, symToSuggest(g, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0))
|
||||
findUsages(g, info, s, usageSym)
|
||||
elif conf.ideCmd == ideHighlight and info.fileIndex == conf.m.trackPos.fileIndex:
|
||||
suggestResult(conf, symToSuggest(g, s, isLocal=false, ideHighlight, info, 100, PrefixMatch.None, false, 0))
|
||||
elif conf.ideCmd == ideOutline and isDecl:
|
||||
# if a module is included then the info we have is inside the include and
|
||||
# we need to walk up the owners until we find the outer most module,
|
||||
# which will be the last skModule prior to an skPackage.
|
||||
var
|
||||
parentFileIndex = info.fileIndex # assume we're in the correct module
|
||||
parentModule = s.owner
|
||||
while parentModule != nil and parentModule.kind == skModule:
|
||||
parentFileIndex = parentModule.info.fileIndex
|
||||
parentModule = parentModule.owner
|
||||
if conf.ideCmd == ideUse:
|
||||
findUsages(g, info, s, usageSym)
|
||||
elif conf.ideCmd == ideDef:
|
||||
findDefinition(g, info, s, usageSym)
|
||||
elif conf.ideCmd == ideDus and s != nil:
|
||||
if isTracked(info, conf.m.trackPos, s.name.s.len):
|
||||
suggestResult(conf, symToSuggest(g, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0))
|
||||
findUsages(g, info, s, usageSym)
|
||||
elif conf.ideCmd == ideHighlight and info.fileIndex == conf.m.trackPos.fileIndex:
|
||||
suggestResult(conf, symToSuggest(g, s, isLocal=false, ideHighlight, info, 100, PrefixMatch.None, false, 0))
|
||||
elif conf.ideCmd == ideOutline and isDecl:
|
||||
# if a module is included then the info we have is inside the include and
|
||||
# we need to walk up the owners until we find the outer most module,
|
||||
# which will be the last skModule prior to an skPackage.
|
||||
var
|
||||
parentFileIndex = info.fileIndex # assume we're in the correct module
|
||||
parentModule = s.owner
|
||||
while parentModule != nil and parentModule.kind == skModule:
|
||||
parentFileIndex = parentModule.info.fileIndex
|
||||
parentModule = parentModule.owner
|
||||
|
||||
if parentFileIndex == conf.m.trackPos.fileIndex:
|
||||
suggestResult(conf, symToSuggest(g, s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0))
|
||||
if parentFileIndex == conf.m.trackPos.fileIndex:
|
||||
suggestResult(conf, symToSuggest(g, s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0))
|
||||
|
||||
proc warnAboutDeprecated(conf: ConfigRef; info: TLineInfo; s: PSym) =
|
||||
var pragmaNode: PNode
|
||||
@@ -698,28 +696,26 @@ proc markOwnerModuleAsUsed(c: PContext; s: PSym) =
|
||||
else:
|
||||
inc i
|
||||
|
||||
proc markUsed(c: PContext; info: TLineInfo; s: PSym; checkStyle = true; isGenericInstance = false) =
|
||||
if not isGenericInstance:
|
||||
let conf = c.config
|
||||
incl(s.flags, sfUsed)
|
||||
if s.kind == skEnumField and s.owner != nil:
|
||||
incl(s.owner.flags, sfUsed)
|
||||
if sfDeprecated in s.owner.flags:
|
||||
proc markUsed(c: PContext; info: TLineInfo; s: PSym; checkStyle = true) =
|
||||
let conf = c.config
|
||||
incl(s.flags, sfUsed)
|
||||
if s.kind == skEnumField and s.owner != nil:
|
||||
incl(s.owner.flags, sfUsed)
|
||||
if sfDeprecated in s.owner.flags:
|
||||
warnAboutDeprecated(conf, info, s)
|
||||
if {sfDeprecated, sfError} * s.flags != {}:
|
||||
if sfDeprecated in s.flags:
|
||||
if not (c.lastTLineInfo.line == info.line and
|
||||
c.lastTLineInfo.col == info.col):
|
||||
warnAboutDeprecated(conf, info, s)
|
||||
if {sfDeprecated, sfError} * s.flags != {}:
|
||||
if sfDeprecated in s.flags:
|
||||
if not (c.lastTLineInfo.line == info.line and
|
||||
c.lastTLineInfo.col == info.col):
|
||||
warnAboutDeprecated(conf, info, s)
|
||||
c.lastTLineInfo = info
|
||||
c.lastTLineInfo = info
|
||||
|
||||
if sfError in s.flags: userError(conf, info, s)
|
||||
if sfError in s.flags: userError(conf, info, s)
|
||||
when defined(nimsuggest):
|
||||
suggestSym(c.graph, info, s, c.graph.usageSym, isDecl = false, isGenericInstance = isGenericInstance)
|
||||
if not isGenericInstance:
|
||||
if checkStyle:
|
||||
styleCheckUse(c, info, s)
|
||||
markOwnerModuleAsUsed(c, s)
|
||||
suggestSym(c.graph, info, s, c.graph.usageSym, false)
|
||||
if checkStyle:
|
||||
styleCheckUse(c, info, s)
|
||||
markOwnerModuleAsUsed(c, s)
|
||||
|
||||
proc safeSemExpr*(c: PContext, n: PNode): PNode =
|
||||
# use only for idetools support!
|
||||
|
||||
@@ -16,7 +16,6 @@ type
|
||||
caughtExceptions*: seq[PType]
|
||||
caughtExceptionsSet*: bool
|
||||
isDecl*: bool
|
||||
isGenericInstance*: bool
|
||||
|
||||
SuggestFileSymbolDatabase* = object
|
||||
lineInfo*: seq[TinyLineInfo]
|
||||
@@ -24,7 +23,6 @@ type
|
||||
caughtExceptions*: seq[seq[PType]]
|
||||
caughtExceptionsSet*: PackedBoolArray
|
||||
isDecl*: PackedBoolArray
|
||||
isGenericInstance*: PackedBoolArray
|
||||
fileIndex*: FileIndex
|
||||
trackCaughtExceptions*: bool
|
||||
isSorted*: bool
|
||||
@@ -84,11 +82,6 @@ proc getSymInfoPair*(s: SuggestFileSymbolDatabase; idx: int): SymInfoPair =
|
||||
s.caughtExceptionsSet[idx]
|
||||
else:
|
||||
false,
|
||||
isGenericInstance:
|
||||
if s.trackCaughtExceptions:
|
||||
s.isGenericInstance[idx]
|
||||
else:
|
||||
false,
|
||||
isDecl: s.isDecl[idx]
|
||||
)
|
||||
|
||||
@@ -97,7 +90,6 @@ proc reverse*(s: var SuggestFileSymbolDatabase) =
|
||||
s.sym.reverse()
|
||||
s.caughtExceptions.reverse()
|
||||
s.caughtExceptionsSet.reverse()
|
||||
s.isGenericInstance.reverse()
|
||||
s.isDecl.reverse()
|
||||
|
||||
proc newSuggestFileSymbolDatabase*(aFileIndex: FileIndex; aTrackCaughtExceptions: bool): SuggestFileSymbolDatabase =
|
||||
@@ -107,7 +99,6 @@ proc newSuggestFileSymbolDatabase*(aFileIndex: FileIndex; aTrackCaughtExceptions
|
||||
caughtExceptions: @[],
|
||||
caughtExceptionsSet: newPackedBoolArray(),
|
||||
isDecl: newPackedBoolArray(),
|
||||
isGenericInstance: newPackedBoolArray(),
|
||||
fileIndex: aFileIndex,
|
||||
trackCaughtExceptions: aTrackCaughtExceptions,
|
||||
isSorted: true
|
||||
@@ -128,8 +119,6 @@ func compare*(s: var SuggestFileSymbolDatabase; i, j: int): int =
|
||||
result = cmp(s.lineInfo[i], s.lineInfo[j])
|
||||
if result == 0:
|
||||
result = cmp(s.isDecl[i], s.isDecl[j])
|
||||
if result == 0 and s.trackCaughtExceptions:
|
||||
result = cmp(s.isGenericInstance[i], s.isGenericInstance[j])
|
||||
|
||||
proc exchange(s: var SuggestFileSymbolDatabase; i, j: int) =
|
||||
if i == j:
|
||||
@@ -144,9 +133,6 @@ proc exchange(s: var SuggestFileSymbolDatabase; i, j: int) =
|
||||
var tmp3 = s.caughtExceptionsSet[i]
|
||||
s.caughtExceptionsSet[i] = s.caughtExceptionsSet[j]
|
||||
s.caughtExceptionsSet[j] = tmp3
|
||||
var tmp6 = s.isGenericInstance[i]
|
||||
s.isGenericInstance[i] = s.isGenericInstance[j]
|
||||
s.isGenericInstance[j] = tmp6
|
||||
var tmp4 = s.isDecl[i]
|
||||
s.isDecl[i] = s.isDecl[j]
|
||||
s.isDecl[j] = tmp4
|
||||
@@ -210,17 +196,12 @@ proc add*(s: var SuggestFileSymbolDatabase; v: SymInfoPair) =
|
||||
if s.trackCaughtExceptions:
|
||||
s.caughtExceptions.add(v.caughtExceptions)
|
||||
s.caughtExceptionsSet.add(v.caughtExceptionsSet)
|
||||
s.isGenericInstance.add(v.isGenericInstance)
|
||||
s.isSorted = false
|
||||
|
||||
proc add*(s: var SuggestSymbolDatabase; v: SymInfoPair; trackCaughtExceptions: bool) =
|
||||
s.mgetOrPut(v.info.fileIndex, newSuggestFileSymbolDatabase(v.info.fileIndex, trackCaughtExceptions)).add(v)
|
||||
|
||||
proc findSymInfoIndex*(s: var SuggestFileSymbolDatabase; li: TLineInfo; isGenericInstance: bool): int =
|
||||
# if trackCaughtExceptions is false, then all records in the database are not generic instances, so
|
||||
# if we're searching for a generic instance, we find none
|
||||
if isGenericInstance and not s.trackCaughtExceptions:
|
||||
return -1
|
||||
proc findSymInfoIndex*(s: var SuggestFileSymbolDatabase; li: TLineInfo): int =
|
||||
doAssert(li.fileIndex == s.fileIndex)
|
||||
if not s.isSorted:
|
||||
s.sort()
|
||||
@@ -229,17 +210,3 @@ proc findSymInfoIndex*(s: var SuggestFileSymbolDatabase; li: TLineInfo; isGeneri
|
||||
col: li.col
|
||||
)
|
||||
result = binarySearch(s.lineInfo, q, cmp)
|
||||
# if trackCaughtExceptions is false, then all records in the database are not generic instances, so
|
||||
# if we're a searching for a non-generic instance, then we're done, we return what we have found
|
||||
if not isGenericInstance and not s.trackCaughtExceptions:
|
||||
return
|
||||
# in this case trackCaughtExceptions is true, and the database contains both generic and non-generic instances, so we need
|
||||
# to check the isGenericInstance flag also
|
||||
if result != -1:
|
||||
# search through a sequence of equal lineInfos to find a matching isGenericInstance
|
||||
while result > 0 and s.isGenericInstance[result] != isGenericInstance and cmp(s.lineInfo[result], s.lineInfo[result - 1]) == 0:
|
||||
dec result
|
||||
while result < (s.lineInfo.len - 1) and s.isGenericInstance[result] != isGenericInstance and cmp(s.lineInfo[result], s.lineInfo[result + 1]) == 0:
|
||||
inc result
|
||||
if s.isGenericInstance[result] != isGenericInstance:
|
||||
result = -1
|
||||
|
||||
@@ -513,7 +513,6 @@ proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode =
|
||||
|
||||
# we cannot generate a proper thunk here for GC-safety reasons
|
||||
# (see internal documentation):
|
||||
if jsNoLambdaLifting in c.graph.config.legacyFeatures and c.graph.config.backend == backendJs: return prc
|
||||
result = newNodeIT(nkClosure, prc.info, dest)
|
||||
var conv = newNodeIT(nkHiddenSubConv, prc.info, dest)
|
||||
conv.add(newNodeI(nkEmpty, prc.info))
|
||||
|
||||
@@ -740,7 +740,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
addSep(prag)
|
||||
prag.add("gcsafe")
|
||||
if not hasImplicitRaises and prefer == preferInferredEffects and not isNil(t.owner) and not isNil(t.owner.typ) and not isNil(t.owner.typ.n) and (t.owner.typ.n.len > 0):
|
||||
let effects = t.n[0]
|
||||
let effects = t.owner.typ.n[0]
|
||||
if effects.kind == nkEffectList and effects.len == effectListLen:
|
||||
var inferredRaisesStr = ""
|
||||
let effs = effects[exceptionEffects]
|
||||
@@ -1316,17 +1316,9 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||
result = sameTypeOrNilAux(a.elementType, b.elementType, c) and
|
||||
sameValue(a.n[0], b.n[0]) and
|
||||
sameValue(a.n[1], b.n[1])
|
||||
of tyAlias, tyInferred, tyIterable:
|
||||
of tyGenericInst, tyAlias, tyInferred, tyIterable:
|
||||
cycleCheck()
|
||||
result = sameTypeAux(a.skipModifier, b.skipModifier, c)
|
||||
of tyGenericInst:
|
||||
# BUG #23445
|
||||
# The type system must distinguish between `T[int] = object #[empty]#`
|
||||
# and `T[float] = object #[empty]#`!
|
||||
cycleCheck()
|
||||
for ff, aa in underspecifiedPairs(a, b, 1, -1):
|
||||
if not sameTypeAux(ff, aa, c): return false
|
||||
result = sameTypeAux(a.skipModifier, b.skipModifier, c)
|
||||
of tyNone: result = false
|
||||
of tyConcept:
|
||||
result = exprStructuralEquivalent(a.n, b.n)
|
||||
|
||||
@@ -8703,7 +8703,7 @@ after the last specified parameter. Nim string values will be converted to C
|
||||
strings automatically:
|
||||
|
||||
```Nim
|
||||
proc printf(formatstr: cstring) {.header: "<stdio.h>", varargs.}
|
||||
proc printf(formatstr: cstring) {.nodecl, varargs.}
|
||||
|
||||
printf("hallo %s", "world") # "world" will be passed as C string
|
||||
```
|
||||
|
||||
@@ -272,15 +272,11 @@ __EMSCRIPTEN__
|
||||
#elif defined(__cplusplus)
|
||||
#define NIM_STATIC_ASSERT(x, msg) static_assert((x), msg)
|
||||
#else
|
||||
#define _NIM_STATIC_ASSERT_FINAL(x, append_name) typedef int NIM_STATIC_ASSERT_AUX ## append_name[(x) ? 1 : -1];
|
||||
#define _NIM_STATIC_ASSERT_STAGE_3(x, line) _NIM_STATIC_ASSERT_FINAL(x, _AT_LINE_##line)
|
||||
#define _NIM_STATIC_ASSERT_STAGE_2(x, line) _NIM_STATIC_ASSERT_STAGE_3(x, line)
|
||||
#define NIM_STATIC_ASSERT(x, msg) _NIM_STATIC_ASSERT_STAGE_2(x,__LINE__)
|
||||
#define NIM_STATIC_ASSERT(x, msg) typedef int NIM_STATIC_ASSERT_AUX[(x) ? 1 : -1];
|
||||
// On failure, your C compiler will say something like:
|
||||
// "error: 'NIM_STATIC_ASSERT_AUX_AT_LINE_XXX' declared as an array with a negative size"
|
||||
// Adding the line number helps to avoid redefinitions which are not allowed in
|
||||
// old GCC versions, however the order of evaluation for __LINE__ is a little tricky,
|
||||
// hence all the helper macros. See https://stackoverflow.com/a/3385694 for more info.
|
||||
// "error: 'NIM_STATIC_ASSERT_AUX' declared as an array with a negative size"
|
||||
// we could use a better fallback to also show line number, using:
|
||||
// http://www.pixelbeat.org/programming/gcc/static_assert.html
|
||||
#endif
|
||||
|
||||
/* C99 compiler? */
|
||||
|
||||
@@ -379,145 +379,6 @@ proc hashVmImplChar(x: openArray[char], sPos, ePos: int): Hash =
|
||||
proc hashVmImplByte(x: openArray[byte], sPos, ePos: int): Hash =
|
||||
raiseAssert "implementation override in compiler/vmops.nim"
|
||||
|
||||
const k0 = 0xc3a5c85c97cb3127u64 # Primes on (2^63, 2^64) for various uses
|
||||
const k1 = 0xb492b66fbe98f273u64
|
||||
const k2 = 0x9ae16a3b2f90404fu64
|
||||
|
||||
proc load4e(s: openArray[byte], o=0): uint32 {.inline.} =
|
||||
uint32(s[o + 3]) shl 24 or uint32(s[o + 2]) shl 16 or
|
||||
uint32(s[o + 1]) shl 8 or uint32(s[o + 0])
|
||||
|
||||
proc load8e(s: openArray[byte], o=0): uint64 {.inline.} =
|
||||
uint64(s[o + 7]) shl 56 or uint64(s[o + 6]) shl 48 or
|
||||
uint64(s[o + 5]) shl 40 or uint64(s[o + 4]) shl 32 or
|
||||
uint64(s[o + 3]) shl 24 or uint64(s[o + 2]) shl 16 or
|
||||
uint64(s[o + 1]) shl 8 or uint64(s[o + 0])
|
||||
|
||||
proc load4(s: openArray[byte], o=0): uint32 {.inline.} =
|
||||
when nimvm: result = load4e(s, o)
|
||||
else:
|
||||
when declared copyMem: copyMem result.addr, s[o].addr, result.sizeof
|
||||
else: result = load4e(s, o)
|
||||
|
||||
proc load8(s: openArray[byte], o=0): uint64 {.inline.} =
|
||||
when nimvm: result = load8e(s, o)
|
||||
else:
|
||||
when declared copyMem: copyMem result.addr, s[o].addr, result.sizeof
|
||||
else: result = load8e(s, o)
|
||||
|
||||
proc lenU(s: openArray[byte]): uint64 {.inline.} = s.len.uint64
|
||||
|
||||
proc shiftMix(v: uint64): uint64 {.inline.} = v xor (v shr 47)
|
||||
|
||||
proc rotR(v: uint64; bits: cint): uint64 {.inline.} =
|
||||
(v shr bits) or (v shl (64 - bits))
|
||||
|
||||
proc len16(u: uint64; v: uint64; mul: uint64): uint64 {.inline.} =
|
||||
var a = (u xor v)*mul
|
||||
a = a xor (a shr 47)
|
||||
var b = (v xor a)*mul
|
||||
b = b xor (b shr 47)
|
||||
b*mul
|
||||
|
||||
proc len0_16(s: openArray[byte]): uint64 {.inline.} =
|
||||
if s.len >= 8:
|
||||
let mul = k2 + 2*s.lenU
|
||||
let a = load8(s) + k2
|
||||
let b = load8(s, s.len - 8)
|
||||
let c = rotR(b, 37)*mul + a
|
||||
let d = (rotR(a, 25) + b)*mul
|
||||
len16 c, d, mul
|
||||
elif s.len >= 4:
|
||||
let mul = k2 + 2*s.lenU
|
||||
let a = load4(s).uint64
|
||||
len16 s.lenU + (a shl 3), load4(s, s.len - 4), mul
|
||||
elif s.len > 0:
|
||||
let a = uint32(s[0])
|
||||
let b = uint32(s[s.len shr 1])
|
||||
let c = uint32(s[s.len - 1])
|
||||
let y = a + (b shl 8)
|
||||
let z = s.lenU + (c shl 2)
|
||||
shiftMix(y*k2 xor z*k0)*k2
|
||||
else: k2 # s.len == 0
|
||||
|
||||
proc len17_32(s: openArray[byte]): uint64 {.inline.} =
|
||||
let mul = k2 + 2*s.lenU
|
||||
let a = load8(s)*k1
|
||||
let b = load8(s, 8)
|
||||
let c = load8(s, s.len - 8)*mul
|
||||
let d = load8(s, s.len - 16)*k2
|
||||
len16 rotR(a + b, 43) + rotR(c, 30) + d, a + rotR(b + k2, 18) + c, mul
|
||||
|
||||
proc len33_64(s: openArray[byte]): uint64 {.inline.} =
|
||||
let mul = k2 + 2*s.lenU
|
||||
let a = load8(s)*k2
|
||||
let b = load8(s, 8)
|
||||
let c = load8(s, s.len - 8)*mul
|
||||
let d = load8(s, s.len - 16)*k2
|
||||
let y = rotR(a + b, 43) + rotR(c, 30) + d
|
||||
let z = len16(y, a + rotR(b + k2, 18) + c, mul)
|
||||
let e = load8(s, 16)*mul
|
||||
let f = load8(s, 24)
|
||||
let g = (y + load8(s, s.len - 32))*mul
|
||||
let h = (z + load8(s, s.len - 24))*mul
|
||||
len16 rotR(e + f, 43) + rotR(g, 30) + h, e + rotR(f + a, 18) + g, mul
|
||||
|
||||
type Pair = tuple[first, second: uint64]
|
||||
|
||||
proc weakLen32withSeeds2(w, x, y, z, a, b: uint64): Pair {.inline.} =
|
||||
var a = a + w
|
||||
var b = rotR(b + a + z, 21)
|
||||
let c = a
|
||||
a += x
|
||||
a += y
|
||||
b += rotR(a, 44)
|
||||
result[0] = a + z
|
||||
result[1] = b + c
|
||||
|
||||
proc weakLen32withSeeds(s: openArray[byte]; o: int; a,b: uint64): Pair {.inline.} =
|
||||
weakLen32withSeeds2 load8(s, o ), load8(s, o + 8),
|
||||
load8(s, o + 16), load8(s, o + 24), a, b
|
||||
|
||||
proc hashFarm(s: openArray[byte]): uint64 {.inline.} =
|
||||
if s.len <= 16: return len0_16(s)
|
||||
if s.len <= 32: return len17_32(s)
|
||||
if s.len <= 64: return len33_64(s)
|
||||
const seed = 81u64 # not const to use input `h`
|
||||
var
|
||||
o = 0 # s[] ptr arith -> variable origin variable `o`
|
||||
x = seed
|
||||
y = seed*k1 + 113
|
||||
z = shiftMix(y*k2 + 113)*k2
|
||||
v, w: Pair
|
||||
x = x*k2 + load8(s)
|
||||
let eos = ((s.len - 1) div 64)*64
|
||||
let last64 = eos + ((s.len - 1) and 63) - 63
|
||||
while true:
|
||||
x = rotR(x + y + v[0] + load8(s, o+8), 37)*k1
|
||||
y = rotR(y + v[1] + load8(s, o+48), 42)*k1
|
||||
x = x xor w[1]
|
||||
y += v[0] + load8(s, o+40)
|
||||
z = rotR(z + w[0], 33)*k1
|
||||
v = weakLen32withSeeds(s, o+0 , v[1]*k1, x + w[0])
|
||||
w = weakLen32withSeeds(s, o+32, z + w[1], y + load8(s, o+16))
|
||||
swap z, x
|
||||
inc o, 64
|
||||
if o == eos: break
|
||||
let mul = k1 + ((z and 0xff) shl 1)
|
||||
o = last64
|
||||
w[0] += (s.lenU - 1) and 63
|
||||
v[0] += w[0]
|
||||
w[0] += v[0]
|
||||
x = rotR(x + y + v[0] + load8(s, o+8), 37)*mul
|
||||
y = rotR(y + v[1] + load8(s, o+48), 42)*mul
|
||||
x = x xor w[1]*9
|
||||
y += v[0]*9 + load8(s, o+40)
|
||||
z = rotR(z + w[0], 33)*mul
|
||||
v = weakLen32withSeeds(s, o+0 , v[1]*mul, x + w[0])
|
||||
w = weakLen32withSeeds(s, o+32, z + w[1], y + load8(s, o+16))
|
||||
swap z, x
|
||||
len16 len16(v[0],w[0],mul) + shiftMix(y)*k0 + z, len16(v[1],w[1],mul) + x, mul
|
||||
|
||||
proc hash*(x: string): Hash =
|
||||
## Efficient hashing of strings.
|
||||
##
|
||||
@@ -527,13 +388,10 @@ proc hash*(x: string): Hash =
|
||||
runnableExamples:
|
||||
doAssert hash("abracadabra") != hash("AbracadabrA")
|
||||
|
||||
when defined nimPreviewHashFarm: # Default switched -> `not nimStringHash2`
|
||||
result = cast[Hash](hashFarm(toOpenArrayByte(x, 0, x.high)))
|
||||
when nimvm:
|
||||
result = hashVmImpl(x, 0, high(x))
|
||||
else:
|
||||
when nimvm:
|
||||
result = hashVmImpl(x, 0, high(x))
|
||||
else:
|
||||
result = murmurHash(toOpenArrayByte(x, 0, high(x)))
|
||||
result = murmurHash(toOpenArrayByte(x, 0, high(x)))
|
||||
|
||||
proc hash*(x: cstring): Hash =
|
||||
## Efficient hashing of null-terminated strings.
|
||||
@@ -542,21 +400,14 @@ proc hash*(x: cstring): Hash =
|
||||
doAssert hash(cstring"AbracadabrA") == hash("AbracadabrA")
|
||||
doAssert hash(cstring"abracadabra") != hash(cstring"AbracadabrA")
|
||||
|
||||
when defined nimPreviewHashFarm: # Default switched -> `not nimStringHash2`
|
||||
when defined js:
|
||||
let xx = $x
|
||||
result = cast[Hash](hashFarm(toOpenArrayByte(xx, 0, xx.high)))
|
||||
else:
|
||||
result = cast[Hash](hashFarm(toOpenArrayByte(x, 0, x.high)))
|
||||
when nimvm:
|
||||
hashVmImpl(x, 0, high(x))
|
||||
else:
|
||||
when nimvm:
|
||||
hashVmImpl(x, 0, high(x))
|
||||
when not defined(js):
|
||||
murmurHash(toOpenArrayByte(x, 0, x.high))
|
||||
else:
|
||||
when not defined(js):
|
||||
murmurHash(toOpenArrayByte(x, 0, x.high))
|
||||
else:
|
||||
let xx = $x
|
||||
murmurHash(toOpenArrayByte(xx, 0, high(xx)))
|
||||
let xx = $x
|
||||
murmurHash(toOpenArrayByte(xx, 0, high(xx)))
|
||||
|
||||
proc hash*(sBuf: string, sPos, ePos: int): Hash =
|
||||
## Efficient hashing of a string buffer, from starting
|
||||
@@ -567,10 +418,7 @@ proc hash*(sBuf: string, sPos, ePos: int): Hash =
|
||||
var a = "abracadabra"
|
||||
doAssert hash(a, 0, 3) == hash(a, 7, 10)
|
||||
|
||||
when defined nimPreviewHashFarm: # Default switched -> `not nimStringHash2`
|
||||
result = cast[Hash](hashFarm(toOpenArrayByte(sBuf, sPos, ePos)))
|
||||
else:
|
||||
murmurHash(toOpenArrayByte(sBuf, sPos, ePos))
|
||||
murmurHash(toOpenArrayByte(sBuf, sPos, ePos))
|
||||
|
||||
proc hashIgnoreStyle*(x: string): Hash =
|
||||
## Efficient hashing of strings; style is ignored.
|
||||
@@ -705,18 +553,12 @@ proc hash*[A](x: openArray[A]): Hash =
|
||||
## Efficient hashing of arrays and sequences.
|
||||
## There must be a `hash` proc defined for the element type `A`.
|
||||
when A is byte:
|
||||
when defined nimPreviewHashFarm: # Default switched -> `not nimStringHash2`
|
||||
result = cast[Hash](hashFarm(x))
|
||||
else:
|
||||
result = murmurHash(x)
|
||||
result = murmurHash(x)
|
||||
elif A is char:
|
||||
when defined nimPreviewHashFarm: # Default switched -> `not nimStringHash2`
|
||||
result = cast[Hash](hashFarm(toOpenArrayByte(x, 0, x.high)))
|
||||
when nimvm:
|
||||
result = hashVmImplChar(x, 0, x.high)
|
||||
else:
|
||||
when nimvm:
|
||||
result = hashVmImplChar(x, 0, x.high)
|
||||
else:
|
||||
result = murmurHash(toOpenArrayByte(x, 0, x.high))
|
||||
result = murmurHash(toOpenArrayByte(x, 0, x.high))
|
||||
else:
|
||||
result = 0
|
||||
for a in x:
|
||||
@@ -734,21 +576,15 @@ proc hash*[A](aBuf: openArray[A], sPos, ePos: int): Hash =
|
||||
doAssert hash(a, 0, 1) == hash(a, 3, 4)
|
||||
|
||||
when A is byte:
|
||||
when defined nimPreviewHashFarm: # Default switched -> `not nimStringHash2`
|
||||
result = cast[Hash](hashFarm(toOpenArray(aBuf, sPos, ePos)))
|
||||
when nimvm:
|
||||
result = hashVmImplByte(aBuf, sPos, ePos)
|
||||
else:
|
||||
when nimvm:
|
||||
result = hashVmImplByte(aBuf, sPos, ePos)
|
||||
else:
|
||||
result = murmurHash(toOpenArray(aBuf, sPos, ePos))
|
||||
result = murmurHash(toOpenArray(aBuf, sPos, ePos))
|
||||
elif A is char:
|
||||
when defined nimPreviewHashFarm: # Default switched -> `not nimStringHash2`
|
||||
result = cast[Hash](hashFarm(toOpenArrayByte(aBuf, sPos, ePos)))
|
||||
when nimvm:
|
||||
result = hashVmImplChar(aBuf, sPos, ePos)
|
||||
else:
|
||||
when nimvm:
|
||||
result = hashVmImplChar(aBuf, sPos, ePos)
|
||||
else:
|
||||
result = murmurHash(toOpenArrayByte(aBuf, sPos, ePos))
|
||||
result = murmurHash(toOpenArrayByte(aBuf, sPos, ePos))
|
||||
else:
|
||||
for i in sPos .. ePos:
|
||||
result = result !& hash(aBuf[i])
|
||||
|
||||
@@ -35,12 +35,12 @@ proc newEIO(msg: string): ref IOError =
|
||||
new(result)
|
||||
result.msg = msg
|
||||
|
||||
proc setFileSize(fh: FileHandle, newFileSize = -1, oldSize = -1): OSErrorCode =
|
||||
## Set the size of open file pointed to by `fh` to `newFileSize` if != -1,
|
||||
## allocating | freeing space from the file system. This routine returns the
|
||||
## last OSErrorCode found rather than raising to support old rollback/clean-up
|
||||
## code style. [ Should maybe move to std/osfiles. ]
|
||||
if newFileSize < 0 or newFileSize == oldSize:
|
||||
proc setFileSize(fh: FileHandle, newFileSize = -1): OSErrorCode =
|
||||
## Set the size of open file pointed to by `fh` to `newFileSize` if != -1.
|
||||
## Space is only allocated if that is cheaper than writing to the file. This
|
||||
## routine returns the last OSErrorCode found rather than raising to support
|
||||
## old rollback/clean-up code style. [ Should maybe move to std/osfiles. ]
|
||||
if newFileSize == -1:
|
||||
return
|
||||
when defined(windows):
|
||||
var sizeHigh = int32(newFileSize shr 32)
|
||||
@@ -51,18 +51,14 @@ proc setFileSize(fh: FileHandle, newFileSize = -1, oldSize = -1): OSErrorCode =
|
||||
setEndOfFile(fh) == 0:
|
||||
result = lastErr
|
||||
else:
|
||||
if newFileSize > oldSize: # grow the file
|
||||
var e: cint # posix_fallocate truncates up when needed.
|
||||
when declared(posix_fallocate):
|
||||
while (e = posix_fallocate(fh, 0, newFileSize); e == EINTR):
|
||||
discard
|
||||
if e in [EINVAL, EOPNOTSUPP] and ftruncate(fh, newFileSize) == -1:
|
||||
result = osLastError() # fallback arguable; Most portable BUT allows SEGV
|
||||
elif e != 0:
|
||||
result = osLastError()
|
||||
else: # shrink the file
|
||||
if ftruncate(fh.cint, newFileSize) == -1:
|
||||
result = osLastError()
|
||||
var e: cint # posix_fallocate truncates up when needed.
|
||||
when declared(posix_fallocate):
|
||||
while (e = posix_fallocate(fh, 0, newFileSize); e == EINTR):
|
||||
discard
|
||||
if e in [EINVAL, EOPNOTSUPP] and ftruncate(fh, newFileSize) == -1:
|
||||
result = osLastError() # fallback arguable; Most portable, but allows SEGV
|
||||
elif e != 0:
|
||||
result = osLastError()
|
||||
|
||||
type
|
||||
MemFile* = object ## represents a memory mapped file
|
||||
@@ -259,31 +255,41 @@ proc open*(filename: string, mode: FileMode = fmRead,
|
||||
flags = flags or O_CREAT or O_TRUNC
|
||||
var permissionsMode = S_IRUSR or S_IWUSR
|
||||
result.handle = open(filename, flags, permissionsMode)
|
||||
if result.handle != -1:
|
||||
if (let e = setFileSize(result.handle.FileHandle, newFileSize);
|
||||
e != 0.OSErrorCode): fail(e, "error setting file size")
|
||||
else:
|
||||
result.handle = open(filename, flags)
|
||||
|
||||
if result.handle == -1:
|
||||
# XXX: errno is supposed to be set here
|
||||
# Is there an exception that wraps it?
|
||||
fail(osLastError(), "error opening file")
|
||||
|
||||
if mappedSize != -1: #XXX Logic here differs from `when windows` branch ..
|
||||
result.size = mappedSize #.. which always fstats&Uses min(mappedSize, st).
|
||||
else: # if newFileSize!=-1: result.size=newFileSize # if trust setFileSize
|
||||
var stat: Stat #^^.. BUT some FSes (eg. Linux HugeTLBfs) round to 2MiB.
|
||||
if (let e = setFileSize(result.handle.FileHandle, newFileSize);
|
||||
e != 0.OSErrorCode): fail(e, "error setting file size")
|
||||
|
||||
if mappedSize != -1:
|
||||
result.size = mappedSize
|
||||
else:
|
||||
var stat: Stat
|
||||
if fstat(result.handle, stat) != -1:
|
||||
result.size = stat.st_size.int # int may be 32-bit-unsafe for 2..<4 GiB
|
||||
# XXX: Hmm, this could be unsafe
|
||||
# Why is mmap taking int anyway?
|
||||
result.size = int(stat.st_size)
|
||||
else:
|
||||
fail(osLastError(), "error getting file size")
|
||||
|
||||
result.flags = if mapFlags == cint(-1): MAP_SHARED else: mapFlags
|
||||
# Ensure exactly one of MAP_PRIVATE cr MAP_SHARED is set
|
||||
#Ensure exactly one of MAP_PRIVATE cr MAP_SHARED is set
|
||||
if int(result.flags and MAP_PRIVATE) == 0:
|
||||
result.flags = result.flags or MAP_SHARED
|
||||
|
||||
let pr = if readonly: PROT_READ else: PROT_READ or PROT_WRITE
|
||||
result.mem = mmap(nil, result.size, pr, result.flags, result.handle, offset)
|
||||
result.mem = mmap(
|
||||
nil,
|
||||
result.size,
|
||||
if readonly: PROT_READ else: PROT_READ or PROT_WRITE,
|
||||
result.flags,
|
||||
result.handle,
|
||||
offset)
|
||||
|
||||
if result.mem == cast[pointer](MAP_FAILED):
|
||||
fail(osLastError(), "file mapping failed")
|
||||
|
||||
@@ -347,7 +353,7 @@ proc resize*(f: var MemFile, newFileSize: int) {.raises: [IOError, OSError].} =
|
||||
raise newException(IOError,
|
||||
"Cannot resize MemFile opened with allowRemap=false")
|
||||
if newFileSize != f.size:
|
||||
if (let e = setFileSize(f.handle.FileHandle, newFileSize, f.size);
|
||||
if (let e = setFileSize(f.handle.FileHandle, newFileSize);
|
||||
e != 0.OSErrorCode): raiseOSError(e)
|
||||
when defined(linux): #Maybe NetBSD, too?
|
||||
# On Linux this can be over 100 times faster than a munmap,mmap cycle.
|
||||
|
||||
@@ -117,10 +117,9 @@ proc option*[T](val: sink T): Option[T] {.inline.} =
|
||||
assert option[Foo](nil).isNone
|
||||
assert option(42).isSome
|
||||
|
||||
when T is SomePointer:
|
||||
result = Option[T](val: val)
|
||||
else:
|
||||
result = Option[T](has: true, val: val)
|
||||
result.val = val
|
||||
when T isnot SomePointer:
|
||||
result.has = true
|
||||
|
||||
proc some*[T](val: sink T): Option[T] {.inline.} =
|
||||
## Returns an `Option` that has the value `val`.
|
||||
@@ -137,9 +136,10 @@ proc some*[T](val: sink T): Option[T] {.inline.} =
|
||||
|
||||
when T is SomePointer:
|
||||
assert not val.isNil
|
||||
result = Option[T](val: val)
|
||||
result.val = val
|
||||
else:
|
||||
result = Option[T](has: true, val: val)
|
||||
result.has = true
|
||||
result.val = val
|
||||
|
||||
proc none*(T: typedesc): Option[T] {.inline.} =
|
||||
## Returns an `Option` for this type that has no value.
|
||||
|
||||
@@ -692,10 +692,7 @@ proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noWeirdT
|
||||
|
||||
proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect], noWeirdTarget.} =
|
||||
## Sleeps `milsecs` milliseconds.
|
||||
## A negative `milsecs` causes sleep to return immediately.
|
||||
when defined(windows):
|
||||
if milsecs < 0:
|
||||
return # fixes #23732
|
||||
winlean.sleep(int32(milsecs))
|
||||
else:
|
||||
var a, b: Timespec
|
||||
|
||||
@@ -460,8 +460,6 @@ proc parseBiggestInt*(s: openArray[char], number: var BiggestInt): int {.
|
||||
var res: BiggestInt
|
||||
doAssert parseBiggestInt("9223372036854775807", res) == 19
|
||||
doAssert res == 9223372036854775807
|
||||
doAssert parseBiggestInt("-2024_05_09", res) == 11
|
||||
doAssert res == -20240509
|
||||
var res = BiggestInt(0)
|
||||
# use 'res' for exception safety (don't write to 'number' in case of an
|
||||
# overflow exception):
|
||||
@@ -476,8 +474,10 @@ proc parseInt*(s: openArray[char], number: var int): int {.
|
||||
## `ValueError` is raised if the parsed integer is out of the valid range.
|
||||
runnableExamples:
|
||||
var res: int
|
||||
doAssert parseInt("-2024_05_02", res) == 11
|
||||
doAssert res == -20240502
|
||||
doAssert parseInt("2019", res, 0) == 4
|
||||
doAssert res == 2019
|
||||
doAssert parseInt("2019", res, 2) == 2
|
||||
doAssert res == 19
|
||||
var res = BiggestInt(0)
|
||||
result = parseBiggestInt(s, res)
|
||||
when sizeof(int) <= 4:
|
||||
@@ -992,10 +992,6 @@ proc parseBiggestInt*(s: string, number: var BiggestInt, start = 0): int {.noSid
|
||||
var res: BiggestInt
|
||||
doAssert parseBiggestInt("9223372036854775807", res, 0) == 19
|
||||
doAssert res == 9223372036854775807
|
||||
doAssert parseBiggestInt("-2024_05_09", res) == 11
|
||||
doAssert res == -20240509
|
||||
doAssert parseBiggestInt("-2024_05_02", res, 7) == 4
|
||||
doAssert res == 502
|
||||
parseBiggestInt(s.toOpenArray(start, s.high), number)
|
||||
|
||||
proc parseInt*(s: string, number: var int, start = 0): int {.noSideEffect, raises: [ValueError].} =
|
||||
@@ -1004,10 +1000,10 @@ proc parseInt*(s: string, number: var int, start = 0): int {.noSideEffect, raise
|
||||
## `ValueError` is raised if the parsed integer is out of the valid range.
|
||||
runnableExamples:
|
||||
var res: int
|
||||
doAssert parseInt("-2024_05_02", res) == 11
|
||||
doAssert res == -20240502
|
||||
doAssert parseInt("-2024_05_02", res, 7) == 4
|
||||
doAssert res == 502
|
||||
doAssert parseInt("2019", res, 0) == 4
|
||||
doAssert res == 2019
|
||||
doAssert parseInt("2019", res, 2) == 2
|
||||
doAssert res == 19
|
||||
parseInt(s.toOpenArray(start, s.high), number)
|
||||
|
||||
|
||||
|
||||
@@ -874,7 +874,7 @@ proc writeFile*(filename: string, content: openArray[byte]) {.since: (1, 1).} =
|
||||
var f: File = nil
|
||||
if open(f, filename, fmWrite):
|
||||
try:
|
||||
discard f.writeBuffer(unsafeAddr content[0], content.len)
|
||||
f.writeBuffer(unsafeAddr content[0], content.len)
|
||||
finally:
|
||||
close(f)
|
||||
else:
|
||||
|
||||
@@ -93,6 +93,8 @@ type
|
||||
freeList: ptr FreeCell
|
||||
free: int # how many bytes remain
|
||||
acc: int # accumulator for small object allocation
|
||||
when defined(gcDestructors):
|
||||
sharedFreeList: ptr FreeCell # make no attempt at avoiding false sharing for now for this object field
|
||||
data {.align: MemAlign.}: UncheckedArray[byte] # start of usable memory
|
||||
|
||||
BigChunk = object of BaseChunk # not necessarily > PageSize!
|
||||
@@ -107,9 +109,7 @@ type
|
||||
MemRegion = object
|
||||
when not defined(gcDestructors):
|
||||
minLargeObj, maxLargeObj: int
|
||||
freeSmallChunks: array[0..max(1, SmallChunkSize div MemAlign-1), PSmallChunk]
|
||||
when defined(gcDestructors):
|
||||
sharedFreeLists: array[0..max(1, SmallChunkSize div MemAlign-1), ptr FreeCell]
|
||||
freeSmallChunks: array[0..max(1,SmallChunkSize div MemAlign-1), PSmallChunk]
|
||||
flBitmap: uint32
|
||||
slBitmap: array[RealFli, uint32]
|
||||
matrix: array[RealFli, array[MaxSli, PBigChunk]]
|
||||
@@ -777,10 +777,8 @@ when defined(gcDestructors):
|
||||
sysAssert c.next == nil, "c.next pointer must be nil"
|
||||
atomicPrepend a.sharedFreeListBigChunks, c
|
||||
|
||||
proc addToSharedFreeList(c: PSmallChunk; f: ptr FreeCell; size: int) {.inline.} =
|
||||
atomicPrepend c.owner.sharedFreeLists[size], f
|
||||
|
||||
const MaxSteps = 20
|
||||
proc addToSharedFreeList(c: PSmallChunk; f: ptr FreeCell) {.inline.} =
|
||||
atomicPrepend c.sharedFreeList, f
|
||||
|
||||
proc compensateCounters(a: var MemRegion; c: PSmallChunk; size: int) =
|
||||
# rawDealloc did NOT do the usual:
|
||||
@@ -790,26 +788,30 @@ when defined(gcDestructors):
|
||||
# we split the list in order to achieve bounded response times.
|
||||
var it = c.freeList
|
||||
var x = 0
|
||||
var maxIters = 20 # make it time-bounded
|
||||
while it != nil:
|
||||
if maxIters == 0:
|
||||
let rest = it.next.loada
|
||||
if rest != nil:
|
||||
it.next.storea nil
|
||||
addToSharedFreeList(c, rest)
|
||||
break
|
||||
inc x, size
|
||||
let chunk = cast[PSmallChunk](pageAddr(it))
|
||||
inc(chunk.free, x)
|
||||
it = it.next
|
||||
it = it.next.loada
|
||||
dec maxIters
|
||||
inc(c.free, x)
|
||||
dec(a.occ, x)
|
||||
|
||||
proc freeDeferredObjects(a: var MemRegion; root: PBigChunk) =
|
||||
var it = root
|
||||
var maxIters = MaxSteps # make it time-bounded
|
||||
var maxIters = 20 # make it time-bounded
|
||||
while true:
|
||||
let rest = it.next.loada
|
||||
it.next.storea nil
|
||||
deallocBigChunk(a, cast[PBigChunk](it))
|
||||
if maxIters == 0:
|
||||
if rest != nil:
|
||||
addToSharedFreeListBigChunks(a, rest)
|
||||
sysAssert a.sharedFreeListBigChunks != nil, "re-enqueing failed"
|
||||
let rest = it.next.loada
|
||||
it.next.storea nil
|
||||
addToSharedFreeListBigChunks(a, rest)
|
||||
break
|
||||
it = rest
|
||||
it = it.next.loada
|
||||
dec maxIters
|
||||
if it == nil: break
|
||||
|
||||
@@ -833,6 +835,8 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
|
||||
sysAssert c.size == PageSize, "rawAlloc 3"
|
||||
c.size = size
|
||||
c.acc = size
|
||||
when defined(gcDestructors):
|
||||
c.sharedFreeList = nil
|
||||
c.free = SmallChunkSize - smallChunkOverhead() - size
|
||||
sysAssert c.owner == addr(a), "rawAlloc: No owner set!"
|
||||
c.next = nil
|
||||
@@ -849,11 +853,10 @@ proc rawAlloc(a: var MemRegion, requestedSize: int): pointer =
|
||||
when defined(gcDestructors):
|
||||
if c.freeList == nil:
|
||||
when hasThreadSupport:
|
||||
# Steal the entire list from `sharedFreeList`:
|
||||
c.freeList = atomicExchangeN(addr a.sharedFreeLists[s], nil, ATOMIC_RELAXED)
|
||||
c.freeList = atomicExchangeN(addr c.sharedFreeList, nil, ATOMIC_RELAXED)
|
||||
else:
|
||||
c.freeList = a.sharedFreeLists[s]
|
||||
a.sharedFreeLists[s] = nil
|
||||
c.freeList = c.sharedFreeList
|
||||
c.sharedFreeList = nil
|
||||
compensateCounters(a, c, size)
|
||||
if c.freeList == nil:
|
||||
sysAssert(c.acc + smallChunkOverhead() + size <= SmallChunkSize,
|
||||
@@ -920,7 +923,7 @@ proc rawDealloc(a: var MemRegion, p: pointer) =
|
||||
if isSmallChunk(c):
|
||||
# `p` is within a small chunk:
|
||||
var c = cast[PSmallChunk](c)
|
||||
let s = c.size
|
||||
var s = c.size
|
||||
# ^ We might access thread foreign storage here.
|
||||
# The other thread cannot possibly free this block as it's still alive.
|
||||
var f = cast[ptr FreeCell](p)
|
||||
@@ -954,7 +957,7 @@ proc rawDealloc(a: var MemRegion, p: pointer) =
|
||||
freeBigChunk(a, cast[PBigChunk](c))
|
||||
else:
|
||||
when defined(gcDestructors):
|
||||
addToSharedFreeList(c, f, s div MemAlign)
|
||||
addToSharedFreeList(c, f)
|
||||
sysAssert(((cast[int](p) and PageMask) - smallChunkOverhead()) %%
|
||||
s == 0, "rawDealloc 2")
|
||||
else:
|
||||
|
||||
@@ -146,7 +146,7 @@ proc unregisterCycle(s: Cell) =
|
||||
let idx = s.rootIdx-1
|
||||
when false:
|
||||
if idx >= roots.len or idx < 0:
|
||||
cprintf("[Bug!] %ld %ld\n", idx, roots.len)
|
||||
cprintf("[Bug!] %ld\n", idx)
|
||||
rawQuit 1
|
||||
roots.d[idx] = roots.d[roots.len-1]
|
||||
roots.d[idx][0].rootIdx = idx+1
|
||||
@@ -303,14 +303,6 @@ proc collectColor(s: Cell; desc: PNimTypeV2; col: int; j: var GcEnv) =
|
||||
t.setColor(colBlack)
|
||||
trace(t, desc, j)
|
||||
|
||||
const
|
||||
defaultThreshold = when defined(nimFixedOrc): 10_000 else: 128
|
||||
|
||||
when defined(nimStressOrc):
|
||||
const rootsThreshold = 10 # broken with -d:nimStressOrc: 10 and for havlak iterations 1..8
|
||||
else:
|
||||
var rootsThreshold {.threadvar.}: int
|
||||
|
||||
proc collectCyclesBacon(j: var GcEnv; lowMark: int) =
|
||||
# pretty direct translation from
|
||||
# https://researcher.watson.ibm.com/researcher/files/us-bacon/Bacon01Concurrent.pdf
|
||||
@@ -349,25 +341,22 @@ proc collectCyclesBacon(j: var GcEnv; lowMark: int) =
|
||||
s.rootIdx = 0
|
||||
collectColor(s, roots.d[i][1], colToCollect, j)
|
||||
|
||||
# Bug #22927: `free` calls destructors which can append to `roots`.
|
||||
# We protect against this here by setting `roots.len` to 0 and also
|
||||
# setting the threshold so high that no cycle collection can be triggered
|
||||
# until we are out of this critical section:
|
||||
when not defined(nimStressOrc):
|
||||
let oldThreshold = rootsThreshold
|
||||
rootsThreshold = high(int)
|
||||
roots.len = 0
|
||||
|
||||
for i in 0 ..< j.toFree.len:
|
||||
when orcLeakDetector:
|
||||
writeCell("CYCLIC OBJECT FREED", j.toFree.d[i][0], j.toFree.d[i][1])
|
||||
free(j.toFree.d[i][0], j.toFree.d[i][1])
|
||||
|
||||
when not defined(nimStressOrc):
|
||||
rootsThreshold = oldThreshold
|
||||
|
||||
inc j.freed, j.toFree.len
|
||||
deinit j.toFree
|
||||
#roots.len = 0
|
||||
|
||||
const
|
||||
defaultThreshold = when defined(nimFixedOrc): 10_000 else: 128
|
||||
|
||||
when defined(nimStressOrc):
|
||||
const rootsThreshold = 10 # broken with -d:nimStressOrc: 10 and for havlak iterations 1..8
|
||||
else:
|
||||
var rootsThreshold {.threadvar.}: int
|
||||
|
||||
when defined(nimOrcStats):
|
||||
var freedCyclicObjects {.threadvar.}: int
|
||||
@@ -407,8 +396,7 @@ proc collectCycles() =
|
||||
collectCyclesBacon(j, 0)
|
||||
|
||||
deinit j.traceStack
|
||||
if roots.len == 0:
|
||||
deinit roots
|
||||
deinit roots
|
||||
|
||||
when not defined(nimStressOrc):
|
||||
# compute the threshold based on the previous history
|
||||
|
||||
@@ -134,8 +134,7 @@ const
|
||||
#List of currently supported capabilities. So lang servers/ides can iterate over and check for what's enabled
|
||||
Capabilities = [
|
||||
"con", #current NimSuggest supports the `con` commmand
|
||||
"exceptionInlayHints",
|
||||
"unknownFile", #current NimSuggest can handle unknown files
|
||||
"exceptionInlayHints"
|
||||
]
|
||||
|
||||
proc parseQuoted(cmd: string; outp: var string; start: int): int =
|
||||
@@ -759,7 +758,15 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
|
||||
|
||||
if gMode != mstdin:
|
||||
conf.writelnHook = proc (msg: string) = discard
|
||||
conf.prefixDir = conf.getPrefixDir()
|
||||
# Find Nim's prefix dir.
|
||||
let binaryPath = findExe("nim")
|
||||
if binaryPath == "":
|
||||
raise newException(IOError,
|
||||
"Cannot find Nim standard library: Nim compiler not in PATH")
|
||||
conf.prefixDir = AbsoluteDir binaryPath.splitPath().head.parentDir()
|
||||
if not dirExists(conf.prefixDir / RelativeDir"lib"):
|
||||
conf.prefixDir = AbsoluteDir""
|
||||
|
||||
#msgs.writelnHook = proc (line: string) = log(line)
|
||||
myLog("START " & conf.projectFull.string)
|
||||
|
||||
@@ -807,7 +814,7 @@ func deduplicateSymInfoPair[SymInfoPair](xs: seq[SymInfoPair]): seq[SymInfoPair]
|
||||
result.add(itm)
|
||||
result.reverse()
|
||||
|
||||
func deduplicateSymInfoPair(xs: SuggestFileSymbolDatabase, isGenericInstance: bool): SuggestFileSymbolDatabase =
|
||||
func deduplicateSymInfoPair(xs: SuggestFileSymbolDatabase): SuggestFileSymbolDatabase =
|
||||
# xs contains duplicate items and we want to filter them by range because the
|
||||
# sym may not match. This can happen when xs contains the same definition but
|
||||
# with different signature because suggestSym might be called multiple times
|
||||
@@ -818,7 +825,6 @@ func deduplicateSymInfoPair(xs: SuggestFileSymbolDatabase, isGenericInstance: bo
|
||||
isDecl: newPackedBoolArray(),
|
||||
caughtExceptions: newSeqOfCap[seq[PType]](xs.caughtExceptions.len),
|
||||
caughtExceptionsSet: newPackedBoolArray(),
|
||||
isGenericInstance: newPackedBoolArray(),
|
||||
fileIndex: xs.fileIndex,
|
||||
trackCaughtExceptions: xs.trackCaughtExceptions,
|
||||
isSorted: false
|
||||
@@ -832,15 +838,13 @@ func deduplicateSymInfoPair(xs: SuggestFileSymbolDatabase, isGenericInstance: bo
|
||||
found = true
|
||||
break
|
||||
if not found:
|
||||
let q = xs.getSymInfoPair(i)
|
||||
if q.isGenericInstance == isGenericInstance:
|
||||
result.add(q)
|
||||
result.add(xs.getSymInfoPair(i))
|
||||
dec i
|
||||
result.reverse()
|
||||
|
||||
proc findSymData(graph: ModuleGraph, trackPos: TLineInfo, isGenericInstance: bool = false):
|
||||
proc findSymData(graph: ModuleGraph, trackPos: TLineInfo):
|
||||
ref SymInfoPair =
|
||||
let db = graph.fileSymbols(trackPos.fileIndex).deduplicateSymInfoPair(isGenericInstance)
|
||||
let db = graph.fileSymbols(trackPos.fileIndex).deduplicateSymInfoPair
|
||||
doAssert(db.fileIndex == trackPos.fileIndex)
|
||||
for i in db.lineInfo.low..db.lineInfo.high:
|
||||
if isTracked(db.lineInfo[i], TinyLineInfo(line: trackPos.line, col: trackPos.col), db.sym[i].name.s.len):
|
||||
@@ -854,28 +858,28 @@ func isInRange*(current, startPos, endPos: TinyLineInfo, tokenLen: int): bool =
|
||||
(current.line > startPos.line or (current.line == startPos.line and current.col>=startPos.col)) and
|
||||
(current.line < endPos.line or (current.line == endPos.line and current.col <= endPos.col))
|
||||
|
||||
proc findSymDataInRange(graph: ModuleGraph, startPos, endPos: TLineInfo, isGenericInstance: bool = false):
|
||||
proc findSymDataInRange(graph: ModuleGraph, startPos, endPos: TLineInfo):
|
||||
seq[SymInfoPair] =
|
||||
result = newSeq[SymInfoPair]()
|
||||
let db = graph.fileSymbols(startPos.fileIndex).deduplicateSymInfoPair(isGenericInstance)
|
||||
let db = graph.fileSymbols(startPos.fileIndex).deduplicateSymInfoPair
|
||||
for i in db.lineInfo.low..db.lineInfo.high:
|
||||
if isInRange(db.lineInfo[i], TinyLineInfo(line: startPos.line, col: startPos.col), TinyLineInfo(line: endPos.line, col: endPos.col), db.sym[i].name.s.len):
|
||||
result.add(db.getSymInfoPair(i))
|
||||
|
||||
proc findSymData(graph: ModuleGraph, file: AbsoluteFile; line, col: int, isGenericInstance: bool = false):
|
||||
proc findSymData(graph: ModuleGraph, file: AbsoluteFile; line, col: int):
|
||||
ref SymInfoPair =
|
||||
let
|
||||
fileIdx = fileInfoIdx(graph.config, file)
|
||||
trackPos = newLineInfo(fileIdx, line, col)
|
||||
result = findSymData(graph, trackPos, isGenericInstance)
|
||||
result = findSymData(graph, trackPos)
|
||||
|
||||
proc findSymDataInRange(graph: ModuleGraph, file: AbsoluteFile; startLine, startCol, endLine, endCol: int, isGenericInstance: bool = false):
|
||||
proc findSymDataInRange(graph: ModuleGraph, file: AbsoluteFile; startLine, startCol, endLine, endCol: int):
|
||||
seq[SymInfoPair] =
|
||||
let
|
||||
fileIdx = fileInfoIdx(graph.config, file)
|
||||
startPos = newLineInfo(fileIdx, startLine, startCol)
|
||||
endPos = newLineInfo(fileIdx, endLine, endCol)
|
||||
result = findSymDataInRange(graph, startPos, endPos, isGenericInstance)
|
||||
result = findSymDataInRange(graph, startPos, endPos)
|
||||
|
||||
proc markDirtyIfNeeded(graph: ModuleGraph, file: string, originalFileIdx: FileIndex) =
|
||||
let sha = $sha1.secureHashFile(file)
|
||||
@@ -924,7 +928,7 @@ proc suggestInlayHintResultException(graph: ModuleGraph, sym: PSym, info: TLineI
|
||||
if sym.kind == skParam and sfEffectsDelayed in sym.flags:
|
||||
return
|
||||
|
||||
var raisesList: seq[PType] = @[]
|
||||
var raisesList: seq[PType] = @[getEbase(graph, info)]
|
||||
|
||||
let t = sym.typ
|
||||
if not isNil(t) and not isNil(t.n) and t.n.len > 0 and t.n[0].len > exceptionEffects:
|
||||
@@ -932,6 +936,7 @@ proc suggestInlayHintResultException(graph: ModuleGraph, sym: PSym, info: TLineI
|
||||
if effects.kind == nkEffectList and effects.len == effectListLen:
|
||||
let effs = effects[exceptionEffects]
|
||||
if not isNil(effs):
|
||||
raisesList = @[]
|
||||
for eff in items(effs):
|
||||
if not isNil(eff):
|
||||
raisesList.add(eff.typ)
|
||||
@@ -1060,6 +1065,10 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile,
|
||||
var fileIndex: FileIndex
|
||||
|
||||
if not (cmd in {ideRecompile, ideGlobalSymbols}):
|
||||
if not fileInfoKnown(conf, file):
|
||||
myLog fmt "{file} is unknown, returning no results"
|
||||
return
|
||||
|
||||
fileIndex = fileInfoIdx(conf, file)
|
||||
msgs.setDirtyFile(
|
||||
conf,
|
||||
@@ -1136,7 +1145,7 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile,
|
||||
incl m.flags, sfDirty
|
||||
of ideOutline:
|
||||
let n = parseFile(fileIndex, graph.cache, graph.config)
|
||||
graph.iterateOutlineNodes(n, graph.fileSymbols(fileIndex).deduplicateSymInfoPair(false))
|
||||
graph.iterateOutlineNodes(n, graph.fileSymbols(fileIndex).deduplicateSymInfoPair)
|
||||
of ideChk:
|
||||
myLog fmt "Reporting errors for {graph.suggestErrors.len} file(s)"
|
||||
for sug in graph.suggestErrorsIter:
|
||||
@@ -1188,7 +1197,7 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile,
|
||||
# find first mention of the symbol in the file containing the definition.
|
||||
# It is either the definition or the declaration.
|
||||
var first: SymInfoPair
|
||||
let db = graph.fileSymbols(s.sym.info.fileIndex).deduplicateSymInfoPair(false)
|
||||
let db = graph.fileSymbols(s.sym.info.fileIndex).deduplicateSymInfoPair
|
||||
for i in db.lineInfo.low..db.lineInfo.high:
|
||||
if s.sym.symbolEqual(db.sym[i]):
|
||||
first = db.getSymInfoPair(i)
|
||||
@@ -1261,16 +1270,12 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile,
|
||||
else:
|
||||
myLog fmt "Discarding unknown inlay hint parameter {token}"
|
||||
|
||||
if typeHints:
|
||||
let s = graph.findSymDataInRange(file, line, col, endLine, endCol, false)
|
||||
for q in s:
|
||||
if typeHints and q.sym.kind in {skLet, skVar, skForVar, skConst} and q.isDecl and not q.sym.hasUserSpecifiedType:
|
||||
graph.suggestInlayHintResultType(q.sym, q.info, ideInlayHints)
|
||||
if exceptionHints:
|
||||
let sGen = graph.findSymDataInRange(file, line, col, endLine, endCol, true)
|
||||
for q in sGen:
|
||||
if q.sym.kind in {skProc, skFunc, skMethod, skVar, skLet, skParam} and not q.isDecl:
|
||||
graph.suggestInlayHintResultException(q.sym, q.info, ideInlayHints, caughtExceptions = q.caughtExceptions, caughtExceptionsSet = q.caughtExceptionsSet)
|
||||
let s = graph.findSymDataInRange(file, line, col, endLine, endCol)
|
||||
for q in s:
|
||||
if typeHints and q.sym.kind in {skLet, skVar, skForVar, skConst} and q.isDecl and not q.sym.hasUserSpecifiedType:
|
||||
graph.suggestInlayHintResultType(q.sym, q.info, ideInlayHints)
|
||||
if exceptionHints and q.sym.kind in {skProc, skFunc, skMethod, skVar, skLet, skParam} and not q.isDecl:
|
||||
graph.suggestInlayHintResultException(q.sym, q.info, ideInlayHints, caughtExceptions = q.caughtExceptions, caughtExceptionsSet = q.caughtExceptionsSet)
|
||||
else:
|
||||
myLog fmt "Discarding {cmd}"
|
||||
|
||||
@@ -1339,7 +1344,13 @@ else:
|
||||
conf.writelnHook = proc (msg: string) = discard
|
||||
# Find Nim's prefix dir.
|
||||
if nimPath == "":
|
||||
conf.prefixDir = conf.getPrefixDir()
|
||||
let binaryPath = findExe("nim")
|
||||
if binaryPath == "":
|
||||
raise newException(IOError,
|
||||
"Cannot find Nim standard library: Nim compiler not in PATH")
|
||||
conf.prefixDir = AbsoluteDir binaryPath.splitPath().head.parentDir()
|
||||
if not dirExists(conf.prefixDir / RelativeDir"lib"):
|
||||
conf.prefixDir = AbsoluteDir""
|
||||
else:
|
||||
conf.prefixDir = AbsoluteDir nimPath
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ pkg "criterion", allowFailure = true # needs testing binary
|
||||
pkg "datamancer"
|
||||
pkg "dashing", "nim c tests/functional.nim"
|
||||
pkg "delaunay"
|
||||
pkg "dnsclient", allowFailure = true # super fragile
|
||||
pkg "dnsclient"
|
||||
pkg "docopt"
|
||||
pkg "dotenv"
|
||||
# when defined(linux): pkg "drchaos"
|
||||
@@ -144,6 +144,7 @@ pkg "polypbren"
|
||||
pkg "presto"
|
||||
pkg "prologue", "nimble tcompile"
|
||||
pkg "protobuf", "nim c -o:protobuff -r src/protobuf.nim"
|
||||
pkg "pylib"
|
||||
pkg "rbtree"
|
||||
pkg "react", "nimble example"
|
||||
pkg "regex", "nim c src/regex"
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
discard """
|
||||
joinable: false
|
||||
"""
|
||||
|
||||
import std / [atomics, strutils, sequtils]
|
||||
|
||||
type
|
||||
BackendMessage* = object
|
||||
field*: seq[int]
|
||||
|
||||
var
|
||||
chan1: Channel[BackendMessage]
|
||||
chan2: Channel[BackendMessage]
|
||||
|
||||
chan1.open()
|
||||
chan2.open()
|
||||
|
||||
proc routeMessage*(msg: BackendMessage) =
|
||||
discard chan2.trySend(msg)
|
||||
|
||||
var
|
||||
recv: Thread[void]
|
||||
stopToken: Atomic[bool]
|
||||
|
||||
proc recvMsg() =
|
||||
while not stopToken.load(moRelaxed):
|
||||
let resp = chan1.tryRecv()
|
||||
if resp.dataAvailable:
|
||||
routeMessage(resp.msg)
|
||||
echo "child consumes ", formatSize getOccupiedMem()
|
||||
|
||||
createThread[void](recv, recvMsg)
|
||||
|
||||
const MESSAGE_COUNT = 100
|
||||
|
||||
proc main() =
|
||||
let msg: BackendMessage = BackendMessage(field: (0..500).toSeq())
|
||||
for j in 0..0: #100:
|
||||
echo "New iteration"
|
||||
|
||||
for _ in 1..MESSAGE_COUNT:
|
||||
chan1.send(msg)
|
||||
echo "After sending"
|
||||
|
||||
var counter = 0
|
||||
while counter < MESSAGE_COUNT:
|
||||
let resp = recv(chan2)
|
||||
counter.inc
|
||||
echo "After receiving ", formatSize getOccupiedMem()
|
||||
|
||||
stopToken.store true, moRelaxed
|
||||
joinThreads(recv)
|
||||
|
||||
main()
|
||||
@@ -1,58 +0,0 @@
|
||||
discard """
|
||||
disabled: "true"
|
||||
"""
|
||||
|
||||
import std / [atomics, strutils, sequtils, isolation]
|
||||
|
||||
import threading / channels
|
||||
|
||||
type
|
||||
BackendMessage* = object
|
||||
field*: seq[int]
|
||||
|
||||
const MESSAGE_COUNT = 100
|
||||
|
||||
var
|
||||
chan1 = newChan[BackendMessage](MESSAGE_COUNT*2)
|
||||
chan2 = newChan[BackendMessage](MESSAGE_COUNT*2)
|
||||
|
||||
#chan1.open()
|
||||
#chan2.open()
|
||||
|
||||
proc routeMessage*(msg: BackendMessage) =
|
||||
var m = isolate(msg)
|
||||
discard chan2.trySend(m)
|
||||
|
||||
var
|
||||
thr: Thread[void]
|
||||
stopToken: Atomic[bool]
|
||||
|
||||
proc recvMsg() =
|
||||
while not stopToken.load(moRelaxed):
|
||||
var resp: BackendMessage
|
||||
if chan1.tryRecv(resp):
|
||||
#if resp.dataAvailable:
|
||||
routeMessage(resp)
|
||||
echo "child consumes ", formatSize getOccupiedMem()
|
||||
|
||||
createThread[void](thr, recvMsg)
|
||||
|
||||
proc main() =
|
||||
let msg: BackendMessage = BackendMessage(field: (0..5).toSeq())
|
||||
for j in 0..100:
|
||||
echo "New iteration"
|
||||
|
||||
for _ in 1..MESSAGE_COUNT:
|
||||
chan1.send(msg)
|
||||
echo "After sending"
|
||||
|
||||
var counter = 0
|
||||
while counter < MESSAGE_COUNT:
|
||||
let resp = recv(chan2)
|
||||
counter.inc
|
||||
echo "After receiving ", formatSize getOccupiedMem()
|
||||
|
||||
stopToken.store true, moRelaxed
|
||||
joinThreads(thr)
|
||||
|
||||
main()
|
||||
@@ -338,29 +338,3 @@ block:
|
||||
doAssert ff.s == 12
|
||||
|
||||
mainSync()
|
||||
|
||||
import std/sequtils
|
||||
|
||||
# bug #23690
|
||||
type
|
||||
SomeObj* = object of RootObj
|
||||
|
||||
Item* = object
|
||||
case kind*: 0..1
|
||||
of 0:
|
||||
a*: int
|
||||
b*: SomeObj
|
||||
of 1:
|
||||
c*: string
|
||||
|
||||
ItemExt* = object
|
||||
a*: Item
|
||||
b*: string
|
||||
|
||||
proc do1(x: int): seq[(string, Item)] =
|
||||
result = @[("zero", Item(kind: 1, c: "first"))]
|
||||
|
||||
proc do2(x: int, e: ItemExt): seq[(string, ItemExt)] =
|
||||
do1(x).map(proc(v: (string, Item)): auto = (v[0], ItemExt(a: v[1], b: e.b)))
|
||||
|
||||
doAssert $do2(0, ItemExt(a: Item(kind: 1, c: "second"), b: "third")) == """@[("zero", (a: (kind: 1, c: "first"), b: "third"))]"""
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
discard """
|
||||
output: '''0
|
||||
true'''
|
||||
cmd: "nim c --gc:arc $file"
|
||||
"""
|
||||
|
||||
# bug #22398
|
||||
|
||||
for i in 0 ..< 10_000:
|
||||
try:
|
||||
try:
|
||||
raise newException(ValueError, "")
|
||||
except CatchableError:
|
||||
discard
|
||||
raise newException(ValueError, "") # or raise getCurrentException(), just raise works ok
|
||||
except ValueError:
|
||||
discard
|
||||
echo getOccupiedMem()
|
||||
echo getCurrentException() == nil
|
||||
@@ -1,12 +0,0 @@
|
||||
discard """
|
||||
errormsg: "expression '0' is of type 'int literal(0)' and has to be used (or discarded); start of expression here: t23677.nim(1, 1)"
|
||||
line: 10
|
||||
column: 3
|
||||
"""
|
||||
|
||||
# issue #23677
|
||||
|
||||
if true:
|
||||
0
|
||||
else:
|
||||
raise newException(ValueError, "err")
|
||||
@@ -5,7 +5,6 @@ tdiscardable
|
||||
1
|
||||
something defered
|
||||
something defered
|
||||
hi
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -111,32 +110,3 @@ block:
|
||||
|
||||
doAssertRaises(ValueError):
|
||||
doAssert foo() == 12
|
||||
|
||||
block: # issue #10440
|
||||
proc x(): int {.discardable.} = discard
|
||||
try:
|
||||
x()
|
||||
finally:
|
||||
echo "hi"
|
||||
|
||||
import macros
|
||||
|
||||
block: # issue #14665
|
||||
macro test(): untyped =
|
||||
let b = @[1, 2, 3, 4]
|
||||
|
||||
result = nnkStmtList.newTree()
|
||||
var i = 0
|
||||
while i < b.len:
|
||||
if false:
|
||||
# this quote do is mandatory, removing it fixes the problem
|
||||
result.add quote do:
|
||||
let testtest = 5
|
||||
else:
|
||||
result.add quote do:
|
||||
let test = 6
|
||||
inc i
|
||||
# removing this continue fixes the problem too
|
||||
continue
|
||||
inc i
|
||||
test()
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
discard """
|
||||
cmd: "nim check $file"
|
||||
"""
|
||||
|
||||
block: # issue #19672
|
||||
try:
|
||||
10 #[tt.Error
|
||||
^ expression '10' is of type 'int literal(10)' and has to be used (or discarded); start of expression here: tfinallyerrmsg.nim(5, 1)]#
|
||||
finally:
|
||||
echo "Finally block"
|
||||
|
||||
block: # issue #13871
|
||||
template t(body: int) =
|
||||
try:
|
||||
body
|
||||
finally:
|
||||
echo "expression"
|
||||
t: 2 #[tt.Error
|
||||
^ expression '2' is of type 'int literal(2)' and has to be used (or discarded)]#
|
||||
@@ -1,9 +0,0 @@
|
||||
discard """
|
||||
exitcode: 1
|
||||
outputsub: '''
|
||||
Error: unhandled exception: value out of range: -2 notin 0 .. 9223372036854775807 [RangeDefect]
|
||||
'''
|
||||
"""
|
||||
|
||||
# bug #22852
|
||||
echo [0][2..^2]
|
||||
@@ -140,8 +140,3 @@ block: # issue #1771
|
||||
|
||||
var a: Foo[range[0..2], float]
|
||||
doAssert test(a) == 0.0
|
||||
|
||||
block: # issue #23730
|
||||
proc test(M: static[int]): array[1 shl M, int] = discard
|
||||
doAssert len(test(3)) == 8
|
||||
doAssert len(test(5)) == 32
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
discard """
|
||||
matrix: "--legacy:jsnolambdalifting;"
|
||||
output: '''
|
||||
3
|
||||
2
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
# bug #23418
|
||||
|
||||
template mapIt*(x: untyped): untyped =
|
||||
type OutType {.gensym.} = typeof(x) #typeof(x, typeOfProc)
|
||||
newSeq[OutType](5)
|
||||
|
||||
type F[E] = object
|
||||
|
||||
proc start(v: int): F[(ValueError,)] = discard
|
||||
proc stop(v: int): F[tuple[]] = discard
|
||||
|
||||
assert $typeof(mapIt(start(9))) == "seq[F[(ValueError,)]]"
|
||||
assert $typeof(mapIt(stop(9))) == "seq[F[tuple[]]]"
|
||||
|
||||
# bug #23445
|
||||
|
||||
type F2[T; I: static int] = distinct int
|
||||
|
||||
proc start2(v: int): F2[void, 22] = discard
|
||||
proc stop2(v: int): F2[void, 33] = discard
|
||||
|
||||
var a = mapIt(start2(5))
|
||||
|
||||
assert $type(a) == "seq[F2[system.void, 22]]", $type(a)
|
||||
|
||||
var b = mapIt(stop2(5))
|
||||
|
||||
assert $type(b) == "seq[F2[system.void, 33]]", $type(b)
|
||||
@@ -1,7 +1,6 @@
|
||||
discard """
|
||||
output: '''
|
||||
Hello World
|
||||
Hello World
|
||||
Hello World'''
|
||||
joinable: false
|
||||
"""
|
||||
@@ -9,7 +8,7 @@ type MyProc = proc() {.cdecl.}
|
||||
type MyProc2 = proc() {.nimcall.}
|
||||
type MyProc3 = proc() #{.closure.} is implicit
|
||||
|
||||
proc testProc() {.exportc:"foo".} = echo "Hello World"
|
||||
proc testProc() = echo "Hello World"
|
||||
|
||||
template reject(x) = doAssert(not compiles(x))
|
||||
|
||||
@@ -24,10 +23,6 @@ proc callPointer(p: pointer) =
|
||||
ffunc0()
|
||||
ffunc1()
|
||||
|
||||
# bug #5901
|
||||
proc foo() {.importc.}
|
||||
(cast[proc(a: int) {.cdecl.}](foo))(5)
|
||||
|
||||
callPointer(cast[pointer](testProc))
|
||||
|
||||
reject: discard cast[enum](0)
|
||||
|
||||
@@ -99,28 +99,3 @@ block: # bug #23019
|
||||
k(w)
|
||||
{.pop.}
|
||||
{.pop.}
|
||||
|
||||
{.push exportC.}
|
||||
|
||||
block:
|
||||
proc foo11() =
|
||||
const factor = [1, 2, 3, 4]
|
||||
doAssert factor[0] == 1
|
||||
proc foo21() =
|
||||
const factor = [1, 2, 3, 4]
|
||||
doAssert factor[0] == 1
|
||||
|
||||
foo11()
|
||||
foo21()
|
||||
|
||||
template foo31() =
|
||||
let factor = [1, 2, 3, 4]
|
||||
doAssert factor[0] == 1
|
||||
template foo41() =
|
||||
let factor = [1, 2, 3, 4]
|
||||
doAssert factor[0] == 1
|
||||
|
||||
foo31()
|
||||
foo41()
|
||||
|
||||
{.pop.}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
discard """
|
||||
matrix: "--gc:refc; --gc:arc"
|
||||
output: '''
|
||||
Value is: 42
|
||||
Value is: 42'''
|
||||
"""
|
||||
|
||||
type AnObject* = object of RootObj
|
||||
value*: int
|
||||
|
||||
proc mutate(a: sink AnObject) =
|
||||
a.value = 1
|
||||
|
||||
var obj = AnObject(value: 42)
|
||||
echo "Value is: ", obj.value
|
||||
mutate(obj)
|
||||
echo "Value is: ", obj.value
|
||||
@@ -47,22 +47,19 @@ block hashes:
|
||||
doAssert hashWangYi1(456) == -6421749900419628582
|
||||
|
||||
block empty:
|
||||
const emptyStrHash = # Hash=int=4B on js even w/--jsbigint64:on => cast[Hash]
|
||||
when defined nimPreviewHashFarm: cast[Hash](-7286425919675154353i64)
|
||||
else: 0
|
||||
var
|
||||
a = ""
|
||||
b = newSeq[char]()
|
||||
c = newSeq[int]()
|
||||
d = cstring""
|
||||
e = "abcd"
|
||||
doAssert hash(a) == emptyStrHash
|
||||
doAssert hash(b) == emptyStrHash
|
||||
doAssert hash(a) == 0
|
||||
doAssert hash(b) == 0
|
||||
doAssert hash(c) == 0
|
||||
doAssert hash(d) == emptyStrHash
|
||||
doAssert hash(d) == 0
|
||||
doAssert hashIgnoreCase(a) == 0
|
||||
doAssert hashIgnoreStyle(a) == 0
|
||||
doAssert hash(e, 3, 2) == emptyStrHash
|
||||
doAssert hash(e, 3, 2) == 0
|
||||
|
||||
block sameButDifferent:
|
||||
doAssert hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13)
|
||||
@@ -96,11 +93,7 @@ block largeSize: # longer than 4 characters
|
||||
proc main() =
|
||||
doAssert hash(0.0) == hash(0)
|
||||
# bug #16061
|
||||
when defined nimPreviewHashFarm: # Default switched -> `not nimStringHash2`
|
||||
# Hash=int=4B on js even w/--jsbigint64:on => cast[Hash]
|
||||
doAssert hash(cstring"abracadabra") == cast[Hash](-1119910118870047694i64)
|
||||
else:
|
||||
doAssert hash(cstring"abracadabra") == 97309975
|
||||
doAssert hash(cstring"abracadabra") == 97309975
|
||||
doAssert hash(cstring"abracadabra") == hash("abracadabra")
|
||||
|
||||
when sizeof(int) == 8 or defined(js):
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
matrix: "; --backend:cpp; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on"
|
||||
matrix: "--mm:refc; --backend:cpp --mm:refc; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on"
|
||||
"""
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ for i in 0 .. 10000:
|
||||
except:
|
||||
discard
|
||||
# memory diff should less than 4M
|
||||
doAssert(abs(getOccupiedMem() - startMemory) < 4 * 1024 * 1024)
|
||||
doAssert(abs(getOccupiedMem() - startMemory) < 4 * 1024 * 1024) # todo fixme doesn;t work for ORC
|
||||
|
||||
|
||||
# test `$`
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
|
||||
import std / [atomics, strutils, sequtils]
|
||||
|
||||
type
|
||||
BackendMessage* = object
|
||||
field*: seq[int]
|
||||
|
||||
var
|
||||
chan1: Channel[BackendMessage]
|
||||
chan2: Channel[BackendMessage]
|
||||
|
||||
chan1.open()
|
||||
chan2.open()
|
||||
|
||||
proc routeMessage*(msg: BackendMessage) =
|
||||
discard chan2.trySend(msg)
|
||||
|
||||
var
|
||||
recv: Thread[void]
|
||||
stopToken: Atomic[bool]
|
||||
|
||||
proc recvMsg() =
|
||||
while not stopToken.load(moRelaxed):
|
||||
let resp = chan1.tryRecv()
|
||||
if resp.dataAvailable:
|
||||
routeMessage(resp.msg)
|
||||
echo "child consumes ", formatSize getOccupiedMem()
|
||||
|
||||
createThread[void](recv, recvMsg)
|
||||
|
||||
const MESSAGE_COUNT = 100
|
||||
|
||||
proc main() =
|
||||
let msg: BackendMessage = BackendMessage(field: (0..500).toSeq())
|
||||
for j in 0..0: #100:
|
||||
echo "New iteration"
|
||||
|
||||
for _ in 1..MESSAGE_COUNT:
|
||||
chan1.send(msg)
|
||||
echo "After sending"
|
||||
|
||||
var counter = 0
|
||||
while counter < MESSAGE_COUNT:
|
||||
let resp = recv(chan2)
|
||||
counter.inc
|
||||
echo "After receiving ", formatSize getOccupiedMem()
|
||||
|
||||
stopToken.store true, moRelaxed
|
||||
joinThreads(recv)
|
||||
|
||||
main()
|
||||
@@ -124,13 +124,3 @@ proc bug22597 = # bug #22597
|
||||
doAssert i == 1
|
||||
|
||||
bug22597()
|
||||
|
||||
block: # bug #20048
|
||||
type
|
||||
Test = object
|
||||
tokens: openArray[string]
|
||||
|
||||
func init(Self: typedesc[Test], tokens: openArray[string]): Self = Self(tokens: tokens)
|
||||
|
||||
let data = Test.init(["123"])
|
||||
doAssert @(data.tokens) == @["123"]
|
||||
|
||||
@@ -58,18 +58,6 @@ block: # bug #16671
|
||||
|
||||
f()
|
||||
|
||||
block: # bug #15746
|
||||
type
|
||||
Reader = object
|
||||
data: openArray[char]
|
||||
current: int
|
||||
|
||||
proc initReader(data: openArray[char], offset = 0): Reader =
|
||||
result = Reader(data: data, current: offset)
|
||||
|
||||
let s = "\x01\x00\x00\x00"
|
||||
doAssert initReader(s).data[0].int == 1
|
||||
|
||||
block:
|
||||
proc foo(x: openArray[char]) =
|
||||
discard x
|
||||
|
||||
Reference in New Issue
Block a user