mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-31 10:53:40 +00:00
Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4c44d10df | ||
|
|
55bb60a56b | ||
|
|
ef8b8317ff | ||
|
|
fff127bec7 | ||
|
|
7b5289a1a4 | ||
|
|
3a0d09c1c5 | ||
|
|
3ab6012c81 | ||
|
|
add124e07a | ||
|
|
8834f3e74d | ||
|
|
489dd89a45 | ||
|
|
ba9effc8a1 | ||
|
|
0d93fdf607 | ||
|
|
b8cec0c714 | ||
|
|
4793fc0fc1 | ||
|
|
e1b44666b0 | ||
|
|
194d21a6e4 | ||
|
|
1b80f7126a | ||
|
|
1dc85802e2 | ||
|
|
9e081579bb | ||
|
|
30dad5dfa1 | ||
|
|
6d32066055 | ||
|
|
86e5545c25 | ||
|
|
f4e80d51ff | ||
|
|
1db305af1c | ||
|
|
805b4e2dc2 | ||
|
|
e8e9948223 | ||
|
|
75441dcdc3 | ||
|
|
d30565f810 | ||
|
|
5c916b645b | ||
|
|
9ad184841e | ||
|
|
7536d7f94a | ||
|
|
ee0d3f9b34 | ||
|
|
d3cf815dbe | ||
|
|
b477c2adcc | ||
|
|
78d4aa3d01 | ||
|
|
855f5c8b81 | ||
|
|
7ab0f3beec | ||
|
|
ba8c9a9d1e | ||
|
|
87c1200c93 | ||
|
|
d46e71bea3 | ||
|
|
4cf2658235 | ||
|
|
5fa48e97b6 | ||
|
|
562fb0d14b | ||
|
|
320ecc69a0 | ||
|
|
106cf7a9f7 | ||
|
|
7221c6f156 | ||
|
|
4a7cdaecb4 | ||
|
|
81d58d2cc8 | ||
|
|
1080f5eba2 | ||
|
|
18e62ad136 | ||
|
|
f03aa1d0b5 | ||
|
|
ef63d47ecd | ||
|
|
0a58af8cbf | ||
|
|
8359f9683a | ||
|
|
c3425c05e9 | ||
|
|
3fa378533a | ||
|
|
4850bb5a59 | ||
|
|
037f536e7e | ||
|
|
287fbc5fb5 | ||
|
|
f553288db3 | ||
|
|
e0e386314f | ||
|
|
1de6a7a023 | ||
|
|
d1db4c29fa | ||
|
|
a488067a41 |
6
.github/workflows/ci_bench.yml
vendored
6
.github/workflows/ci_bench.yml
vendored
@@ -21,10 +21,10 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js 16.x'
|
||||
uses: actions/setup-node@v3
|
||||
- name: 'Install node.js 20.x'
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '16.x'
|
||||
node-version: '20.x'
|
||||
|
||||
- name: 'Install dependencies (Linux amd64)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
|
||||
6
.github/workflows/ci_packages.yml
vendored
6
.github/workflows/ci_packages.yml
vendored
@@ -32,10 +32,10 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js 16.x'
|
||||
uses: actions/setup-node@v3
|
||||
- name: 'Install node.js 20.x'
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '16.x'
|
||||
node-version: '20.x'
|
||||
|
||||
- name: 'Install dependencies (Linux amd64)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
|
||||
6
.github/workflows/ci_publish.yml
vendored
6
.github/workflows/ci_publish.yml
vendored
@@ -21,10 +21,10 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: 'Install node.js 16.x'
|
||||
uses: actions/setup-node@v3
|
||||
- name: 'Install node.js 20.x'
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '16.x'
|
||||
node-version: '20.x'
|
||||
|
||||
- name: 'Install dependencies (Linux amd64)'
|
||||
if: runner.os == 'Linux' && matrix.cpu == 'amd64'
|
||||
|
||||
@@ -898,6 +898,7 @@ type
|
||||
info*: TLineInfo
|
||||
when defined(nimsuggest):
|
||||
endInfo*: TLineInfo
|
||||
hasUserSpecifiedType*: bool # used for determining whether to display inlay type hints
|
||||
owner*: PSym
|
||||
flags*: TSymFlags
|
||||
ast*: PNode # syntax tree of proc, iterator, etc.:
|
||||
|
||||
@@ -1501,6 +1501,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
|
||||
getSeqPayloadType(p.module, seqtype),
|
||||
])
|
||||
else:
|
||||
if d.k == locNone: getTemp(p, e.typ, d, needsInit=false) # bug #22560
|
||||
putIntoDest(p, d, e, ropecg(p.module,
|
||||
"($1)#nimNewSeqOfCap($2, $3)", [
|
||||
getTypeDesc(p.module, seqtype),
|
||||
@@ -1550,6 +1551,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||
|
||||
var tmp: TLoc
|
||||
var r: Rope
|
||||
let needsZeroMem = p.config.selectedGC notin {gcArc, gcAtomicArc, gcOrc} or nfAllFieldsSet notin e.flags
|
||||
if useTemp:
|
||||
getTemp(p, t, tmp)
|
||||
r = rdLoc(tmp)
|
||||
@@ -1558,10 +1560,13 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||
t = t.lastSon.skipTypes(abstractInstOwned)
|
||||
r = "(*$1)" % [r]
|
||||
gcUsage(p.config, e)
|
||||
else:
|
||||
elif needsZeroMem:
|
||||
constructLoc(p, tmp)
|
||||
else:
|
||||
genObjectInit(p, cpsStmts, t, tmp, constructObj)
|
||||
else:
|
||||
resetLoc(p, d)
|
||||
if needsZeroMem: resetLoc(p, d)
|
||||
else: genObjectInit(p, cpsStmts, d.t, d, if isRef: constructRefObj else: constructObj)
|
||||
r = rdLoc(d)
|
||||
discard getTypeDesc(p.module, t)
|
||||
let ty = getUniqueType(t)
|
||||
|
||||
@@ -311,10 +311,10 @@ proc genLineDir(p: BProc, t: PNode) =
|
||||
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex != InvalidFileIdx:
|
||||
if freshLine:
|
||||
if lastFileIndex == t.info.fileIndex:
|
||||
linefmt(p, cpsStmts, "nimln_($1);\n",
|
||||
linefmt(p, cpsStmts, "nimln_($1);",
|
||||
[line])
|
||||
else:
|
||||
linefmt(p, cpsStmts, "nimlf_($1, $2);\n",
|
||||
linefmt(p, cpsStmts, "nimlf_($1, $2);",
|
||||
[line, quotedFilename(p.config, t.info)])
|
||||
|
||||
proc accessThreadLocalVar(p: BProc, s: PSym)
|
||||
@@ -986,11 +986,19 @@ proc closureSetup(p: BProc, prc: PSym) =
|
||||
linefmt(p, cpsStmts, "$1 = ($2) ClE_0;$n",
|
||||
[rdLoc(env.loc), getTypeDesc(p.module, env.typ)])
|
||||
|
||||
const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef,
|
||||
nkMacroDef, nkMixinStmt, nkBindStmt, nkFormalParams} +
|
||||
declarativeDefs
|
||||
|
||||
proc containsResult(n: PNode): bool =
|
||||
result = false
|
||||
case n.kind
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkFormalParams:
|
||||
of succ(nkEmpty)..pred(nkSym), succ(nkSym)..nkNilLit, harmless:
|
||||
discard
|
||||
of nkReturnStmt:
|
||||
for i in 0..<n.len:
|
||||
if containsResult(n[i]): return true
|
||||
result = n.len > 0 and n[0].kind == nkEmpty
|
||||
of nkSym:
|
||||
if n.sym.kind == skResult:
|
||||
result = true
|
||||
@@ -998,10 +1006,6 @@ proc containsResult(n: PNode): bool =
|
||||
for i in 0..<n.len:
|
||||
if containsResult(n[i]): return true
|
||||
|
||||
const harmless = {nkConstSection, nkTypeSection, nkEmpty, nkCommentStmt, nkTemplateDef,
|
||||
nkMacroDef, nkMixinStmt, nkBindStmt, nkFormalParams} +
|
||||
declarativeDefs
|
||||
|
||||
proc easyResultAsgn(n: PNode): PNode =
|
||||
case n.kind
|
||||
of nkStmtList, nkStmtListExpr:
|
||||
@@ -1175,7 +1179,13 @@ proc genProcAux*(m: BModule, prc: PSym) =
|
||||
# declare the result symbol:
|
||||
assignLocalVar(p, resNode)
|
||||
assert(res.loc.r != "")
|
||||
initLocalVar(p, res, immediateAsgn=false)
|
||||
if p.config.selectedGC in {gcArc, gcAtomicArc, gcOrc} and
|
||||
allPathsAsgnResult(procBody) == InitSkippable:
|
||||
# In an ideal world the codegen could rely on injectdestructors doing its job properly
|
||||
# and then the analysis step would not be required.
|
||||
discard "result init optimized out"
|
||||
else:
|
||||
initLocalVar(p, res, immediateAsgn=false)
|
||||
returnStmt = ropecg(p.module, "\treturn $1;$n", [rdLoc(res.loc)])
|
||||
elif sfConstructor in prc.flags:
|
||||
fillLoc(resNode.sym.loc, locParam, resNode, "this", OnHeap)
|
||||
|
||||
@@ -1723,7 +1723,7 @@ proc genOutFile(d: PDoc, groupedToc = false): string =
|
||||
"moduledesc", d.modDescFinal, "date", getDateStr(), "time", getClockStr(),
|
||||
"content", content, "author", d.meta[metaAuthor],
|
||||
"version", esc(d.target, d.meta[metaVersion]), "analytics", d.analytics,
|
||||
"deprecationMsg", d.modDeprecationMsg]
|
||||
"deprecationMsg", d.modDeprecationMsg, "nimVersion", $NimMajor & "." & $NimMinor & "." & $NimPatch]
|
||||
else:
|
||||
code = content
|
||||
result = code
|
||||
@@ -1907,7 +1907,7 @@ proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"")
|
||||
"title", "Index",
|
||||
"subtitle", "", "tableofcontents", "", "moduledesc", "",
|
||||
"date", getDateStr(), "time", getClockStr(),
|
||||
"content", content, "author", "", "version", "", "analytics", ""]
|
||||
"content", content, "author", "", "version", "", "analytics", "", "nimVersion", $NimMajor & "." & $NimMinor & "." & $NimPatch]
|
||||
# no analytics because context is not available
|
||||
|
||||
try:
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
# This include implements the high level optimization pass.
|
||||
# included from sem.nim
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
proc hlo(c: PContext, n: PNode): PNode
|
||||
|
||||
proc evalPattern(c: PContext, n, orig: PNode): PNode =
|
||||
|
||||
@@ -185,7 +185,9 @@ proc isCursor(n: PNode): bool =
|
||||
template isUnpackedTuple(n: PNode): bool =
|
||||
## we move out all elements of unpacked tuples,
|
||||
## hence unpacked tuples themselves don't need to be destroyed
|
||||
(n.kind == nkSym and n.sym.kind == skTemp and n.sym.typ.kind == tyTuple)
|
||||
## except it's already a cursor
|
||||
(n.kind == nkSym and n.sym.kind == skTemp and
|
||||
n.sym.typ.kind == tyTuple and sfCursor notin n.sym.flags)
|
||||
|
||||
proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string; inferredFromCopy = false) =
|
||||
var m = "'" & opname & "' is not available for type <" & typeToString(t) & ">"
|
||||
@@ -850,7 +852,9 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
|
||||
result[i][1] = p(n[i][1], c, s, m)
|
||||
else:
|
||||
result[i] = p(n[i], c, s, m)
|
||||
if mode == normal and isRefConstr:
|
||||
if mode == normal and (isRefConstr or (hasDestructor(c, t) and
|
||||
getAttachedOp(c.graph, t, attachedDestructor) != nil and
|
||||
sfOverridden in getAttachedOp(c.graph, t, attachedDestructor).flags)):
|
||||
result = ensureDestruction(result, n, c, s)
|
||||
of nkCallKinds:
|
||||
if n[0].kind == nkSym and n[0].sym.magic == mEnsureMove:
|
||||
|
||||
@@ -162,8 +162,7 @@ proc fillBodyObj(c: var TLiftCtx; n, body, x, y: PNode; enforceDefaultOp: bool)
|
||||
if c.filterDiscriminator != nil: return
|
||||
let f = n.sym
|
||||
let b = if c.kind == attachedTrace: y else: y.dotField(f)
|
||||
if (sfCursor in f.flags and f.typ.skipTypes(abstractInst).kind in {tyRef, tyProc} and
|
||||
c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcHooks}) or
|
||||
if (sfCursor in f.flags and c.g.config.selectedGC in {gcArc, gcAtomicArc, gcOrc, gcHooks}) or
|
||||
enforceDefaultOp:
|
||||
defaultOp(c, f.typ, body, x.dotField(f), b)
|
||||
else:
|
||||
|
||||
@@ -237,6 +237,9 @@ proc addField*(obj: PType; s: PSym; cache: IdentCache; idgen: IdGenerator): PSym
|
||||
field.itemId = ItemId(module: s.itemId.module, item: -s.itemId.item)
|
||||
let t = skipIntLit(s.typ, idgen)
|
||||
field.typ = t
|
||||
if s.kind in {skLet, skVar, skField, skForVar}:
|
||||
#field.bitsize = s.bitsize
|
||||
field.alignment = s.alignment
|
||||
assert t.kind != tyTyped
|
||||
propagateToOwner(obj, t)
|
||||
field.position = obj.n.len
|
||||
|
||||
@@ -57,6 +57,7 @@ type
|
||||
SymInfoPair* = object
|
||||
sym*: PSym
|
||||
info*: TLineInfo
|
||||
isDecl*: bool
|
||||
|
||||
PipelinePass* = enum
|
||||
NonePass
|
||||
|
||||
@@ -195,7 +195,7 @@ type
|
||||
IdeCmd* = enum
|
||||
ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideChkFile, ideMod,
|
||||
ideHighlight, ideOutline, ideKnown, ideMsg, ideProject, ideGlobalSymbols,
|
||||
ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand
|
||||
ideRecompile, ideChanged, ideType, ideDeclaration, ideExpand, ideInlayHints
|
||||
|
||||
Feature* = enum ## experimental features; DO NOT RENAME THESE!
|
||||
dotOperators,
|
||||
@@ -280,9 +280,24 @@ type
|
||||
version*: int
|
||||
endLine*: uint16
|
||||
endCol*: int
|
||||
inlayHintInfo*: SuggestInlayHint
|
||||
|
||||
Suggestions* = seq[Suggest]
|
||||
|
||||
SuggestInlayHintKind* = enum
|
||||
sihkType = "Type",
|
||||
sihkParameter = "Parameter"
|
||||
|
||||
SuggestInlayHint* = ref object
|
||||
kind*: SuggestInlayHintKind
|
||||
line*: int # Starts at 1
|
||||
column*: int # Starts at 0
|
||||
label*: string
|
||||
paddingLeft*: bool
|
||||
paddingRight*: bool
|
||||
allowInsert*: bool
|
||||
tooltip*: string
|
||||
|
||||
ProfileInfo* = object
|
||||
time*: float
|
||||
count*: int
|
||||
@@ -417,6 +432,8 @@ type
|
||||
expandNodeResult*: string
|
||||
expandPosition*: TLineInfo
|
||||
|
||||
clientProcessId*: int
|
||||
|
||||
|
||||
proc parseNimVersion*(a: string): NimVer =
|
||||
# could be moved somewhere reusable
|
||||
@@ -1057,6 +1074,7 @@ proc `$`*(c: IdeCmd): string =
|
||||
of ideRecompile: "recompile"
|
||||
of ideChanged: "changed"
|
||||
of ideType: "type"
|
||||
of ideInlayHints: "inlayHints"
|
||||
|
||||
proc floatInt64Align*(conf: ConfigRef): int16 =
|
||||
## Returns either 4 or 8 depending on reasons.
|
||||
|
||||
@@ -26,7 +26,10 @@ when not defined(leanCompiler):
|
||||
import spawn
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/formatfloat
|
||||
import std/[
|
||||
formatfloat,
|
||||
assertions,
|
||||
]
|
||||
|
||||
# implementation
|
||||
|
||||
@@ -206,12 +209,58 @@ proc commonType*(c: PContext; x, y: PType): PType =
|
||||
result.addSonSkipIntLit(r, c.idgen)
|
||||
|
||||
proc endsInNoReturn(n: PNode): bool =
|
||||
# check if expr ends in raise exception or call of noreturn proc
|
||||
## 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
|
||||
result = it.kind in nkLastBlockStmts or
|
||||
it.kind in nkCallKinds and it[0].kind == nkSym and sfNoReturn in it[0].sym.flags
|
||||
|
||||
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:
|
||||
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"
|
||||
# none of the branches returned
|
||||
result = true
|
||||
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
|
||||
@@ -462,7 +511,13 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
|
||||
# we now know the supplied arguments
|
||||
var paramTypes = newIdTable()
|
||||
for param, value in genericParamsInMacroCall(s, call):
|
||||
idTablePut(paramTypes, param.typ, value.typ)
|
||||
var givenType = value.typ
|
||||
# the sym nodes used for the supplied generic arguments for
|
||||
# templates and macros leave type nil so regular sem can handle it
|
||||
# in this case, get the type directly from the sym
|
||||
if givenType == nil and value.kind == nkSym and value.sym.typ != nil:
|
||||
givenType = value.sym.typ
|
||||
idTablePut(paramTypes, param.typ, givenType)
|
||||
|
||||
retType = generateTypeInstance(c, paramTypes,
|
||||
macroResult.info, retType)
|
||||
|
||||
@@ -595,7 +595,12 @@ proc semResolvedCall(c: PContext, x: TCandidate,
|
||||
else:
|
||||
x.call.add c.graph.emptyNode
|
||||
of skType:
|
||||
x.call.add newSymNode(s, n.info)
|
||||
var tn = newSymNode(s, n.info)
|
||||
# this node will be used in template substitution,
|
||||
# pretend this is an untyped node and let regular sem handle the type
|
||||
# to prevent problems where a generic parameter is treated as a value
|
||||
tn.typ = nil
|
||||
x.call.add tn
|
||||
else:
|
||||
internalAssert c.config, false
|
||||
|
||||
@@ -665,14 +670,18 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
||||
onUse(info, s)
|
||||
result = newSymNode(newInst, info)
|
||||
|
||||
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
assert n.kind == nkBracketExpr
|
||||
proc setGenericParams(c: PContext, n: PNode) =
|
||||
## sems generic params in subscript expression
|
||||
for i in 1..<n.len:
|
||||
let e = semExprWithType(c, n[i])
|
||||
if e.typ == nil:
|
||||
n[i].typ = errorType(c)
|
||||
else:
|
||||
n[i].typ = e.typ.skipTypes({tyTypeDesc})
|
||||
|
||||
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||
assert n.kind == nkBracketExpr
|
||||
setGenericParams(c, n)
|
||||
var s = s
|
||||
var a = n[0]
|
||||
if a.kind == nkSym:
|
||||
|
||||
@@ -996,10 +996,6 @@ proc bracketedMacro(n: PNode): PSym =
|
||||
if result.kind notin {skMacro, skTemplate}:
|
||||
result = nil
|
||||
|
||||
proc setGenericParams(c: PContext, n: PNode) =
|
||||
for i in 1..<n.len:
|
||||
n[i].typ = semTypeNode(c, n[i], nil)
|
||||
|
||||
proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags; expectedType: PType = nil): PNode =
|
||||
if efNoSemCheck notin flags and n.typ != nil and n.typ.kind == tyError:
|
||||
return errorNode(c, n)
|
||||
@@ -1106,7 +1102,6 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags; expectedType: PType
|
||||
msg.addDeclaredLocMaybe(c.config, typ)
|
||||
localError(c.config, n.info, msg)
|
||||
return errorNode(c, n)
|
||||
result = nil
|
||||
else:
|
||||
result = m.call
|
||||
instGenericConvertersSons(c, result, m)
|
||||
@@ -2244,7 +2239,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||
for i in 1..<ids.len:
|
||||
let exp = semExprWithType(c, quotes[i+1], {})
|
||||
let typ = exp.typ
|
||||
if tfTriggersCompileTime notin typ.flags and exp.kind == nkSym and exp.sym.kind notin routineKinds + {skType}:
|
||||
if tfTriggersCompileTime notin typ.flags and typ.kind != tyStatic and exp.kind == nkSym and exp.sym.kind notin routineKinds + {skType}:
|
||||
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[i], newNodeIT(nkType, n.info, typ), c.graph.emptyNode)
|
||||
else:
|
||||
dummyTemplate[paramsPos].add newTreeI(nkIdentDefs, n.info, ids[i], getSysSym(c.graph, n.info, "typed").newSymNode, c.graph.emptyNode)
|
||||
|
||||
@@ -167,6 +167,17 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||
elif s.isMixedIn:
|
||||
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
||||
else:
|
||||
if s.kind == skType and candidates.len > 1:
|
||||
var ambig = false
|
||||
let s2 = searchInScopes(c, ident, ambig)
|
||||
if ambig:
|
||||
# this is a type conversion like a.T where T is ambiguous with
|
||||
# other types or routines
|
||||
# in regular code, this never considers a type conversion and
|
||||
# skips to routine overloading
|
||||
# so symchoices are used which behave similarly with type symbols
|
||||
result = newDot(result, symChoice(c, n, s, scForceOpen))
|
||||
return
|
||||
let syms = semGenericStmtSymbol(c, n, s, ctx, flags, fromDotExpr=true)
|
||||
result = newDot(result, syms)
|
||||
|
||||
|
||||
@@ -668,7 +668,8 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
result.typ = expectedType # type inference for empty sequence # bug #21377
|
||||
of mEnsureMove:
|
||||
result = n
|
||||
if isAssignable(c, n[1]) notin {arLValue, arLocalLValue}:
|
||||
localError(c.config, n.info, "'" & $n[1] & "'" & " is not a mutable location; it cannot be moved")
|
||||
if n[1].kind in {nkStmtListExpr, nkBlockExpr,
|
||||
nkIfExpr, nkCaseStmt, nkTryStmt}:
|
||||
localError(c.config, n.info, "Nested expressions cannot be moved: '" & $n[1] & "'")
|
||||
else:
|
||||
result = n
|
||||
|
||||
@@ -656,9 +656,11 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
addToVarSection(c, result, b)
|
||||
continue
|
||||
|
||||
var hasUserSpecifiedType = false
|
||||
var typ: PType = nil
|
||||
if a[^2].kind != nkEmpty:
|
||||
typ = semTypeNode(c, a[^2], nil)
|
||||
hasUserSpecifiedType = true
|
||||
|
||||
var typFlags: TTypeAllowedFlags
|
||||
|
||||
@@ -730,6 +732,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
addToVarSection(c, result, n, a)
|
||||
continue
|
||||
var v = semIdentDef(c, a[j], symkind, false)
|
||||
when defined(nimsuggest):
|
||||
v.hasUserSpecifiedType = hasUserSpecifiedType
|
||||
styleCheckDef(c, v)
|
||||
onDef(a[j].info, v)
|
||||
if sfGenSym notin v.flags:
|
||||
@@ -803,9 +807,11 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||
addToVarSection(c, result, b)
|
||||
continue
|
||||
|
||||
var hasUserSpecifiedType = false
|
||||
var typ: PType = nil
|
||||
if a[^2].kind != nkEmpty:
|
||||
typ = semTypeNode(c, a[^2], nil)
|
||||
hasUserSpecifiedType = true
|
||||
|
||||
var typFlags: TTypeAllowedFlags
|
||||
|
||||
@@ -846,6 +852,8 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||
else:
|
||||
for j in 0..<a.len-2:
|
||||
var v = semIdentDef(c, a[j], skConst)
|
||||
when defined(nimsuggest):
|
||||
v.hasUserSpecifiedType = hasUserSpecifiedType
|
||||
if sfGenSym notin v.flags: addInterfaceDecl(c, v)
|
||||
elif v.owner == nil: v.owner = getCurrOwner(c)
|
||||
styleCheckDef(c, v)
|
||||
@@ -2613,9 +2621,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags, expectedType: PType =
|
||||
var m = n[i]
|
||||
while m.kind in {nkStmtListExpr, nkStmtList} and m.len > 0: # from templates
|
||||
m = m.lastSon
|
||||
if m.kind in nkLastBlockStmts or
|
||||
m.kind in nkCallKinds and m[0].kind == nkSym and
|
||||
sfNoReturn in m[0].sym.flags:
|
||||
if endsInNoReturn(m):
|
||||
for j in i + 1..<n.len:
|
||||
case n[j].kind
|
||||
of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkState: discard
|
||||
|
||||
@@ -566,6 +566,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||
# so we use the generic code for nkDotExpr too
|
||||
let s = qualifiedLookUp(c.c, n, {})
|
||||
if s != nil:
|
||||
# mirror the nkIdent case
|
||||
# do not symchoice a quoted template parameter (bug #2390):
|
||||
if s.owner == c.owner and s.kind == skParam and
|
||||
n.kind == nkAccQuoted and n.len == 1:
|
||||
@@ -577,7 +578,9 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||
elif contains(c.toMixin, s.name.id):
|
||||
return symChoice(c.c, n, s, scForceOpen, c.noGenSym > 0)
|
||||
else:
|
||||
return symChoice(c.c, n, s, scOpen, c.noGenSym > 0)
|
||||
if s.kind in {skType, skVar, skLet, skConst}:
|
||||
discard qualifiedLookUp(c.c, n, {checkAmbiguity, checkModule})
|
||||
return semTemplSymbol(c.c, n, s, c.noGenSym > 0)
|
||||
if n.kind == nkDotExpr:
|
||||
result = n
|
||||
result[0] = semTemplBody(c, n[0])
|
||||
@@ -673,6 +676,9 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||
# a template's parameters are not gensym'ed even if that was originally the
|
||||
# case as we determine whether it's a template parameter in the template
|
||||
# body by the absence of the sfGenSym flag:
|
||||
let retType = s.typ[0]
|
||||
if retType != nil and retType.kind != tyUntyped:
|
||||
allUntyped = false
|
||||
for i in 1..<s.typ.n.len:
|
||||
let param = s.typ.n[i].sym
|
||||
if param.name.id != ord(wUnderscore):
|
||||
|
||||
@@ -141,6 +141,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||
result.n.add symNode
|
||||
styleCheckDef(c, e)
|
||||
onDef(e.info, e)
|
||||
suggestSym(c.graph, e.info, e, c.graph.usageSym)
|
||||
if sfGenSym notin e.flags:
|
||||
if not isPure:
|
||||
addInterfaceOverloadableSymAt(c, c.currentScope, e)
|
||||
|
||||
@@ -46,7 +46,8 @@ proc searchInstTypes*(g: ModuleGraph; key: PType): PType =
|
||||
# XXX: This happens for prematurely cached
|
||||
# types such as Channel[empty]. Why?
|
||||
# See the notes for PActor in handleGenericInvocation
|
||||
return
|
||||
# if this is return the same type gets cached more than it needs to
|
||||
continue
|
||||
if not sameFlags(inst, key):
|
||||
continue
|
||||
|
||||
@@ -204,7 +205,7 @@ proc hasValuelessStatics(n: PNode): bool =
|
||||
a
|
||||
proc doThing(_: MyThing)
|
||||
]#
|
||||
if n.safeLen == 0:
|
||||
if n.safeLen == 0 and n.kind != nkEmpty: # Some empty nodes can get in here
|
||||
n.typ == nil or n.typ.kind == tyStatic
|
||||
else:
|
||||
for x in n:
|
||||
|
||||
@@ -1207,7 +1207,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||
of tyArray:
|
||||
var fRange = f[0]
|
||||
var aRange = a[0]
|
||||
if fRange.kind == tyGenericParam:
|
||||
if fRange.kind in {tyGenericParam, tyAnything}:
|
||||
var prev = PType(idTableGet(c.bindings, fRange))
|
||||
if prev == nil:
|
||||
put(c, fRange, a[0])
|
||||
@@ -1536,6 +1536,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
|
||||
if x.kind == tyGenericInvocation:
|
||||
if f[0] == x[0]:
|
||||
for i in 1..<f.len:
|
||||
# Handle when checking against a generic that isn't fully instantiated
|
||||
if i >= x.len: return
|
||||
let tr = typeRel(c, f[i], x[i], flags)
|
||||
if tr <= isSubtype: return
|
||||
result = isGeneric
|
||||
|
||||
@@ -81,7 +81,16 @@ proc cmpSuggestions(a, b: Suggest): int =
|
||||
# independent of hashing order:
|
||||
result = cmp(a.name[], b.name[])
|
||||
|
||||
proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int =
|
||||
proc scanForTrailingAsterisk(line: string, start: int): int =
|
||||
result = 0
|
||||
while start+result < line.len and line[start+result] in {' ', '\t'}:
|
||||
inc result
|
||||
if start+result < line.len and line[start+result] == '*':
|
||||
inc result
|
||||
else:
|
||||
result = 0
|
||||
|
||||
proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo; skipTrailingAsterisk: bool = false): int =
|
||||
let
|
||||
line = sourceLine(conf, info)
|
||||
column = toColumn(info)
|
||||
@@ -103,8 +112,10 @@ proc getTokenLenFromSource(conf: ConfigRef; ident: string; info: TLineInfo): int
|
||||
result = 0
|
||||
elif ident[0] in linter.Letters and ident[^1] != '=':
|
||||
result = identLen(line, column)
|
||||
if cmpIgnoreStyle(line[column..column + result - 1], ident) != 0:
|
||||
if cmpIgnoreStyle(line[column..column + result - 1], ident[0..min(result-1,len(ident)-1)]) != 0:
|
||||
result = 0
|
||||
if skipTrailingAsterisk and result > 0:
|
||||
result += scanForTrailingAsterisk(line, column + result)
|
||||
else:
|
||||
var sourceIdent: string
|
||||
result = parseWhile(line, sourceIdent,
|
||||
@@ -154,7 +165,10 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info
|
||||
result.qualifiedPath.add(s.name.s)
|
||||
|
||||
if s.typ != nil:
|
||||
result.forth = typeToString(s.typ)
|
||||
if section == ideInlayHints:
|
||||
result.forth = typeToString(s.typ, preferInlayHint)
|
||||
else:
|
||||
result.forth = typeToString(s.typ)
|
||||
else:
|
||||
result.forth = ""
|
||||
when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
|
||||
@@ -173,58 +187,90 @@ proc symToSuggest*(g: ModuleGraph; s: PSym, isLocal: bool, section: IdeCmd, info
|
||||
result.filePath = toFullPath(g.config, infox)
|
||||
result.line = toLinenumber(infox)
|
||||
result.column = toColumn(infox)
|
||||
result.tokenLen = if section != ideHighlight:
|
||||
result.tokenLen = if section notin {ideHighlight, ideInlayHints}:
|
||||
s.name.s.len
|
||||
else:
|
||||
getTokenLenFromSource(g.config, s.name.s, infox)
|
||||
getTokenLenFromSource(g.config, s.name.s, infox, section == ideInlayHints)
|
||||
result.version = g.config.suggestVersion
|
||||
result.endLine = endLine
|
||||
result.endCol = endCol
|
||||
|
||||
proc `$`*(suggest: Suggest): string =
|
||||
result = $suggest.section
|
||||
proc `$`*(suggest: SuggestInlayHint): string =
|
||||
result = $suggest.kind
|
||||
result.add(sep)
|
||||
if suggest.section == ideHighlight:
|
||||
if suggest.symkind.TSymKind == skVar and suggest.isGlobal:
|
||||
result.add("skGlobalVar")
|
||||
elif suggest.symkind.TSymKind == skLet and suggest.isGlobal:
|
||||
result.add("skGlobalLet")
|
||||
result.add($suggest.line)
|
||||
result.add(sep)
|
||||
result.add($suggest.column)
|
||||
result.add(sep)
|
||||
result.add(suggest.label)
|
||||
result.add(sep)
|
||||
result.add($suggest.paddingLeft)
|
||||
result.add(sep)
|
||||
result.add($suggest.paddingRight)
|
||||
result.add(sep)
|
||||
result.add($suggest.allowInsert)
|
||||
result.add(sep)
|
||||
result.add(suggest.tooltip)
|
||||
|
||||
proc `$`*(suggest: Suggest): string =
|
||||
if suggest.section == ideInlayHints:
|
||||
result = $suggest.inlayHintInfo
|
||||
else:
|
||||
result = $suggest.section
|
||||
result.add(sep)
|
||||
if suggest.section == ideHighlight:
|
||||
if suggest.symkind.TSymKind == skVar and suggest.isGlobal:
|
||||
result.add("skGlobalVar")
|
||||
elif suggest.symkind.TSymKind == skLet and suggest.isGlobal:
|
||||
result.add("skGlobalLet")
|
||||
else:
|
||||
result.add($suggest.symkind.TSymKind)
|
||||
result.add(sep)
|
||||
result.add($suggest.line)
|
||||
result.add(sep)
|
||||
result.add($suggest.column)
|
||||
result.add(sep)
|
||||
result.add($suggest.tokenLen)
|
||||
else:
|
||||
result.add($suggest.symkind.TSymKind)
|
||||
result.add(sep)
|
||||
result.add($suggest.line)
|
||||
result.add(sep)
|
||||
result.add($suggest.column)
|
||||
result.add(sep)
|
||||
result.add($suggest.tokenLen)
|
||||
else:
|
||||
result.add($suggest.symkind.TSymKind)
|
||||
result.add(sep)
|
||||
if suggest.qualifiedPath.len != 0:
|
||||
result.add(suggest.qualifiedPath.join("."))
|
||||
result.add(sep)
|
||||
result.add(suggest.forth)
|
||||
result.add(sep)
|
||||
result.add(suggest.filePath)
|
||||
result.add(sep)
|
||||
result.add($suggest.line)
|
||||
result.add(sep)
|
||||
result.add($suggest.column)
|
||||
result.add(sep)
|
||||
when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
|
||||
result.add(suggest.doc.escape)
|
||||
if suggest.version == 0 or suggest.version == 3:
|
||||
result.add(sep)
|
||||
result.add($suggest.quality)
|
||||
if suggest.section == ideSug:
|
||||
if suggest.qualifiedPath.len != 0:
|
||||
result.add(suggest.qualifiedPath.join("."))
|
||||
result.add(sep)
|
||||
result.add(suggest.forth)
|
||||
result.add(sep)
|
||||
result.add(suggest.filePath)
|
||||
result.add(sep)
|
||||
result.add($suggest.line)
|
||||
result.add(sep)
|
||||
result.add($suggest.column)
|
||||
result.add(sep)
|
||||
when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
|
||||
result.add(suggest.doc.escape)
|
||||
if suggest.version == 0 or suggest.version == 3:
|
||||
result.add(sep)
|
||||
result.add($suggest.prefix)
|
||||
result.add($suggest.quality)
|
||||
if suggest.section == ideSug:
|
||||
result.add(sep)
|
||||
result.add($suggest.prefix)
|
||||
|
||||
if (suggest.version == 3 and suggest.section in {ideOutline, ideExpand}):
|
||||
result.add(sep)
|
||||
result.add($suggest.endLine)
|
||||
result.add(sep)
|
||||
result.add($suggest.endCol)
|
||||
if (suggest.version == 3 and suggest.section in {ideOutline, ideExpand}):
|
||||
result.add(sep)
|
||||
result.add($suggest.endLine)
|
||||
result.add(sep)
|
||||
result.add($suggest.endCol)
|
||||
|
||||
proc suggestToSuggestInlayHint*(sug: Suggest): SuggestInlayHint =
|
||||
SuggestInlayHint(
|
||||
kind: sihkType,
|
||||
line: sug.line,
|
||||
column: sug.column + sug.tokenLen,
|
||||
label: ": " & sug.forth,
|
||||
paddingLeft: false,
|
||||
paddingRight: false,
|
||||
allowInsert: true,
|
||||
tooltip: ""
|
||||
)
|
||||
|
||||
proc suggestResult*(conf: ConfigRef; s: Suggest) =
|
||||
if not isNil(conf.suggestionResultHook):
|
||||
@@ -507,7 +553,7 @@ proc findDefinition(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym
|
||||
if s.isNil: return
|
||||
if isTracked(info, g.config.m.trackPos, s.name.s.len) or (s == usageSym and sfForward notin s.flags):
|
||||
suggestResult(g.config, symToSuggest(g, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0, useSuppliedInfo = s == usageSym))
|
||||
if sfForward notin s.flags and g.config.suggestVersion != 3:
|
||||
if sfForward notin s.flags and g.config.suggestVersion < 3:
|
||||
suggestQuit()
|
||||
else:
|
||||
usageSym = s
|
||||
@@ -522,7 +568,7 @@ proc suggestSym*(g: ModuleGraph; info: TLineInfo; s: PSym; usageSym: var PSym; i
|
||||
## misnamed: should be 'symDeclared'
|
||||
let conf = g.config
|
||||
when defined(nimsuggest):
|
||||
g.suggestSymbols.mgetOrPut(info.fileIndex, @[]).add SymInfoPair(sym: s, info: info)
|
||||
g.suggestSymbols.mgetOrPut(info.fileIndex, @[]).add SymInfoPair(sym: s, info: info, isDecl: isDecl)
|
||||
|
||||
if conf.suggestVersion == 0:
|
||||
if s.allUsages.len == 0:
|
||||
@@ -711,7 +757,7 @@ proc suggestSentinel*(c: PContext) =
|
||||
|
||||
when defined(nimsuggest):
|
||||
proc onDef(graph: ModuleGraph, s: PSym, info: TLineInfo) =
|
||||
if graph.config.suggestVersion == 3 and info.exactEquals(s.info):
|
||||
if graph.config.suggestVersion >= 3 and info.exactEquals(s.info):
|
||||
suggestSym(graph, info, s, graph.usageSym)
|
||||
|
||||
template getPContext(): untyped =
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
import
|
||||
intsets, ast, astalgo, trees, msgs, strutils, platform, renderer, options,
|
||||
lineinfos, int128, modulegraphs, astmsgs
|
||||
lineinfos, int128, modulegraphs, astmsgs, wordrecg
|
||||
|
||||
when defined(nimPreviewSlimSystem):
|
||||
import std/[assertions, formatfloat]
|
||||
@@ -28,6 +28,7 @@ type
|
||||
preferMixed,
|
||||
# most useful, shows: symbol + resolved symbols if it differs, e.g.:
|
||||
# tuple[a: MyInt{int}, b: float]
|
||||
preferInlayHint,
|
||||
|
||||
TTypeRelation* = enum # order is important!
|
||||
isNone, isConvertible,
|
||||
@@ -508,7 +509,7 @@ const
|
||||
"void", "iterable"]
|
||||
|
||||
const preferToResolveSymbols = {preferName, preferTypeName, preferModuleInfo,
|
||||
preferGenericArg, preferResolved, preferMixed}
|
||||
preferGenericArg, preferResolved, preferMixed, preferInlayHint}
|
||||
|
||||
template bindConcreteTypeToUserTypeClass*(tc, concrete: PType) =
|
||||
tc.add concrete
|
||||
@@ -542,7 +543,10 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
if prefer in preferToResolveSymbols and t.sym != nil and
|
||||
sfAnon notin t.sym.flags and t.kind != tySequence:
|
||||
if t.kind == tyInt and isIntLit(t):
|
||||
result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
|
||||
if prefer == preferInlayHint:
|
||||
result = t.sym.name.s
|
||||
else:
|
||||
result = t.sym.name.s & " literal(" & $t.n.intVal & ")"
|
||||
elif t.kind == tyAlias and t[0].kind != tyAlias:
|
||||
result = typeToString(t[0])
|
||||
elif prefer in {preferResolved, preferMixed}:
|
||||
@@ -558,7 +562,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
result = t.sym.name.s
|
||||
if prefer == preferMixed and result != t.sym.name.s:
|
||||
result = t.sym.name.s & "{" & result & "}"
|
||||
elif prefer in {preferName, preferTypeName} or t.sym.owner.isNil:
|
||||
elif prefer in {preferName, preferTypeName, preferInlayHint} or t.sym.owner.isNil:
|
||||
# note: should probably be: {preferName, preferTypeName, preferGenericArg}
|
||||
result = t.sym.name.s
|
||||
if t.kind == tyGenericParam and t.len > 0:
|
||||
@@ -577,8 +581,11 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
if not isIntLit(t) or prefer == preferExported:
|
||||
result = typeToStr[t.kind]
|
||||
else:
|
||||
if prefer == preferGenericArg:
|
||||
case prefer:
|
||||
of preferGenericArg:
|
||||
result = $t.n.intVal
|
||||
of preferInlayHint:
|
||||
result = "int"
|
||||
else:
|
||||
result = "int literal(" & $t.n.intVal & ")"
|
||||
of tyGenericInst, tyGenericInvocation:
|
||||
@@ -751,6 +758,14 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
result.add(')')
|
||||
if t.len > 0 and t[0] != nil: result.add(": " & typeToString(t[0]))
|
||||
var prag = if t.callConv == ccNimCall and tfExplicitCallConv notin t.flags: "" else: $t.callConv
|
||||
if not isNil(t.owner) and not isNil(t.owner.ast) and (t.owner.ast.len - 1) >= pragmasPos:
|
||||
let pragmasNode = t.owner.ast[pragmasPos]
|
||||
let raisesSpec = effectSpec(pragmasNode, wRaises)
|
||||
if not isNil(raisesSpec):
|
||||
addSep(prag)
|
||||
prag.add("raises: ")
|
||||
prag.add($raisesSpec)
|
||||
|
||||
if tfNoSideEffect in t.flags:
|
||||
addSep(prag)
|
||||
prag.add("noSideEffect")
|
||||
|
||||
@@ -1015,7 +1015,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of opcLenCstring:
|
||||
decodeBImm(rkInt)
|
||||
assert regs[rb].kind == rkNode
|
||||
regs[ra].intVal = regs[rb].node.strVal.cstring.len - imm
|
||||
if regs[rb].node.kind == nkNilLit:
|
||||
regs[ra].intVal = -imm
|
||||
else:
|
||||
regs[ra].intVal = regs[rb].node.strVal.cstring.len - imm
|
||||
of opcIncl:
|
||||
decodeB(rkNode)
|
||||
let b = regs[rb].regToNode
|
||||
@@ -1213,6 +1216,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of opcEqStr:
|
||||
decodeBC(rkInt)
|
||||
regs[ra].intVal = ord(regs[rb].node.strVal == regs[rc].node.strVal)
|
||||
of opcEqCString:
|
||||
decodeBC(rkInt)
|
||||
let bNil = regs[rb].node.kind == nkNilLit
|
||||
let cNil = regs[rc].node.kind == nkNilLit
|
||||
regs[ra].intVal = ord((bNil and cNil) or
|
||||
(not bNil and not cNil and regs[rb].node.strVal == regs[rc].node.strVal))
|
||||
of opcLeStr:
|
||||
decodeBC(rkInt)
|
||||
regs[ra].intVal = ord(regs[rb].node.strVal <= regs[rc].node.strVal)
|
||||
@@ -1496,7 +1505,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
regs[ra].node
|
||||
c.currentExceptionA = raised
|
||||
# Set the `name` field of the exception
|
||||
c.currentExceptionA[2].skipColon.strVal = c.currentExceptionA.typ.sym.name.s
|
||||
var exceptionNameNode = newStrNode(nkStrLit, c.currentExceptionA.typ.sym.name.s)
|
||||
if c.currentExceptionA[2].kind == nkExprColonExpr:
|
||||
exceptionNameNode.typ = c.currentExceptionA[2][1].typ
|
||||
c.currentExceptionA[2][1] = exceptionNameNode
|
||||
else:
|
||||
exceptionNameNode.typ = c.currentExceptionA[2].typ
|
||||
c.currentExceptionA[2] = exceptionNameNode
|
||||
c.exceptionInstr = pc
|
||||
|
||||
var frame = tos
|
||||
|
||||
@@ -99,7 +99,7 @@ type
|
||||
opcLeFloat, opcLtFloat, opcLeu, opcLtu,
|
||||
opcEqRef, opcEqNimNode, opcSameNodeType,
|
||||
opcXor, opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt,
|
||||
opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
|
||||
opcEqStr, opcEqCString, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
|
||||
opcMulSet, opcPlusSet, opcMinusSet, opcConcatStr,
|
||||
opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
|
||||
opcIsNil, opcOf, opcIs,
|
||||
|
||||
@@ -406,13 +406,19 @@ proc genIf(c: PCtx, n: PNode; dest: var TDest) =
|
||||
c.gen(it[0], tmp)
|
||||
elsePos = c.xjmp(it[0], opcFJmp, tmp) # if false
|
||||
c.clearDest(n, dest)
|
||||
c.gen(it[1], dest) # then part
|
||||
if isEmptyType(it[1].typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(it[1])
|
||||
else:
|
||||
c.gen(it[1], dest) # then part
|
||||
if i < n.len-1:
|
||||
endings.add(c.xjmp(it[1], opcJmp, 0))
|
||||
c.patch(elsePos)
|
||||
else:
|
||||
c.clearDest(n, dest)
|
||||
c.gen(it[0], dest)
|
||||
if isEmptyType(it[0].typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(it[0])
|
||||
else:
|
||||
c.gen(it[0], dest)
|
||||
for endPos in endings: c.patch(endPos)
|
||||
c.clearDest(n, dest)
|
||||
|
||||
@@ -506,17 +512,25 @@ proc genCase(c: PCtx; n: PNode; dest: var TDest) =
|
||||
let it = n[i]
|
||||
if it.len == 1:
|
||||
# else stmt:
|
||||
if it[0].kind != nkNilLit or it[0].typ != nil:
|
||||
let body = it[0]
|
||||
if body.kind != nkNilLit or body.typ != nil:
|
||||
# an nkNilLit with nil for typ implies there is no else branch, this
|
||||
# avoids unused related errors as we've already consumed the dest
|
||||
c.gen(it[0], dest)
|
||||
if isEmptyType(body.typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(body)
|
||||
else:
|
||||
c.gen(body, dest)
|
||||
else:
|
||||
let b = rawGenLiteral(c, it)
|
||||
c.gABx(it, opcBranch, tmp, b)
|
||||
let elsePos = c.xjmp(it.lastSon, opcFJmp, tmp)
|
||||
c.gen(it.lastSon, dest)
|
||||
let body = it.lastSon
|
||||
let elsePos = c.xjmp(body, opcFJmp, tmp)
|
||||
if isEmptyType(body.typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(body)
|
||||
else:
|
||||
c.gen(body, dest)
|
||||
if i < n.len-1:
|
||||
endings.add(c.xjmp(it.lastSon, opcJmp, 0))
|
||||
endings.add(c.xjmp(body, opcJmp, 0))
|
||||
c.patch(elsePos)
|
||||
c.clearDest(n, dest)
|
||||
for endPos in endings: c.patch(endPos)
|
||||
@@ -532,7 +546,10 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
|
||||
if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
|
||||
var endings: seq[TPosition] = @[]
|
||||
let ehPos = c.xjmp(n, opcTry, 0)
|
||||
c.gen(n[0], dest)
|
||||
if isEmptyType(n[0].typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(n[0])
|
||||
else:
|
||||
c.gen(n[0], dest)
|
||||
c.clearDest(n, dest)
|
||||
# Add a jump past the exception handling code
|
||||
let jumpToFinally = c.xjmp(n, opcJmp, 0)
|
||||
@@ -550,7 +567,11 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
|
||||
if it.len == 1:
|
||||
# general except section:
|
||||
c.gABx(it, opcExcept, 0, 0)
|
||||
c.gen(it.lastSon, dest)
|
||||
let body = it.lastSon
|
||||
if isEmptyType(body.typ): # maybe noreturn call, don't touch `dest`
|
||||
c.gen(body)
|
||||
else:
|
||||
c.gen(body, dest)
|
||||
c.clearDest(n, dest)
|
||||
if i < n.len:
|
||||
endings.add(c.xjmp(it, opcJmp, 0))
|
||||
@@ -882,6 +903,8 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
|
||||
let dst = n[0].typ.skipTypes(abstractRange)#.kind
|
||||
let srcSize = getSize(c.config, src)
|
||||
let dstSize = getSize(c.config, dst)
|
||||
const unsupportedCastDifferentSize =
|
||||
"VM does not support 'cast' from $1 with size $2 to $3 with size $4 due to different sizes"
|
||||
if src.kind in allowedIntegers and dst.kind in allowedIntegers:
|
||||
let tmp = c.genx(n[1])
|
||||
if dest < 0: dest = c.getTemp(n[0].typ)
|
||||
@@ -898,8 +921,11 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
|
||||
# is smaller than source.
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(dstSize*8))
|
||||
c.freeTemp(tmp)
|
||||
elif srcSize == dstSize and src.kind in allowedIntegers and
|
||||
dst.kind in {tyFloat, tyFloat32, tyFloat64}:
|
||||
elif src.kind in allowedIntegers and
|
||||
dst.kind in {tyFloat, tyFloat32, tyFloat64}:
|
||||
if srcSize != dstSize:
|
||||
globalError(c.config, n.info, unsupportedCastDifferentSize %
|
||||
[$src.kind, $srcSize, $dst.kind, $dstSize])
|
||||
let tmp = c.genx(n[1])
|
||||
if dest < 0: dest = c.getTemp(n[0].typ)
|
||||
if dst.kind == tyFloat32:
|
||||
@@ -908,8 +934,11 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
|
||||
c.gABC(n, opcCastIntToFloat64, dest, tmp)
|
||||
c.freeTemp(tmp)
|
||||
|
||||
elif srcSize == dstSize and src.kind in {tyFloat, tyFloat32, tyFloat64} and
|
||||
elif src.kind in {tyFloat, tyFloat32, tyFloat64} and
|
||||
dst.kind in allowedIntegers:
|
||||
if srcSize != dstSize:
|
||||
globalError(c.config, n.info, unsupportedCastDifferentSize %
|
||||
[$src.kind, $srcSize, $dst.kind, $dstSize])
|
||||
let tmp = c.genx(n[1])
|
||||
if dest < 0: dest = c.getTemp(n[0].typ)
|
||||
if src.kind == tyFloat32:
|
||||
@@ -1151,7 +1180,8 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
|
||||
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
|
||||
genConv(c, n, n[1], dest)
|
||||
of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr)
|
||||
of mEqStr: genBinaryABC(c, n, dest, opcEqStr)
|
||||
of mEqCString: genBinaryABC(c, n, dest, opcEqCString)
|
||||
of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
|
||||
of mLtStr: genBinaryABC(c, n, dest, opcLtStr)
|
||||
of mEqSet: genBinarySet(c, n, dest, opcEqSet)
|
||||
@@ -1525,6 +1555,7 @@ proc checkCanEval(c: PCtx; n: PNode) =
|
||||
# little hack ahead for bug #12612: assume gensym'ed variables
|
||||
# are in the right scope:
|
||||
if sfGenSym in s.flags and c.prc.sym == nil: discard
|
||||
elif s.kind == skParam and s.typ.kind == tyTypeDesc: discard
|
||||
else: cannotEval(c, n)
|
||||
elif s.kind in {skProc, skFunc, skConverter, skMethod,
|
||||
skIterator} and sfForward in s.flags:
|
||||
@@ -1864,10 +1895,10 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
|
||||
result = newNodeIT(nkUIntLit, info, t)
|
||||
of tyFloat..tyFloat128:
|
||||
result = newNodeIT(nkFloatLit, info, t)
|
||||
of tyCstring, tyString:
|
||||
of tyString:
|
||||
result = newNodeIT(nkStrLit, info, t)
|
||||
result.strVal = ""
|
||||
of tyVar, tyLent, tyPointer, tyPtr, tyUntyped,
|
||||
of tyCstring, tyVar, tyLent, tyPointer, tyPtr, tyUntyped,
|
||||
tyTyped, tyTypeDesc, tyRef, tyNil:
|
||||
result = newNodeIT(nkNilLit, info, t)
|
||||
of tyProc:
|
||||
@@ -2079,8 +2110,13 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
let s = n.sym
|
||||
checkCanEval(c, n)
|
||||
case s.kind
|
||||
of skVar, skForVar, skTemp, skLet, skParam, skResult:
|
||||
of skVar, skForVar, skTemp, skLet, skResult:
|
||||
genRdVar(c, n, dest, flags)
|
||||
of skParam:
|
||||
if s.typ.kind == tyTypeDesc:
|
||||
genTypeLit(c, s.typ, dest)
|
||||
else:
|
||||
genRdVar(c, n, dest, flags)
|
||||
of skProc, skFunc, skConverter, skMacro, skTemplate, skMethod, skIterator:
|
||||
# 'skTemplate' is only allowed for 'getAst' support:
|
||||
if s.kind == skIterator and s.typ.callConv == TCallingConvention.ccClosure:
|
||||
|
||||
@@ -237,10 +237,10 @@ doc.file = """<?xml version="1.0" encoding="utf-8" ?>
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH4QQQEwksSS9ZWwAAAk1JREFUWMPtll2ITVEUx39nn/O7Y5qR8f05wtCUUr6ZIS++8pEnkZInPImneaCQ5METNdOkeFBKUhMPRIkHKfEuUZSUlGlKPN2TrgfncpvmnntnmlEyq1Z7t89/rf9a6+y99oZxGZf/XeIq61EdtgKXgdXA0xrYAvBjOIF1AI9zvjcC74BSpndrJPkBWDScTF8Aa4E3wDlgHbASaANmVqlcCnwHvgDvgVfAJ+AikAAvgfVZwLnSVZHZaOuKoQi3ZOMi4NkYkpe1p4J7A8BpYAD49hfIy/oqG0+hLomiKP2L5L+1ubn5115S+3OAn4EnwBlgMzCjyt6ZAnQCJ4A7wOs88iRJHvw50HoujuPBoCKwHWiosy8MdfZnAdcHk8dxXFJ3VQbQlCTJvRBCGdRbD4M6uc5glpY3eAihpN5S5w12diSEcCCEcKUO4ljdr15T76ur1FDDLIQQ3qv71EdDOe3Kxj3leRXyk+pxdWnFWod6Wt2bY3de3aSuUHcPBVimHs7mK9WrmeOF6lR1o9qnzskh2ar2qm1qizpfXaPeVGdlmGN5pb09qMxz1Xb1kLqgzn1RyH7JUXW52lr5e/Kqi9qpto7V1atuUzfnARrV7jEib1T76gG2qxdGmXyiekkt1GswPTtek0aBfJp6YySGBfWg2tPQ0FAYgf1stUfdmdcjarbYJEniKIq6gY/Aw+zWHAC+p2labGpqiorFYgGYCEzN7oQdQClN07O1/EfDyGgC0ALMBdYAi4FyK+4H3gLPsxfR1zRNi+NP7nH5J+QntnXe5B5mpfQAAAAASUVORK5CYII=">
|
||||
|
||||
<!-- CSS -->
|
||||
<link rel="stylesheet" type="text/css" href="$nimdoccss">
|
||||
<link rel="stylesheet" type="text/css" href="${nimdoccss}?v=$nimVersion">
|
||||
|
||||
<!-- JS -->
|
||||
<script type="text/javascript" src="$dochackjs"></script>
|
||||
<script type="text/javascript" src="${dochackjs}?v=$nimVersion"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document" id="documentId">
|
||||
|
||||
@@ -217,9 +217,11 @@ type
|
||||
## code.
|
||||
|
||||
proc destroyRegex(pattern: Regex) =
|
||||
`=destroy`(pattern.pattern)
|
||||
pcre.free_substring(cast[cstring](pattern.pcreObj))
|
||||
if pattern.pcreExtra != nil:
|
||||
pcre.free_study(pattern.pcreExtra)
|
||||
`=destroy`(pattern.captureNameToId)
|
||||
|
||||
proc getinfo[T](pattern: Regex, opt: cint): T =
|
||||
let retcode = pcre.fullinfo(pattern.pcreObj, pattern.pcreExtra, opt, addr result)
|
||||
|
||||
@@ -465,6 +465,7 @@ const MSG_EOR* = cint(128)
|
||||
const MSG_OOB* = cint(1)
|
||||
const SCM_RIGHTS* = cint(1)
|
||||
const SO_ACCEPTCONN* = cint(30)
|
||||
const SO_BINDTODEVICE* = cint(25)
|
||||
const SO_BROADCAST* = cint(6)
|
||||
const SO_DEBUG* = cint(1)
|
||||
const SO_DONTROUTE* = cint(5)
|
||||
|
||||
@@ -606,10 +606,10 @@ when not defined(lwip):
|
||||
|
||||
when defined(zephyr):
|
||||
type
|
||||
Tnfds* = distinct cint
|
||||
Tnfds* = distinct culong
|
||||
else:
|
||||
type
|
||||
Tnfds* {.importc: "nfds_t", header: "<poll.h>".} = cint
|
||||
Tnfds* {.importc: "nfds_t", header: "<poll.h>".} = culong
|
||||
|
||||
var
|
||||
errno* {.importc, header: "<errno.h>".}: cint ## error variable
|
||||
|
||||
@@ -482,6 +482,7 @@ var MSG_EOR* {.importc: "MSG_EOR", header: "<sys/socket.h>".}: cint
|
||||
var MSG_OOB* {.importc: "MSG_OOB", header: "<sys/socket.h>".}: cint
|
||||
var SCM_RIGHTS* {.importc: "SCM_RIGHTS", header: "<sys/socket.h>".}: cint
|
||||
var SO_ACCEPTCONN* {.importc: "SO_ACCEPTCONN", header: "<sys/socket.h>".}: cint
|
||||
var SO_BINDTODEVICE* {.importc: "SO_BINDTODEVICE", header: "<sys/socket.h>".}: cint
|
||||
var SO_BROADCAST* {.importc: "SO_BROADCAST", header: "<sys/socket.h>".}: cint
|
||||
var SO_DEBUG* {.importc: "SO_DEBUG", header: "<sys/socket.h>".}: cint
|
||||
var SO_DONTROUTE* {.importc: "SO_DONTROUTE", header: "<sys/socket.h>".}: cint
|
||||
|
||||
@@ -66,14 +66,10 @@ template cbBase(a, b): untyped = [
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', a, b]
|
||||
|
||||
let
|
||||
const
|
||||
cb64 = cbBase('+', '/')
|
||||
cb64safe = cbBase('-', '_')
|
||||
|
||||
const
|
||||
cb64VM = cbBase('+', '/')
|
||||
cb64safeVM = cbBase('-', '_')
|
||||
|
||||
const
|
||||
invalidChar = 255
|
||||
|
||||
@@ -134,14 +130,10 @@ template encodeInternal(s, alphabet: typed): untyped =
|
||||
result.setLen(outputIndex)
|
||||
|
||||
template encodeImpl() {.dirty.} =
|
||||
when nimvm:
|
||||
block:
|
||||
let lookupTableVM = if safe: cb64safeVM else: cb64VM
|
||||
encodeInternal(s, lookupTableVM)
|
||||
if safe:
|
||||
encodeInternal(s, cb64safe)
|
||||
else:
|
||||
block:
|
||||
let lookupTable = if safe: unsafeAddr(cb64safe) else: unsafeAddr(cb64)
|
||||
encodeInternal(s, lookupTable)
|
||||
encodeInternal(s, cb64)
|
||||
|
||||
proc encode*[T: byte|char](s: openArray[T], safe = false): string =
|
||||
## Encodes `s` into base64 representation.
|
||||
|
||||
@@ -165,28 +165,6 @@ proc newSinglyLinkedNode*[T](value: T): SinglyLinkedNode[T] =
|
||||
new(result)
|
||||
result.value = value
|
||||
|
||||
func toSinglyLinkedList*[T](elems: openArray[T]): SinglyLinkedList[T] {.since: (1, 5, 1).} =
|
||||
## Creates a new `SinglyLinkedList` from the members of `elems`.
|
||||
runnableExamples:
|
||||
from std/sequtils import toSeq
|
||||
let a = [1, 2, 3, 4, 5].toSinglyLinkedList
|
||||
assert a.toSeq == [1, 2, 3, 4, 5]
|
||||
|
||||
result = initSinglyLinkedList[T]()
|
||||
for elem in elems.items:
|
||||
result.add(elem)
|
||||
|
||||
func toDoublyLinkedList*[T](elems: openArray[T]): DoublyLinkedList[T] {.since: (1, 5, 1).} =
|
||||
## Creates a new `DoublyLinkedList` from the members of `elems`.
|
||||
runnableExamples:
|
||||
from std/sequtils import toSeq
|
||||
let a = [1, 2, 3, 4, 5].toDoublyLinkedList
|
||||
assert a.toSeq == [1, 2, 3, 4, 5]
|
||||
|
||||
result = initDoublyLinkedList[T]()
|
||||
for elem in elems.items:
|
||||
result.add(elem)
|
||||
|
||||
template itemsListImpl() {.dirty.} =
|
||||
var it {.cursor.} = L.head
|
||||
while it != nil:
|
||||
@@ -993,3 +971,25 @@ proc appendMoved*[T: SomeLinkedList](a, b: var T) {.since: (1, 5, 1).} =
|
||||
## * `addMoved proc <#addMoved,SinglyLinkedList[T],SinglyLinkedList[T]>`_
|
||||
## * `addMoved proc <#addMoved,DoublyLinkedList[T],DoublyLinkedList[T]>`_
|
||||
a.addMoved(b)
|
||||
|
||||
func toSinglyLinkedList*[T](elems: openArray[T]): SinglyLinkedList[T] {.since: (1, 5, 1).} =
|
||||
## Creates a new `SinglyLinkedList` from the members of `elems`.
|
||||
runnableExamples:
|
||||
from std/sequtils import toSeq
|
||||
let a = [1, 2, 3, 4, 5].toSinglyLinkedList
|
||||
assert a.toSeq == [1, 2, 3, 4, 5]
|
||||
|
||||
result = initSinglyLinkedList[T]()
|
||||
for elem in elems.items:
|
||||
result.add(elem)
|
||||
|
||||
func toDoublyLinkedList*[T](elems: openArray[T]): DoublyLinkedList[T] {.since: (1, 5, 1).} =
|
||||
## Creates a new `DoublyLinkedList` from the members of `elems`.
|
||||
runnableExamples:
|
||||
from std/sequtils import toSeq
|
||||
let a = [1, 2, 3, 4, 5].toDoublyLinkedList
|
||||
assert a.toSeq == [1, 2, 3, 4, 5]
|
||||
|
||||
result = initDoublyLinkedList[T]()
|
||||
for elem in elems.items:
|
||||
result.add(elem)
|
||||
|
||||
@@ -200,8 +200,8 @@ const
|
||||
colGoldenRod* = Color(0xDAA520)
|
||||
colGray* = Color(0x808080)
|
||||
colGreen* = Color(0x008000)
|
||||
colGrey* = Color(0x808080)
|
||||
colGreenYellow* = Color(0xADFF2F)
|
||||
colGrey* = Color(0x808080)
|
||||
colHoneyDew* = Color(0xF0FFF0)
|
||||
colHotPink* = Color(0xFF69B4)
|
||||
colIndianRed* = Color(0xCD5C5C)
|
||||
@@ -350,8 +350,8 @@ const
|
||||
"goldenrod": colGoldenRod,
|
||||
"gray": colGray,
|
||||
"green": colGreen,
|
||||
"grey": colGrey,
|
||||
"greenyellow": colGreenYellow,
|
||||
"grey": colGrey,
|
||||
"honeydew": colHoneyDew,
|
||||
"hotpink": colHotPink,
|
||||
"indianred": colIndianRed,
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
{.deprecated: "use the nimble packages `malebolgia`, `taskpools` or `weave` instead".}
|
||||
|
||||
## Implements Nim's `parallel & spawn statements <manual_experimental.html#parallel-amp-spawn>`_.
|
||||
##
|
||||
## Unstable API.
|
||||
|
||||
@@ -319,16 +319,24 @@ proc murmurHash(x: openArray[byte]): Hash =
|
||||
h1: uint32
|
||||
i = 0
|
||||
|
||||
|
||||
template impl =
|
||||
var j = stepSize
|
||||
while j > 0:
|
||||
dec j
|
||||
k1 = (k1 shl 8) or (ord(x[i+j])).uint32
|
||||
|
||||
# body
|
||||
while i < n * stepSize:
|
||||
var k1: uint32
|
||||
when defined(js) or defined(sparc) or defined(sparc64):
|
||||
var j = stepSize
|
||||
while j > 0:
|
||||
dec j
|
||||
k1 = (k1 shl 8) or (ord(x[i+j])).uint32
|
||||
|
||||
when nimvm:
|
||||
impl()
|
||||
else:
|
||||
k1 = cast[ptr uint32](unsafeAddr x[i])[]
|
||||
when declared(copyMem):
|
||||
copyMem(addr k1, addr x[i], 4)
|
||||
else:
|
||||
impl()
|
||||
inc i, stepSize
|
||||
|
||||
k1 = imul(k1, c1)
|
||||
|
||||
@@ -387,21 +387,37 @@ when not useNimNetLite:
|
||||
|
||||
proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} =
|
||||
## This function will lookup the hostname of an IP Address.
|
||||
var myaddr: InAddr
|
||||
myaddr.s_addr = inet_addr(ip)
|
||||
var
|
||||
addrInfo = getAddrInfo(ip, Port(0), AF_UNSPEC)
|
||||
myAddr: pointer
|
||||
addrLen = 0
|
||||
family = 0
|
||||
|
||||
defer: freeAddrInfo(addrInfo)
|
||||
|
||||
if addrInfo.ai_addr.sa_family.cint == nativeAfInet:
|
||||
family = nativeAfInet
|
||||
myAddr = addr cast[ptr Sockaddr_in](addrInfo.ai_addr).sin_addr
|
||||
addrLen = 4
|
||||
elif addrInfo.ai_addr.sa_family.cint == nativeAfInet6:
|
||||
family = nativeAfInet6
|
||||
myAddr = addr cast[ptr Sockaddr_in6](addrInfo.ai_addr).sin6_addr
|
||||
addrLen = 16
|
||||
else:
|
||||
raise newException(IOError, "Unknown socket family in `getHostByAddr()`")
|
||||
|
||||
when useWinVersion:
|
||||
var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
|
||||
cint(AF_INET))
|
||||
var s = winlean.gethostbyaddr(cast[ptr InAddr](myAddr), addrLen.cuint,
|
||||
cint(family))
|
||||
if s == nil: raiseOSError(osLastError())
|
||||
else:
|
||||
var s =
|
||||
when defined(android4):
|
||||
posix.gethostbyaddr(cast[cstring](addr(myaddr)), sizeof(myaddr).cint,
|
||||
cint(posix.AF_INET))
|
||||
posix.gethostbyaddr(cast[cstring](myAddr), addrLen.cint,
|
||||
cint(family))
|
||||
else:
|
||||
posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).SockLen,
|
||||
cint(posix.AF_INET))
|
||||
posix.gethostbyaddr(myAddr, addrLen.SockLen,
|
||||
cint(family))
|
||||
if s == nil:
|
||||
raiseOSError(osLastError(), $hstrerror(h_errno))
|
||||
|
||||
@@ -424,7 +440,20 @@ when not useNimNetLite:
|
||||
result.addrList.add($inet_ntoa(inaddrPtr[]))
|
||||
inc(i)
|
||||
else:
|
||||
result.addrList = cstringArrayToSeq(s.h_addr_list)
|
||||
let strAddrLen = when not useWinVersion: posix.INET6_ADDRSTRLEN.int
|
||||
else: 46
|
||||
var i = 0
|
||||
while not isNil(s.h_addr_list[i]):
|
||||
var ipStr = newString(strAddrLen)
|
||||
if inet_ntop(nativeAfInet6, cast[pointer](s.h_addr_list[i]),
|
||||
cstring(ipStr), len(ipStr).int32) == nil:
|
||||
raiseOSError(osLastError())
|
||||
when not useWinVersion:
|
||||
if posix.IN6_IS_ADDR_V4MAPPED(cast[ptr In6Addr](s.h_addr_list[i])) != 0:
|
||||
ipStr.setSlice("::ffff:".len..<strAddrLen)
|
||||
setLen(ipStr, len(cstring(ipStr)))
|
||||
result.addrList.add(ipStr)
|
||||
inc(i)
|
||||
result.length = int(s.h_length)
|
||||
|
||||
proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} =
|
||||
|
||||
@@ -638,14 +638,14 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noW
|
||||
# /proc/<pid>/path/a.out (complete pathname)
|
||||
when defined(windows):
|
||||
var bufsize = int32(MAX_PATH)
|
||||
var buf = newWideCString("", bufsize)
|
||||
var buf = newWideCString(bufsize)
|
||||
while true:
|
||||
var L = getModuleFileNameW(0, buf, bufsize)
|
||||
if L == 0'i32:
|
||||
result = "" # error!
|
||||
break
|
||||
elif L > bufsize:
|
||||
buf = newWideCString("", L)
|
||||
buf = newWideCString(L)
|
||||
bufsize = L
|
||||
else:
|
||||
result = buf$L
|
||||
|
||||
@@ -562,7 +562,7 @@ template matchOrParse(mopProc: untyped) =
|
||||
# procs. For the former, *enter* and *leave* event handler code generators
|
||||
# are provided which just return *discard*.
|
||||
|
||||
proc mopProc(s: string, p: Peg, start: int, c: var Captures): int {.gcsafe.} =
|
||||
proc mopProc(s: string, p: Peg, start: int, c: var Captures): int {.gcsafe, raises: [].} =
|
||||
proc matchBackRef(s: string, p: Peg, start: int, c: var Captures): int =
|
||||
# Parse handler code must run in an *of* clause of its own for each
|
||||
# *PegKind*, so we encapsulate the identical clause body for
|
||||
|
||||
@@ -457,10 +457,6 @@ when not defined(js) and not defined(nimSeqsV2):
|
||||
data: UncheckedArray[char]
|
||||
NimString = ptr NimStringDesc
|
||||
|
||||
when notJSnotNims and not defined(nimSeqsV2):
|
||||
template space(s: PGenericSeq): int {.dirty.} =
|
||||
s.reserved and not (seqShallowFlag or strlitFlag)
|
||||
|
||||
when notJSnotNims:
|
||||
include "system/hti"
|
||||
|
||||
@@ -1068,6 +1064,10 @@ const
|
||||
hasThreadSupport = compileOption("threads") and not defined(nimscript)
|
||||
hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own
|
||||
|
||||
when notJSnotNims and not defined(nimSeqsV2):
|
||||
template space(s: PGenericSeq): int =
|
||||
s.reserved and not (seqShallowFlag or strlitFlag)
|
||||
|
||||
when hasThreadSupport and defined(tcc) and not compileOption("tlsEmulation"):
|
||||
# tcc doesn't support TLS
|
||||
{.error: "`--tlsEmulation:on` must be used when using threads with tcc backend".}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
const
|
||||
NimMajor* {.intdefine.}: int = 1
|
||||
NimMajor* {.intdefine.}: int = 2
|
||||
## is the major number of Nim's version. Example:
|
||||
## ```
|
||||
## when (NimMajor, NimMinor, NimPatch) >= (1, 3, 1): discard
|
||||
## ```
|
||||
# see also std/private/since
|
||||
|
||||
NimMinor* {.intdefine.}: int = 9
|
||||
NimMinor* {.intdefine.}: int = 0
|
||||
## is the minor number of Nim's version.
|
||||
## Odd for devel, even for releases.
|
||||
|
||||
NimPatch* {.intdefine.}: int = 5
|
||||
NimPatch* {.intdefine.}: int = 2
|
||||
## is the patch number of Nim's version.
|
||||
## Odd for devel, even for releases.
|
||||
|
||||
|
||||
@@ -278,7 +278,9 @@ proc toJSStr(s: string): cstring {.compilerproc.} =
|
||||
|
||||
proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} =
|
||||
asm """
|
||||
return new Array(`len`);
|
||||
var result = new Array(`len`);
|
||||
for (var i = 0; i < `len`; i++) {result[i] = 0;}
|
||||
return result;
|
||||
"""
|
||||
|
||||
proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} =
|
||||
|
||||
@@ -88,7 +88,7 @@ type
|
||||
|
||||
proc alloc(r: var MemRegion, size: int): pointer =
|
||||
result = alloc(size)
|
||||
proc alloc0Impl(r: var MemRegion, size: int): pointer =
|
||||
proc alloc0(r: var MemRegion, size: int): pointer =
|
||||
result = alloc0Impl(size)
|
||||
proc dealloc(r: var MemRegion, p: pointer) = dealloc(p)
|
||||
proc deallocOsPages(r: var MemRegion) = discard
|
||||
|
||||
@@ -140,8 +140,6 @@ proc newSeq[T](s: var seq[T], len: Natural) =
|
||||
setLen(s, len)
|
||||
|
||||
|
||||
template capacityImpl(sek: NimSeqV2): int =
|
||||
if sek.p != nil: (xu.p.cap and not strlitFlag) else: 0
|
||||
|
||||
func capacity*[T](self: seq[T]): int {.inline.} =
|
||||
## Returns the current capacity of the seq.
|
||||
@@ -151,9 +149,8 @@ func capacity*[T](self: seq[T]): int {.inline.} =
|
||||
lst.add "Nim"
|
||||
assert lst.capacity == 42
|
||||
|
||||
{.cast(noSideEffect).}:
|
||||
let sek = unsafeAddr self
|
||||
result = capacityImpl(cast[ptr NimSeqV2](sek)[])
|
||||
let sek = cast[ptr NimSeqV2[T]](unsafeAddr self)
|
||||
result = if sek.p != nil: sek.p.cap and not strlitFlag else: 0
|
||||
|
||||
|
||||
{.pop.} # See https://github.com/nim-lang/Nim/issues/21401
|
||||
|
||||
@@ -13,9 +13,11 @@
|
||||
proc cardSetImpl(s: ptr UncheckedArray[uint8], len: int): int {.inline.} =
|
||||
var i = 0
|
||||
result = 0
|
||||
var num = 0'u64
|
||||
when defined(x86) or defined(amd64):
|
||||
while i < len - 8:
|
||||
inc(result, countBits64((cast[ptr uint64](s[i].unsafeAddr))[]))
|
||||
copyMem(addr num, addr s[i], 8)
|
||||
inc(result, countBits64(num))
|
||||
inc(i, 8)
|
||||
|
||||
while i < len:
|
||||
|
||||
@@ -34,53 +34,72 @@ template frees(s) =
|
||||
else:
|
||||
dealloc(s.p)
|
||||
|
||||
template allocPayload(newLen: int): ptr NimStrPayload =
|
||||
when compileOption("threads"):
|
||||
cast[ptr NimStrPayload](allocShared(contentSize(newLen)))
|
||||
else:
|
||||
cast[ptr NimStrPayload](alloc(contentSize(newLen)))
|
||||
|
||||
template allocPayload0(newLen: int): ptr NimStrPayload =
|
||||
when compileOption("threads"):
|
||||
cast[ptr NimStrPayload](allocShared0(contentSize(newLen)))
|
||||
else:
|
||||
cast[ptr NimStrPayload](alloc0(contentSize(newLen)))
|
||||
|
||||
template reallocPayload(p: pointer, newLen: int): ptr NimStrPayload =
|
||||
when compileOption("threads"):
|
||||
cast[ptr NimStrPayload](reallocShared(p, contentSize(newLen)))
|
||||
else:
|
||||
cast[ptr NimStrPayload](realloc(p, contentSize(newLen)))
|
||||
|
||||
template reallocPayload0(p: pointer; oldLen, newLen: int): ptr NimStrPayload =
|
||||
when compileOption("threads"):
|
||||
cast[ptr NimStrPayload](reallocShared0(p, contentSize(oldLen), contentSize(newLen)))
|
||||
else:
|
||||
cast[ptr NimStrPayload](realloc0(p, contentSize(oldLen), contentSize(newLen)))
|
||||
|
||||
proc resize(old: int): int {.inline.} =
|
||||
if old <= 0: result = 4
|
||||
elif old <= high(int16): result = old * 2
|
||||
else: result = old * 3 div 2 # for large arrays * 3/2 is better
|
||||
|
||||
proc prepareAdd(s: var NimStringV2; addlen: int) {.compilerRtl.} =
|
||||
let newLen = s.len + addlen
|
||||
proc prepareAdd(s: var NimStringV2; addLen: int) {.compilerRtl.} =
|
||||
let newLen = s.len + addLen
|
||||
if isLiteral(s):
|
||||
let oldP = s.p
|
||||
# can't mutate a literal, so we need a fresh copy here:
|
||||
when compileOption("threads"):
|
||||
s.p = cast[ptr NimStrPayload](allocShared0(contentSize(newLen)))
|
||||
else:
|
||||
s.p = cast[ptr NimStrPayload](alloc0(contentSize(newLen)))
|
||||
s.p = allocPayload(newLen)
|
||||
s.p.cap = newLen
|
||||
if s.len > 0:
|
||||
# we are about to append, so there is no need to copy the \0 terminator:
|
||||
copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], min(s.len, newLen))
|
||||
elif oldP == nil:
|
||||
# In the case of `newString(0) & ""`, since `src.len == 0`, `appendString`
|
||||
# will not set the `\0` terminator, so we set it here.
|
||||
s.p.data[0] = '\0'
|
||||
else:
|
||||
let oldCap = s.p.cap and not strlitFlag
|
||||
if newLen > oldCap:
|
||||
let newCap = max(newLen, resize(oldCap))
|
||||
when compileOption("threads"):
|
||||
s.p = cast[ptr NimStrPayload](reallocShared0(s.p, contentSize(oldCap), contentSize(newCap)))
|
||||
else:
|
||||
s.p = cast[ptr NimStrPayload](realloc0(s.p, contentSize(oldCap), contentSize(newCap)))
|
||||
s.p = reallocPayload(s.p, newCap)
|
||||
s.p.cap = newCap
|
||||
if newLen < newCap:
|
||||
zeroMem(cast[pointer](addr s.p.data[newLen+1]), newCap - newLen)
|
||||
|
||||
proc nimAddCharV1(s: var NimStringV2; c: char) {.compilerRtl, inl.} =
|
||||
#if (s.p == nil) or (s.len+1 > s.p.cap and not strlitFlag):
|
||||
prepareAdd(s, 1)
|
||||
s.p.data[s.len] = c
|
||||
s.p.data[s.len+1] = '\0'
|
||||
inc s.len
|
||||
s.p.data[s.len] = '\0'
|
||||
|
||||
proc toNimStr(str: cstring, len: int): NimStringV2 {.compilerproc.} =
|
||||
if len <= 0:
|
||||
result = NimStringV2(len: 0, p: nil)
|
||||
else:
|
||||
when compileOption("threads"):
|
||||
var p = cast[ptr NimStrPayload](allocShared0(contentSize(len)))
|
||||
else:
|
||||
var p = cast[ptr NimStrPayload](alloc0(contentSize(len)))
|
||||
var p = allocPayload(len)
|
||||
p.cap = len
|
||||
if len > 0:
|
||||
# we are about to append, so there is no need to copy the \0 terminator:
|
||||
copyMem(unsafeAddr p.data[0], str, len)
|
||||
copyMem(unsafeAddr p.data[0], str, len+1)
|
||||
result = NimStringV2(len: len, p: p)
|
||||
|
||||
proc cstrToNimstr(str: cstring): NimStringV2 {.compilerRtl.} =
|
||||
@@ -99,29 +118,24 @@ proc appendString(dest: var NimStringV2; src: NimStringV2) {.compilerproc, inlin
|
||||
|
||||
proc appendChar(dest: var NimStringV2; c: char) {.compilerproc, inline.} =
|
||||
dest.p.data[dest.len] = c
|
||||
dest.p.data[dest.len+1] = '\0'
|
||||
inc dest.len
|
||||
dest.p.data[dest.len] = '\0'
|
||||
|
||||
proc rawNewString(space: int): NimStringV2 {.compilerproc.} =
|
||||
# this is also 'system.newStringOfCap'.
|
||||
if space <= 0:
|
||||
result = NimStringV2(len: 0, p: nil)
|
||||
else:
|
||||
when compileOption("threads"):
|
||||
var p = cast[ptr NimStrPayload](allocShared0(contentSize(space)))
|
||||
else:
|
||||
var p = cast[ptr NimStrPayload](alloc0(contentSize(space)))
|
||||
var p = allocPayload(space)
|
||||
p.cap = space
|
||||
p.data[0] = '\0'
|
||||
result = NimStringV2(len: 0, p: p)
|
||||
|
||||
proc mnewString(len: int): NimStringV2 {.compilerproc.} =
|
||||
if len <= 0:
|
||||
result = NimStringV2(len: 0, p: nil)
|
||||
else:
|
||||
when compileOption("threads"):
|
||||
var p = cast[ptr NimStrPayload](allocShared0(contentSize(len)))
|
||||
else:
|
||||
var p = cast[ptr NimStrPayload](alloc0(contentSize(len)))
|
||||
var p = allocPayload0(len)
|
||||
p.cap = len
|
||||
result = NimStringV2(len: len, p: p)
|
||||
|
||||
@@ -129,8 +143,25 @@ proc setLengthStrV2(s: var NimStringV2, newLen: int) {.compilerRtl.} =
|
||||
if newLen == 0:
|
||||
discard "do not free the buffer here, pattern 's.setLen 0' is common for avoiding allocations"
|
||||
else:
|
||||
if newLen > s.len or isLiteral(s):
|
||||
prepareAdd(s, newLen - s.len)
|
||||
if isLiteral(s):
|
||||
let oldP = s.p
|
||||
s.p = allocPayload(newLen)
|
||||
s.p.cap = newLen
|
||||
if s.len > 0:
|
||||
copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], min(s.len, newLen))
|
||||
if newLen > s.len:
|
||||
zeroMem(cast[pointer](addr s.p.data[s.len]), newLen - s.len + 1)
|
||||
else:
|
||||
s.p.data[newLen] = '\0'
|
||||
else:
|
||||
zeroMem(cast[pointer](addr s.p.data[0]), newLen + 1)
|
||||
elif newLen > s.len:
|
||||
let oldCap = s.p.cap and not strlitFlag
|
||||
if newLen > oldCap:
|
||||
let newCap = max(newLen, resize(oldCap))
|
||||
s.p = reallocPayload0(s.p, oldCap, newCap)
|
||||
s.p.cap = newCap
|
||||
|
||||
s.p.data[newLen] = '\0'
|
||||
s.len = newLen
|
||||
|
||||
@@ -147,10 +178,7 @@ proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} =
|
||||
# 'let y = newStringOfCap(); var x = y'
|
||||
# on the other hand... These get turned into moves now.
|
||||
frees(a)
|
||||
when compileOption("threads"):
|
||||
a.p = cast[ptr NimStrPayload](allocShared0(contentSize(b.len)))
|
||||
else:
|
||||
a.p = cast[ptr NimStrPayload](alloc0(contentSize(b.len)))
|
||||
a.p = allocPayload(b.len)
|
||||
a.p.cap = b.len
|
||||
a.len = b.len
|
||||
copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], b.len+1)
|
||||
@@ -158,10 +186,7 @@ proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} =
|
||||
proc nimPrepareStrMutationImpl(s: var NimStringV2) =
|
||||
let oldP = s.p
|
||||
# can't mutate a literal, so we need a fresh copy here:
|
||||
when compileOption("threads"):
|
||||
s.p = cast[ptr NimStrPayload](allocShared0(contentSize(s.len)))
|
||||
else:
|
||||
s.p = cast[ptr NimStrPayload](alloc0(contentSize(s.len)))
|
||||
s.p = allocPayload(s.len)
|
||||
s.p.cap = s.len
|
||||
copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len+1)
|
||||
|
||||
@@ -177,9 +202,6 @@ proc prepareMutation*(s: var string) {.inline.} =
|
||||
nimPrepareStrMutationV2(cast[ptr NimStringV2](s)[])
|
||||
|
||||
|
||||
template capacityImpl(str: NimStringV2): int =
|
||||
if str.p != nil: str.p.cap else: 0
|
||||
|
||||
func capacity*(self: string): int {.inline.} =
|
||||
## Returns the current capacity of the string.
|
||||
# See https://github.com/nim-lang/RFCs/issues/460
|
||||
@@ -188,6 +210,5 @@ func capacity*(self: string): int {.inline.} =
|
||||
str.add "Nim"
|
||||
assert str.capacity == 42
|
||||
|
||||
{.cast(noSideEffect).}:
|
||||
let str = unsafeAddr self
|
||||
result = capacityImpl(cast[ptr NimStringV2](str)[])
|
||||
let str = cast[ptr NimStringV2](unsafeAddr self)
|
||||
result = if str.p != nil: str.p.cap and not strlitFlag else: 0
|
||||
|
||||
@@ -340,3 +340,25 @@ proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {.
|
||||
result = s
|
||||
zeroMem(dataPointer(result, elemAlign, elemSize, result.len), (newLen-%result.len) *% elemSize)
|
||||
result.len = newLen
|
||||
|
||||
func capacity*(self: string): int {.inline.} =
|
||||
## Returns the current capacity of the string.
|
||||
# See https://github.com/nim-lang/RFCs/issues/460
|
||||
runnableExamples:
|
||||
var str = newStringOfCap(cap = 42)
|
||||
str.add "Nim"
|
||||
assert str.capacity == 42
|
||||
|
||||
let str = cast[NimString](self)
|
||||
result = if str != nil: str.space else: 0
|
||||
|
||||
func capacity*[T](self: seq[T]): int {.inline.} =
|
||||
## Returns the current capacity of the seq.
|
||||
# See https://github.com/nim-lang/RFCs/issues/460
|
||||
runnableExamples:
|
||||
var lst = newSeqOfCap[string](cap = 42)
|
||||
lst.add "Nim"
|
||||
assert lst.capacity == 42
|
||||
|
||||
let sek = cast[PGenericSeq](self)
|
||||
result = if sek != nil: sek.space else: 0
|
||||
|
||||
@@ -24,11 +24,13 @@ proc testRst2Html(fixup = false) =
|
||||
let sourceFile = expectedHtml.replace('\\', '/').replace("/expected/", "/source/").replace(".html", ".rst")
|
||||
exec("$1 rst2html $2" % [nimExe, sourceFile])
|
||||
let producedHtml = expectedHtml.replace('\\', '/').replace("/expected/", "/source/htmldocs/")
|
||||
if readFile(expectedHtml) != readFile(producedHtml):
|
||||
let versionCacheParam = "?v=" & $NimMajor & "." & $NimMinor & "." & $NimPatch
|
||||
let producedFile = readFile(producedHtml).replace(versionCacheParam,"") #remove version cache param used for cache invalidation
|
||||
if readFile(expectedHtml) != producedFile:
|
||||
echo diffFiles(expectedHtml, producedHtml).output
|
||||
inc failures
|
||||
if fixup:
|
||||
copyFile(producedHtml, expectedHtml)
|
||||
writeFile(expectedHtml, producedFile)
|
||||
else:
|
||||
echo "SUCCESS: files identical: ", producedHtml
|
||||
if failures == 0:
|
||||
|
||||
@@ -59,16 +59,18 @@ proc testNimDoc(prjDir, docsDir: string; switches: NimSwitches; fixup = false) =
|
||||
echo("$1 buildIndex $2" % [nimExe, nimBuildIndexSwitches])
|
||||
|
||||
for expected in walkDirRec(prjDir / "expected/", checkDir=true):
|
||||
let versionCacheParam = "?v=" & $NimMajor & "." & $NimMinor & "." & $NimPatch
|
||||
let produced = expected.replace('\\', '/').replace("/expected/", "/$1/" % [docsDir])
|
||||
if not fileExists(produced):
|
||||
echo "FAILURE: files not found: ", produced
|
||||
inc failures
|
||||
elif readFile(expected) != readFile(produced):
|
||||
let producedFile = readFile(produced).replace(versionCacheParam,"") #remove version cache param used for cache invalidation
|
||||
if readFile(expected) != producedFile:
|
||||
echo "FAILURE: files differ: ", produced
|
||||
echo diffFiles(expected, produced).output
|
||||
inc failures
|
||||
if fixup:
|
||||
copyFile(produced, expected)
|
||||
writeFile(expected, producedFile)
|
||||
else:
|
||||
echo "SUCCESS: files identical: ", produced
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import strformat
|
||||
import algorithm
|
||||
import tables
|
||||
import times
|
||||
import procmonitor
|
||||
|
||||
template tryImport(module) = import module
|
||||
|
||||
@@ -43,6 +44,7 @@ when defined(windows):
|
||||
else:
|
||||
import posix
|
||||
|
||||
const HighestSuggestProtocolVersion = 4
|
||||
const DummyEof = "!EOF!"
|
||||
const Usage = """
|
||||
Nimsuggest - Tool to give every editor IDE like capabilities for Nim
|
||||
@@ -55,12 +57,17 @@ Options:
|
||||
--address:HOST binds to that address, by default ""
|
||||
--stdin read commands from stdin and write results to
|
||||
stdout instead of using sockets
|
||||
--clientProcessId:PID shutdown nimsuggest in case this process dies
|
||||
--epc use emacs epc mode
|
||||
--debug enable debug output
|
||||
--log enable verbose logging to nimsuggest.log file
|
||||
--v1 use version 1 of the protocol; for backwards compatibility
|
||||
--v2 use version 2(default) of the protocol
|
||||
--v3 use version 3 of the protocol
|
||||
--v4 use version 4 of the protocol
|
||||
--info:X information
|
||||
--info:nimVer return the Nim compiler version that nimsuggest uses internally
|
||||
--info:protocolVer return the newest protocol version that is supported
|
||||
--refresh perform automatic refreshes to keep the analysis precise
|
||||
--maxresults:N limit the number of suggestions to N
|
||||
--tester implies --stdin and outputs a line
|
||||
@@ -161,7 +168,7 @@ proc listEpc(): SexpNode =
|
||||
argspecs = sexp("file line column dirtyfile".split(" ").map(newSSymbol))
|
||||
docstring = sexp("line starts at 1, column at 0, dirtyfile is optional")
|
||||
result = newSList()
|
||||
for command in ["sug", "con", "def", "use", "dus", "chk", "mod", "globalSymbols", "recompile", "saved", "chkFile", "declaration"]:
|
||||
for command in ["sug", "con", "def", "use", "dus", "chk", "mod", "globalSymbols", "recompile", "saved", "chkFile", "declaration", "inlayHints"]:
|
||||
let
|
||||
cmd = sexp(command)
|
||||
methodDesc = newSList()
|
||||
@@ -197,7 +204,7 @@ proc executeNoHooks(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int,
|
||||
graph: ModuleGraph) =
|
||||
let conf = graph.config
|
||||
|
||||
if conf.suggestVersion == 3:
|
||||
if conf.suggestVersion >= 3:
|
||||
let command = fmt "cmd = {cmd} {file}:{line}:{col}"
|
||||
benchmark command:
|
||||
executeNoHooksV3(cmd, file, dirtyfile, line, col, tag, graph)
|
||||
@@ -486,6 +493,11 @@ proc execCmd(cmd: string; graph: ModuleGraph; cachedMsgs: CachedMsgs) =
|
||||
of "chkfile": conf.ideCmd = ideChkFile
|
||||
of "recompile": conf.ideCmd = ideRecompile
|
||||
of "type": conf.ideCmd = ideType
|
||||
of "inlayhints":
|
||||
if conf.suggestVersion >= 4:
|
||||
conf.ideCmd = ideInlayHints
|
||||
else:
|
||||
err()
|
||||
else: err()
|
||||
var dirtyfile = ""
|
||||
var orig = ""
|
||||
@@ -550,7 +562,7 @@ proc mainThread(graph: ModuleGraph) =
|
||||
else:
|
||||
os.sleep 250
|
||||
idle += 1
|
||||
if idle == 20 and gRefresh and conf.suggestVersion != 3:
|
||||
if idle == 20 and gRefresh and conf.suggestVersion < 3:
|
||||
# we use some nimsuggest activity to enable a lazy recompile:
|
||||
conf.ideCmd = ideChk
|
||||
conf.writelnHook = proc (s: string) = discard
|
||||
@@ -581,7 +593,7 @@ proc mainCommand(graph: ModuleGraph) =
|
||||
# do not print errors, but log them
|
||||
conf.writelnHook = proc (msg: string) = discard
|
||||
|
||||
if graph.config.suggestVersion == 3:
|
||||
if graph.config.suggestVersion >= 3:
|
||||
graph.config.structuredErrorHook = proc (conf: ConfigRef; info: TLineInfo; msg: string; sev: Severity) =
|
||||
let suggest = Suggest(section: ideChk, filePath: toFullPath(conf, info),
|
||||
line: toLinenumber(info), column: toColumn(info), doc: msg, forth: $sev)
|
||||
@@ -595,6 +607,9 @@ proc mainCommand(graph: ModuleGraph) =
|
||||
open(requests)
|
||||
open(results)
|
||||
|
||||
if graph.config.clientProcessId != 0:
|
||||
hookProcMonitor(graph.config.clientProcessId)
|
||||
|
||||
case gMode
|
||||
of mstdin: createThread(inputThread, replStdin, (gPort, gAddress))
|
||||
of mtcp: createThread(inputThread, replTcp, (gPort, gAddress))
|
||||
@@ -645,6 +660,17 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) =
|
||||
of "v1": conf.suggestVersion = 1
|
||||
of "v2": conf.suggestVersion = 0
|
||||
of "v3": conf.suggestVersion = 3
|
||||
of "v4": conf.suggestVersion = 4
|
||||
of "info":
|
||||
case p.val.normalize
|
||||
of "protocolver":
|
||||
stdout.writeLine(HighestSuggestProtocolVersion)
|
||||
quit 0
|
||||
of "nimver":
|
||||
stdout.writeLine(system.NimVersion)
|
||||
quit 0
|
||||
else:
|
||||
processSwitch(pass, p, conf)
|
||||
of "tester":
|
||||
gMode = mstdin
|
||||
gEmitEof = true
|
||||
@@ -659,6 +685,8 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) =
|
||||
conf.suggestMaxResults = parseInt(p.val)
|
||||
of "find":
|
||||
findProject = true
|
||||
of "clientprocessid":
|
||||
conf.clientProcessId = parseInt(p.val)
|
||||
else: processSwitch(pass, p, conf)
|
||||
of cmdArgument:
|
||||
let a = unixToNativePath(p.key)
|
||||
@@ -756,6 +784,18 @@ proc findSymData(graph: ModuleGraph, trackPos: TLineInfo):
|
||||
result[] = s
|
||||
break
|
||||
|
||||
func isInRange*(current, startPos, endPos: TLineInfo, tokenLen: int): bool =
|
||||
result = current.fileIndex == startPos.fileIndex and
|
||||
(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):
|
||||
seq[SymInfoPair] =
|
||||
result = newSeq[SymInfoPair]()
|
||||
for s in graph.fileSymbols(startPos.fileIndex).deduplicateSymInfoPair:
|
||||
if isInRange(s.info, startPos, endPos, s.sym.name.s.len):
|
||||
result.add(s)
|
||||
|
||||
proc findSymData(graph: ModuleGraph, file: AbsoluteFile; line, col: int):
|
||||
ref SymInfoPair =
|
||||
let
|
||||
@@ -763,6 +803,14 @@ proc findSymData(graph: ModuleGraph, file: AbsoluteFile; line, col: int):
|
||||
trackPos = newLineInfo(fileIdx, line, col)
|
||||
result = findSymData(graph, trackPos)
|
||||
|
||||
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)
|
||||
|
||||
proc markDirtyIfNeeded(graph: ModuleGraph, file: string, originalFileIdx: FileIndex) =
|
||||
let sha = $sha1.secureHashFile(file)
|
||||
if graph.config.m.fileInfos[originalFileIdx.int32].hash != sha or graph.config.ideCmd == ideSug:
|
||||
@@ -785,6 +833,23 @@ proc suggestResult(graph: ModuleGraph, sym: PSym, info: TLineInfo,
|
||||
endLine = endLine, endCol = endCol)
|
||||
suggestResult(graph.config, suggest)
|
||||
|
||||
proc suggestInlayHintResult(graph: ModuleGraph, sym: PSym, info: TLineInfo,
|
||||
defaultSection = ideNone, endLine: uint16 = 0, endCol = 0) =
|
||||
let section = if defaultSection != ideNone:
|
||||
defaultSection
|
||||
elif sym.info.exactEquals(info):
|
||||
ideDef
|
||||
else:
|
||||
ideUse
|
||||
var suggestDef = symToSuggest(graph, sym, isLocal=false, section,
|
||||
info, 100, PrefixMatch.None, false, 0, true,
|
||||
endLine = endLine, endCol = endCol)
|
||||
suggestDef.inlayHintInfo = suggestToSuggestInlayHint(suggestDef)
|
||||
suggestDef.section = ideInlayHints
|
||||
if sym.kind == skForVar:
|
||||
suggestDef.inlayHintInfo.allowInsert = false
|
||||
suggestResult(graph.config, suggestDef)
|
||||
|
||||
const
|
||||
# kinds for ideOutline and ideGlobalSymbols
|
||||
searchableSymKinds = {skField, skEnumField, skIterator, skMethod, skFunc, skProc, skConverter, skTemplate}
|
||||
@@ -892,7 +957,7 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile,
|
||||
graph.markDirtyIfNeeded(dirtyFile.string, fileInfoIdx(conf, file))
|
||||
|
||||
# these commands require fully compiled project
|
||||
if cmd in {ideUse, ideDus, ideGlobalSymbols, ideChk} and graph.needsCompilation():
|
||||
if cmd in {ideUse, ideDus, ideGlobalSymbols, ideChk, ideInlayHints} and graph.needsCompilation():
|
||||
graph.recompilePartially()
|
||||
# when doing incremental build for the project root we should make sure that
|
||||
# everything is unmarked as no longer beeing dirty in case there is no
|
||||
@@ -1048,6 +1113,19 @@ proc executeNoHooksV3(cmd: IdeCmd, file: AbsoluteFile, dirtyfile: AbsoluteFile,
|
||||
|
||||
graph.markDirty fileIndex
|
||||
graph.markClientsDirty fileIndex
|
||||
of ideInlayHints:
|
||||
myLog fmt "Executing inlayHints"
|
||||
var endLine = 0
|
||||
var endCol = -1
|
||||
var i = 0
|
||||
i += skipWhile(tag, seps, i)
|
||||
i += parseInt(tag, endLine, i)
|
||||
i += skipWhile(tag, seps, i)
|
||||
i += parseInt(tag, endCol, i)
|
||||
let s = graph.findSymDataInRange(file, line, col, endLine, endCol)
|
||||
for q in s:
|
||||
if q.sym.kind in {skLet, skVar, skForVar, skConst} and q.isDecl and not q.sym.hasUserSpecifiedType:
|
||||
graph.suggestInlayHintResult(q.sym, q.info, ideInlayHints)
|
||||
else:
|
||||
myLog fmt "Discarding {cmd}"
|
||||
|
||||
|
||||
34
nimsuggest/procmonitor.nim
Normal file
34
nimsuggest/procmonitor.nim
Normal file
@@ -0,0 +1,34 @@
|
||||
# Monitor a client process and shutdown the current process, if the client
|
||||
# process is found to be dead
|
||||
|
||||
import os
|
||||
|
||||
when defined(posix):
|
||||
import posix_utils
|
||||
import posix
|
||||
|
||||
when defined(windows):
|
||||
import winlean
|
||||
|
||||
when defined(posix):
|
||||
proc monitorClientProcessIdThreadProc(pid: int) {.thread.} =
|
||||
while true:
|
||||
sleep(1000)
|
||||
try:
|
||||
sendSignal(Pid(pid), 0)
|
||||
except:
|
||||
discard kill(Pid(getCurrentProcessId()), cint(SIGTERM))
|
||||
|
||||
when defined(windows):
|
||||
proc monitorClientProcessIdThreadProc(pid: int) {.thread.} =
|
||||
var process = openProcess(SYNCHRONIZE, 0, DWORD(pid))
|
||||
if process != 0:
|
||||
discard waitForSingleObject(process, INFINITE)
|
||||
discard closeHandle(process)
|
||||
quit(0)
|
||||
|
||||
var tid: Thread[int]
|
||||
|
||||
proc hookProcMonitor*(pid: int) =
|
||||
when defined(posix) or defined(windows):
|
||||
createThread(tid, monitorClientProcessIdThreadProc, pid)
|
||||
15
nimsuggest/tests/tuse_enum.nim
Normal file
15
nimsuggest/tests/tuse_enum.nim
Normal file
@@ -0,0 +1,15 @@
|
||||
discard """
|
||||
$nimsuggest --tester $file
|
||||
>use $1
|
||||
def;;skEnumField;;tuse_enum.Colour.Red;;Colour;;$file;;10;;4;;"";;100
|
||||
use;;skEnumField;;tuse_enum.Colour.Red;;Colour;;$file;;14;;8;;"";;100
|
||||
"""
|
||||
|
||||
type
|
||||
Colour = enum
|
||||
Red
|
||||
Green
|
||||
Blue
|
||||
|
||||
discard #[!]#Red
|
||||
|
||||
@@ -46,7 +46,7 @@ pkg "BipBuffer"
|
||||
pkg "blscurve", allowFailure = true
|
||||
pkg "bncurve"
|
||||
pkg "brainfuck", "nim c -d:release -r tests/compile.nim"
|
||||
pkg "bump", "nim c --gc:arc --path:. -r tests/tbump.nim", "https://github.com/disruptek/bump", allowFailure = true
|
||||
pkg "bump", "nim c --mm:arc --path:. -r tests/tbump.nim", "https://github.com/disruptek/bump", allowFailure = true
|
||||
pkg "c2nim", "nim c testsuite/tester.nim"
|
||||
pkg "cascade"
|
||||
pkg "cello", url = "https://github.com/nim-lang/cello", useHead = true
|
||||
@@ -55,7 +55,7 @@ pkg "chroma"
|
||||
pkg "chronicles", "nim c -o:chr -r chronicles.nim"
|
||||
pkg "chronos", "nim c -r -d:release tests/testall"
|
||||
pkg "cligen", "nim c --path:. -r cligen.nim"
|
||||
pkg "combparser", "nimble test --gc:orc"
|
||||
pkg "combparser", "nimble test --mm:orc"
|
||||
pkg "compactdict"
|
||||
pkg "comprehension", "nimble test", "https://github.com/alehander92/comprehension"
|
||||
pkg "cowstrings"
|
||||
@@ -75,7 +75,7 @@ pkg "glob"
|
||||
pkg "ggplotnim", "nim c -d:noCairo -r tests/tests.nim"
|
||||
pkg "gittyup", "nimble test", "https://github.com/disruptek/gittyup", allowFailure = true
|
||||
pkg "gnuplot", "nim c gnuplot.nim"
|
||||
# pkg "gram", "nim c -r --gc:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram"
|
||||
# pkg "gram", "nim c -r --mm:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram"
|
||||
# pending https://github.com/nim-lang/Nim/issues/16509
|
||||
pkg "hts", "nim c -o:htss src/hts.nim"
|
||||
pkg "httpauth"
|
||||
@@ -91,13 +91,12 @@ pkg "lockfreequeues"
|
||||
pkg "macroutils"
|
||||
pkg "manu"
|
||||
pkg "markdown"
|
||||
pkg "measuremancer", "nimble install -y unchained@#HEAD; nimble -y test"
|
||||
pkg "measuremancer", "nimble testDeps; nimble -y test"
|
||||
# when unchained is version 0.3.7 or higher, use `nimble testDeps;`
|
||||
pkg "memo"
|
||||
pkg "msgpack4nim", "nim c -r tests/test_spec.nim"
|
||||
pkg "nake", "nim c nakefile.nim"
|
||||
pkg "neo", "nim c -d:blas=openblas --mm:refc tests/all.nim", "https://github.com/metagn/neo"
|
||||
# remove custom url when https://github.com/andreaferretti/neo/pull/53 is merged
|
||||
pkg "neo", "nim c -d:blas=openblas --mm:refc tests/all.nim"
|
||||
pkg "nesm", "nimble tests", "https://github.com/nim-lang/NESM", useHead = true
|
||||
pkg "netty"
|
||||
pkg "nico", allowFailure = true
|
||||
@@ -121,7 +120,7 @@ pkg "nimsl"
|
||||
pkg "nimsvg"
|
||||
pkg "nimterop", "nimble minitest", url = "https://github.com/nim-lang/nimterop"
|
||||
pkg "nimwc", "nim c nimwc.nim", allowFailure = true
|
||||
pkg "nimx", "nim c --threads:on test/main.nim", allowFailure = true
|
||||
pkg "nimx", "nim c test/main.nim", allowFailure = true
|
||||
pkg "nitter", "nim c src/nitter.nim", "https://github.com/zedeus/nitter"
|
||||
pkg "norm", "testament r tests/common/tmodel.nim"
|
||||
pkg "npeg", "nimble testarc"
|
||||
@@ -145,13 +144,13 @@ pkg "RollingHash", "nim c -r tests/test_cyclichash.nim"
|
||||
pkg "rosencrantz", "nim c -o:rsncntz -r rosencrantz.nim"
|
||||
pkg "sdl1", "nim c -r src/sdl.nim"
|
||||
pkg "sdl2_nim", "nim c -r sdl2/sdl.nim"
|
||||
pkg "sigv4", "nim c --gc:arc -r sigv4.nim", "https://github.com/disruptek/sigv4"
|
||||
pkg "sigv4", "nim c --mm:arc -r sigv4.nim", "https://github.com/disruptek/sigv4"
|
||||
pkg "sim"
|
||||
pkg "smtp", "nimble compileExample"
|
||||
pkg "snip", "nimble test", "https://github.com/genotrance/snip"
|
||||
pkg "ssostrings"
|
||||
pkg "stew"
|
||||
pkg "stint", "nim r stint.nim"
|
||||
pkg "stint", "nim c stint.nim"
|
||||
pkg "strslice"
|
||||
pkg "strunicode", "nim c -r --mm:refc src/strunicode.nim"
|
||||
pkg "supersnappy"
|
||||
@@ -168,12 +167,13 @@ pkg "timezones"
|
||||
pkg "tiny_sqlite"
|
||||
pkg "unicodedb", "nim c -d:release -r tests/tests.nim"
|
||||
pkg "unicodeplus", "nim c -d:release -r tests/tests.nim"
|
||||
pkg "union", "nim c -r tests/treadme.nim", url = "https://github.com/alaviss/union"
|
||||
pkg "unpack"
|
||||
pkg "weave", "nimble test_gc_arc", useHead = true
|
||||
pkg "websocket", "nim c websocket.nim"
|
||||
pkg "winim", "nim c winim.nim"
|
||||
pkg "with"
|
||||
pkg "ws", allowFailure = true
|
||||
pkg "yaml", "nim c -r test/tserialization.nim"
|
||||
pkg "yaml"
|
||||
pkg "zero_functional", "nim c -r test.nim"
|
||||
pkg "zippy"
|
||||
|
||||
@@ -51,3 +51,19 @@ type Bug[T] = object
|
||||
|
||||
var bug: Bug[int]
|
||||
doAssert sizeof(bug) == 128, "Oops my size is " & $sizeof(bug) # 16
|
||||
|
||||
|
||||
block: # bug #22419
|
||||
type
|
||||
ValidatorPubKey = object
|
||||
blob: array[96, byte]
|
||||
|
||||
proc f(): auto =
|
||||
return iterator() =
|
||||
var pad: int8 = 0
|
||||
var y {.align: 16.}: ValidatorPubKey
|
||||
let value = cast[uint64](addr y)
|
||||
doAssert value mod 16 == 0
|
||||
|
||||
f()()
|
||||
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
discard """
|
||||
cmd: '''nim c --gc:arc $file'''
|
||||
output: '''2
|
||||
2'''
|
||||
cmd: '''nim c --mm:arc $file'''
|
||||
output: '''
|
||||
2
|
||||
2
|
||||
destroyed
|
||||
'''
|
||||
"""
|
||||
|
||||
type
|
||||
ObjWithDestructor = object
|
||||
a: int
|
||||
proc `=destroy`(self: var ObjWithDestructor) =
|
||||
proc `=destroy`(self: ObjWithDestructor) =
|
||||
echo "destroyed"
|
||||
|
||||
proc `=`(self: var ObjWithDestructor, other: ObjWithDestructor) =
|
||||
proc `=copy`(self: var ObjWithDestructor, other: ObjWithDestructor) =
|
||||
echo "copied"
|
||||
|
||||
proc test(a: range[0..1], arg: ObjWithDestructor) =
|
||||
@@ -38,4 +41,4 @@ proc test(a: range[0..1], arg: ObjWithDestructor) =
|
||||
if iteration == 2:
|
||||
break
|
||||
|
||||
test(1, ObjWithDestructor())
|
||||
test(1, ObjWithDestructor())
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
discard """
|
||||
cmd: '''nim c --gc:arc $file'''
|
||||
output: '''2
|
||||
2'''
|
||||
cmd: '''nim c --mm:arc $file'''
|
||||
output: '''
|
||||
2
|
||||
2
|
||||
destroyed
|
||||
'''
|
||||
"""
|
||||
|
||||
type
|
||||
ObjWithDestructor = object
|
||||
a: int
|
||||
proc `=destroy`(self: var ObjWithDestructor) =
|
||||
proc `=destroy`(self: ObjWithDestructor) =
|
||||
echo "destroyed"
|
||||
|
||||
proc `=copy`(self: var ObjWithDestructor, other: ObjWithDestructor) =
|
||||
|
||||
@@ -223,3 +223,20 @@ for i in 0..100:
|
||||
var test = newSeqOfCap[uint32](1)
|
||||
test.setLen(1)
|
||||
doAssert test[0] == 0, $(test[0], i)
|
||||
|
||||
|
||||
# bug #22560
|
||||
doAssert len(newSeqOfCap[int](42)) == 0
|
||||
|
||||
block: # bug #17197
|
||||
type Matrix = seq[seq[int]]
|
||||
|
||||
proc needlemanWunsch(sequence1: string, sequence2: string, gap_penal: int8, match: int8, indel_penal: int8): bool =
|
||||
let seq2_len = sequence2.len
|
||||
|
||||
var grid: Matrix
|
||||
for i in sequence1:
|
||||
grid.add(newSeqOfCap[seq[int]](seq2_len))
|
||||
result = true
|
||||
|
||||
doAssert needlemanWunsch("ABC", "DEFG", 1, 2, 3)
|
||||
|
||||
@@ -2,8 +2,9 @@ discard """
|
||||
cmd: "nim check --warningAsError:UnreachableCode $file"
|
||||
action: "reject"
|
||||
nimout: '''
|
||||
tunreachable.nim(23, 3) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode]
|
||||
tunreachable.nim(30, 3) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode]
|
||||
tunreachable.nim(24, 3) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode]
|
||||
tunreachable.nim(31, 3) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode]
|
||||
tunreachable.nim(40, 3) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode]
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -30,3 +31,12 @@ proc main2() =
|
||||
echo "after"
|
||||
|
||||
main2()
|
||||
|
||||
proc main3() =
|
||||
if true:
|
||||
return
|
||||
else:
|
||||
return
|
||||
echo "after"
|
||||
|
||||
main3()
|
||||
@@ -39,7 +39,7 @@ proc foo(x: int): string {.nimcall, raises: [ValueError].} =
|
||||
|
||||
var p: MyProcType = foo #[tt.Error
|
||||
^
|
||||
type mismatch: got <proc (x: int): string{.nimcall, noSideEffect, gcsafe.}> but expected 'MyProcType = proc (x: int): string{.closure.}'
|
||||
type mismatch: got <proc (x: int): string{.nimcall, raises: [ValueError], noSideEffect, gcsafe.}> but expected 'MyProcType = proc (x: int): string{.closure.}'
|
||||
Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'.
|
||||
.raise effects differ
|
||||
]#
|
||||
|
||||
36
tests/exprs/t22604.nim
Normal file
36
tests/exprs/t22604.nim
Normal file
@@ -0,0 +1,36 @@
|
||||
# if
|
||||
for i in 0..<1:
|
||||
let x =
|
||||
case false
|
||||
of true:
|
||||
42
|
||||
of false:
|
||||
if true:
|
||||
continue
|
||||
else:
|
||||
raiseAssert "Won't get here"
|
||||
|
||||
# nested case
|
||||
for i in 0..<1:
|
||||
let x =
|
||||
case false
|
||||
of true:
|
||||
42
|
||||
of false:
|
||||
case true
|
||||
of true:
|
||||
continue
|
||||
of false:
|
||||
raiseAssert "Won't get here"
|
||||
|
||||
# try except
|
||||
for i in 0..<1:
|
||||
let x =
|
||||
case false
|
||||
of true:
|
||||
42
|
||||
of false:
|
||||
try:
|
||||
continue
|
||||
except:
|
||||
raiseAssert "Won't get here"
|
||||
7
tests/generics/m22373a.nim
Normal file
7
tests/generics/m22373a.nim
Normal file
@@ -0,0 +1,7 @@
|
||||
# module a for t22373
|
||||
|
||||
# original:
|
||||
type LightClientHeader* = object
|
||||
|
||||
# simplified:
|
||||
type TypeOrTemplate* = object
|
||||
18
tests/generics/m22373b.nim
Normal file
18
tests/generics/m22373b.nim
Normal file
@@ -0,0 +1,18 @@
|
||||
# module b for t22373
|
||||
|
||||
import m22373a
|
||||
|
||||
# original:
|
||||
type
|
||||
LightClientDataFork* {.pure.} = enum
|
||||
None = 0,
|
||||
Altair = 1
|
||||
template LightClientHeader*(kind: static LightClientDataFork): auto =
|
||||
when kind == LightClientDataFork.Altair:
|
||||
typedesc[m22373a.LightClientHeader]
|
||||
else:
|
||||
static: raiseAssert "Unreachable"
|
||||
|
||||
# simplified:
|
||||
template TypeOrTemplate*(num: int): untyped =
|
||||
typedesc[m22373a.TypeOrTemplate]
|
||||
25
tests/generics/t17509.nim
Normal file
25
tests/generics/t17509.nim
Normal file
@@ -0,0 +1,25 @@
|
||||
type List[O] = object
|
||||
next: ptr List[O]
|
||||
|
||||
proc initList[O](l: ptr List[O]) =
|
||||
l[].next = l
|
||||
|
||||
type
|
||||
PolytopeVertex[R] = object
|
||||
list: List[PolytopeVertex[R]]
|
||||
|
||||
PolytopeEdge[R] = object
|
||||
list: List[PolytopeEdge[R]]
|
||||
|
||||
Polytope[R] = object
|
||||
vertices: List[PolytopeVertex[R]]
|
||||
edges: List[PolytopeEdge[R]]
|
||||
|
||||
var pt: Polytope[float]
|
||||
|
||||
static:
|
||||
doAssert pt.vertices.next is (ptr List[PolytopeVertex[float]])
|
||||
doAssert pt.edges.next is (ptr List[PolytopeEdge[float]])
|
||||
|
||||
initList(addr pt.vertices)
|
||||
initList(addr pt.edges)
|
||||
16
tests/generics/t22373.nim
Normal file
16
tests/generics/t22373.nim
Normal file
@@ -0,0 +1,16 @@
|
||||
# issue #22373
|
||||
|
||||
import m22373a
|
||||
import m22373b
|
||||
|
||||
# original:
|
||||
template lazy_header(name: untyped): untyped {.dirty.} =
|
||||
var `name _ ptr`: ptr[data_fork.LightClientHeader] # this data_fork.Foo part seems required to reproduce
|
||||
proc createLightClientUpdates(data_fork: static LightClientDataFork) =
|
||||
lazy_header(attested_header)
|
||||
createLightClientUpdates(LightClientDataFork.Altair)
|
||||
|
||||
# simplified:
|
||||
proc generic[T](abc: T) =
|
||||
var x: abc.TypeOrTemplate
|
||||
generic(123)
|
||||
@@ -42,4 +42,23 @@ block: #4688
|
||||
|
||||
block: #4164
|
||||
proc printStr[T](s: static[string]): T = discard
|
||||
discard printStr[int]("hello static")
|
||||
discard printStr[int]("hello static")
|
||||
|
||||
import macros
|
||||
|
||||
block: # issue #9040, statics with template, macro, symchoice explicit generics
|
||||
block: # macro
|
||||
macro fun[N: static int](): untyped =
|
||||
newLit 1
|
||||
const a = fun[2]()
|
||||
doAssert a == 1
|
||||
block: # template
|
||||
template fun[N: static int](): untyped =
|
||||
1
|
||||
const a = fun[2]()
|
||||
doAssert a == 1
|
||||
block: # symchoice
|
||||
proc newSeq[x: static int](): int = 1
|
||||
template foo: int =
|
||||
newSeq[2]()
|
||||
doAssert foo() == 1
|
||||
|
||||
@@ -46,6 +46,11 @@ block tdotlookup:
|
||||
x.set("hello", "world")
|
||||
result = x
|
||||
doAssert abc(5) == 10
|
||||
block: # ensure normal call is consistent with dot call
|
||||
proc T(x: int): float = x.float
|
||||
proc foo[T](x: int) =
|
||||
doAssert typeof(T(x)) is typeof(x.T)
|
||||
foo[uint](123)
|
||||
|
||||
block tmodule_same_as_proc:
|
||||
# bug #1965
|
||||
|
||||
@@ -101,3 +101,14 @@ echo @(b.arr[0].arr), @(b.arr[1].arr)
|
||||
let y = b
|
||||
echo @(y.arr[0].arr), @(y.arr[1].arr)
|
||||
|
||||
import macros
|
||||
|
||||
block: # issue #5121
|
||||
type
|
||||
A = object
|
||||
AConst[X] = A
|
||||
|
||||
macro dumpType(t: typedesc): untyped =
|
||||
result = newTree(nnkTupleConstr, newLit $t.getType[1].typeKind, newLit t.getType[1].treeRepr)
|
||||
|
||||
doAssert dumpType(A) == ("ntyObject", "Sym \"A\"")
|
||||
|
||||
16
tests/generics/tuninstantiated_failure.nim
Normal file
16
tests/generics/tuninstantiated_failure.nim
Normal file
@@ -0,0 +1,16 @@
|
||||
discard """
|
||||
cmd: "nim check $file"
|
||||
"""
|
||||
|
||||
type
|
||||
Test[T, K] = object
|
||||
name: string
|
||||
Something = Test[int]
|
||||
|
||||
func `[]`[T, K](x: var Test[T, K], idx: int): var Test[T, K] =
|
||||
x
|
||||
|
||||
var b: Something
|
||||
# Should give a type-mismatch since Something isn't a valid Test
|
||||
b[0].name = "Test" #[tt.Error
|
||||
^ type mismatch]#
|
||||
@@ -78,3 +78,65 @@ block:
|
||||
doAssert x.data.len == 5
|
||||
var y: Leb128Buf[uint16]
|
||||
doAssert y.data.len == 3
|
||||
|
||||
import macros
|
||||
|
||||
block: # issue #12415
|
||||
macro isSomePointerImpl(t: typedesc): bool =
|
||||
var impl = t.getTypeInst[1].getTypeImpl
|
||||
if impl.kind == nnkDistinctTy:
|
||||
impl = impl[0].getTypeImpl
|
||||
if impl.kind in {nnkPtrTy,nnkRefTy}:
|
||||
result = newLit(true)
|
||||
elif impl.kind == nnkSym and impl.eqIdent("pointer"):
|
||||
result = newLit(true)
|
||||
else:
|
||||
result = newLit(false)
|
||||
|
||||
proc isSomePointer[T](t: typedesc[T]): bool {.compileTime.} =
|
||||
isSomePointerImpl(t)
|
||||
|
||||
type
|
||||
Option[T] = object
|
||||
## An optional type that stores its value and state separately in a boolean.
|
||||
when isSomePointer(typedesc(T)):
|
||||
val: T
|
||||
else:
|
||||
val: T
|
||||
has: bool
|
||||
var x: Option[ref int]
|
||||
doAssert not compiles(x.has)
|
||||
var y: Option[int]
|
||||
doAssert compiles(y.has)
|
||||
|
||||
block: # issue #2002
|
||||
proc isNillable(T: typedesc): bool =
|
||||
when compiles((let v: T = nil)):
|
||||
return true
|
||||
else:
|
||||
return false
|
||||
|
||||
type
|
||||
Foo[T] = object
|
||||
when isNillable(T):
|
||||
nillable: float
|
||||
else:
|
||||
notnillable: int
|
||||
|
||||
var val1: Foo[ref int]
|
||||
doAssert compiles(val1.nillable)
|
||||
doAssert not compiles(val1.notnillable)
|
||||
var val2: Foo[int]
|
||||
doAssert not compiles(val2.nillable)
|
||||
doAssert compiles(val2.notnillable)
|
||||
|
||||
block: # issue #1771
|
||||
type
|
||||
Foo[X, T] = object
|
||||
bar: array[X.low..X.high, T]
|
||||
|
||||
proc test[X, T](f: Foo[X, T]): T =
|
||||
f.bar[X.low]
|
||||
|
||||
var a: Foo[range[0..2], float]
|
||||
doAssert test(a) == 0.0
|
||||
|
||||
79
tests/iter/t22619.nim
Normal file
79
tests/iter/t22619.nim
Normal file
@@ -0,0 +1,79 @@
|
||||
# bug #22619
|
||||
|
||||
when false: # todo fixme
|
||||
block:
|
||||
type
|
||||
Resource = object
|
||||
value: int
|
||||
|
||||
Object = object
|
||||
r {.cursor.}: Resource
|
||||
s {.cursor.}: seq[Resource]
|
||||
|
||||
var numDestroy = 0
|
||||
|
||||
proc `=copy`(x: var Resource, y: Resource) {.error.} # disallow full copies
|
||||
proc `=destroy`(x: Resource) =
|
||||
inc numDestroy
|
||||
|
||||
proc test() =
|
||||
# perform the test in procedure so that globals aren't used (their different
|
||||
# semantics with regards to destruction would interfere)
|
||||
var
|
||||
r = Resource(value: 1) # initialize a resource
|
||||
s = @[Resource(value: 2)]
|
||||
|
||||
# make sure no copy is required in the initializer expression:
|
||||
var o = Object(r: r, s: s)
|
||||
|
||||
# copying the object doesn't perform a full copy of the cursor fields:
|
||||
var o2 = o
|
||||
discard addr(o2) # prevent `o2` from being turned into a cursor
|
||||
|
||||
# check that the fields were shallow-copied:
|
||||
doAssert o2.r.value == 1
|
||||
doAssert o2.s[0].value == 2
|
||||
|
||||
# make sure no copy is required with normal field assignments:
|
||||
o.r = r
|
||||
o.s = s
|
||||
|
||||
|
||||
# when `o` and `o2` are destroyed, their destructor must not be called on
|
||||
# their fields
|
||||
|
||||
test()
|
||||
|
||||
# one call for the `r` local and one for the object in `s`
|
||||
doAssert numDestroy == 2
|
||||
|
||||
block:
|
||||
type Value = distinct int
|
||||
|
||||
var numDestroy = 0
|
||||
|
||||
proc `=destroy`(x: Value) =
|
||||
inc numDestroy
|
||||
|
||||
iterator iter(s: seq[Value]): int {.closure.} =
|
||||
# because it is used across yields, `s2` is lifted into the iterator's
|
||||
# environment. Since non-ref cursors in object didn't have their hooks
|
||||
# disabled inside the environments lifted hooks, this led to double
|
||||
# frees
|
||||
var s2 {.cursor.} = s
|
||||
var i = 0
|
||||
let L = s2.len
|
||||
while i < L:
|
||||
yield s2[i].int
|
||||
inc i
|
||||
|
||||
proc test() =
|
||||
var s = @[Value(1), Value(2)]
|
||||
let cl = iter
|
||||
# make sure resuming the iterator works:
|
||||
doAssert cl(s) == 1
|
||||
doAssert cl(s) == 2
|
||||
doAssert cl(s) == 0
|
||||
|
||||
test()
|
||||
doAssert numDestroy == 2
|
||||
@@ -268,6 +268,37 @@ xbenchmark:
|
||||
discard inputtest
|
||||
fastSHA("hey")
|
||||
|
||||
block: # issue #4547
|
||||
macro lazy(stmtList : typed) : untyped =
|
||||
let decl = stmtList[0]
|
||||
decl.expectKind nnkLetSection
|
||||
let name = decl[0][0].strVal
|
||||
let call = decl[0][2].copy
|
||||
call.expectKind nnkCall
|
||||
let ident = newIdentNode("get" & name)
|
||||
result = quote do:
|
||||
var value : type(`call`)
|
||||
proc `ident`() : type(`call`) =
|
||||
if value.isNil:
|
||||
value = `call`
|
||||
value
|
||||
type MyObject = object
|
||||
a,b: int
|
||||
# this part, the macro call and it's result (written in the comment below) is important
|
||||
lazy:
|
||||
let y = new(MyObject)
|
||||
#[
|
||||
var value: type(new(MyObject))
|
||||
proc gety(): type(new(MyObject)) =
|
||||
if value.isNil:
|
||||
value = new(MyObject)
|
||||
value
|
||||
]#
|
||||
doAssert gety().a == 0 # works and should work
|
||||
doAssert gety().b == 0 # works and should work
|
||||
doAssert not declared(y)
|
||||
doAssert not compiles(y.a) # identifier y should not exist anymore
|
||||
doAssert not compiles(y.b) # identifier y should not exist anymore
|
||||
|
||||
block: # bug #13511
|
||||
type
|
||||
|
||||
@@ -271,10 +271,13 @@ sub/mmain.idx""", context
|
||||
check execCmdEx(cmd) == ("12\n", 0)
|
||||
|
||||
block: # bug #15316
|
||||
let file = testsDir / "misc/m15316.nim"
|
||||
let cmd = fmt"{nim} check --hints:off --nimcache:{nimcache} {file}"
|
||||
check execCmdEx(cmd) == ("m15316.nim(1, 15) Error: expression expected, but found \')\'\nm15316.nim(2, 1) Error: expected: \':\', but got: \'[EOF]\'\nm15316.nim(2, 1) Error: expression expected, but found \'[EOF]\'\nm15316.nim(2, 1) " &
|
||||
"Error: expected: \')\', but got: \'[EOF]\'\nError: illformed AST: \n", 1)
|
||||
when not defined(windows):
|
||||
# This never worked reliably on Windows. Needs further investigation but it is hard to reproduce.
|
||||
# Looks like a mild stack corruption when bailing out of nested exception handling.
|
||||
let file = testsDir / "misc/m15316.nim"
|
||||
let cmd = fmt"{nim} check --hints:off --nimcache:{nimcache} {file}"
|
||||
check execCmdEx(cmd) == ("m15316.nim(1, 15) Error: expression expected, but found \')\'\nm15316.nim(2, 1) Error: expected: \':\', but got: \'[EOF]\'\nm15316.nim(2, 1) Error: expression expected, but found \'[EOF]\'\nm15316.nim(2, 1) " &
|
||||
"Error: expected: \')\', but got: \'[EOF]\'\nError: illformed AST: \n", 1)
|
||||
|
||||
|
||||
block: # config.nims, nim.cfg, hintConf, bug #16557
|
||||
|
||||
@@ -55,3 +55,35 @@ type
|
||||
x: int
|
||||
when (NimMajor, NimMinor) >= (1, 1):
|
||||
y: int
|
||||
discard MyObject(x: 100, y: 200)
|
||||
|
||||
block: # Ensure when evaluates properly in objects
|
||||
type X[bits: static int] = object #22474
|
||||
when bits >= 256:
|
||||
data32: byte
|
||||
else:
|
||||
data16: byte
|
||||
|
||||
static:
|
||||
discard X[255]().data16
|
||||
discard X[256]().data32
|
||||
|
||||
|
||||
type ComplexExprObject[S: static string, I: static int, Y: static auto] = object
|
||||
when 'h' in S and I < 10 and Y isnot float:
|
||||
a: int
|
||||
elif I > 30:
|
||||
b: int
|
||||
elif typeof(Y) is float:
|
||||
c: int
|
||||
else:
|
||||
d: int
|
||||
|
||||
static:
|
||||
discard ComplexExprObject["hello", 9, 300i32]().a
|
||||
discard ComplexExprObject["", 40, 30f]().b
|
||||
discard ComplexExprObject["", 20, float 30]().c
|
||||
discard ComplexExprObject["", 20, ""]().d
|
||||
|
||||
|
||||
|
||||
|
||||
3
tests/statictypes/t5780.nim
Normal file
3
tests/statictypes/t5780.nim
Normal file
@@ -0,0 +1,3 @@
|
||||
type StringArray[N:int] = array[N, string]
|
||||
let a = ["one", "two"]
|
||||
doAssert a is StringArray
|
||||
@@ -53,5 +53,9 @@ template main() =
|
||||
doAssert encode("", safe = true) == ""
|
||||
doAssert encode("the quick brown dog jumps over the lazy fox", safe = true) == "dGhlIHF1aWNrIGJyb3duIGRvZyBqdW1wcyBvdmVyIHRoZSBsYXp5IGZveA=="
|
||||
|
||||
func mainNoSideEffects() = main()
|
||||
|
||||
static: main()
|
||||
main()
|
||||
static: mainNoSideEffects()
|
||||
mainNoSideEffects()
|
||||
|
||||
@@ -334,3 +334,16 @@ block:
|
||||
`hello`(12, type(x))
|
||||
|
||||
main()
|
||||
|
||||
block: # bug #22947
|
||||
macro bar[N: static int](a: var array[N, int]) =
|
||||
result = quote do:
|
||||
for i in 0 ..< `N`:
|
||||
`a`[i] = i
|
||||
|
||||
func foo[N: static int](a: var array[N, int]) =
|
||||
bar(a)
|
||||
|
||||
|
||||
var a: array[4, int]
|
||||
foo(a)
|
||||
|
||||
@@ -20,7 +20,8 @@ block:
|
||||
discard x.s
|
||||
|
||||
proc main =
|
||||
var x = X(s: "abcdefg")
|
||||
let m = "abcdefg"
|
||||
var x = X(s: ensureMove m)
|
||||
consume(ensureMove x)
|
||||
|
||||
static: main()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
errormsg: "'if true: s else: String()' is not a mutable location; it cannot be moved"
|
||||
errormsg: "Nested expressions cannot be moved: 'if true: s else: String()'"
|
||||
"""
|
||||
|
||||
type
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
discard """
|
||||
matrix: "--gc:none -d:useMalloc --threads:off"
|
||||
matrix: "--mm:none -d:useMalloc"
|
||||
"""
|
||||
# bug #15617
|
||||
# bug #22262
|
||||
let x = 4
|
||||
doAssert x == 4
|
||||
|
||||
@@ -48,3 +48,35 @@ template publicTemplateObjSyntax*(o: var ObjA, arg: Natural, doStuff: untyped) =
|
||||
o.foo2()
|
||||
doStuff
|
||||
o.bar2(arg)
|
||||
|
||||
# issue #15246
|
||||
import os
|
||||
|
||||
template sourceBaseName*(): string =
|
||||
bind splitFile
|
||||
instantiationInfo().filename.splitFile().name
|
||||
|
||||
# issue #12683
|
||||
|
||||
import unicode
|
||||
template toRune(s: string): Rune = s.runeAt(0)
|
||||
proc heh*[T](x: Slice[T], chars: string) = discard chars.toRune
|
||||
|
||||
# issue #7889
|
||||
|
||||
from streams import newStringStream, readData, writeData
|
||||
|
||||
template bindmeTemplate*(): untyped =
|
||||
var tst = "sometext"
|
||||
var ss = newStringStream("anothertext")
|
||||
ss.writeData(tst[0].addr, 2)
|
||||
discard ss.readData(tst[0].addr, 2) # <= comment this out to make compilation successful
|
||||
|
||||
from macros import quote, newIdentNode
|
||||
|
||||
macro bindmeQuote*(): untyped =
|
||||
quote do:
|
||||
var tst = "sometext"
|
||||
var ss = newStringStream("anothertext")
|
||||
ss.writeData(tst[0].addr, 2)
|
||||
discard ss.readData(tst[0].addr, 2) # <= comment this out to make compilation successful
|
||||
|
||||
8
tests/template/t21532.nim
Normal file
8
tests/template/t21532.nim
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
template elementType(a: untyped): typedesc =
|
||||
typeof(block: (for ai in a: ai))
|
||||
|
||||
func fn[T](a: T) =
|
||||
doAssert elementType(a) is int
|
||||
|
||||
@[1,2,3].fn
|
||||
@@ -18,3 +18,15 @@ block: # issue #11733
|
||||
var evaluated = false
|
||||
a.publicTemplateObjSyntax(42): evaluated = true
|
||||
doAssert evaluated
|
||||
|
||||
block: # issue #15246
|
||||
doAssert sourceBaseName() == "tdotcall"
|
||||
|
||||
block: # issue #12683
|
||||
heh(0..40, "|")
|
||||
|
||||
block: # issue #7889
|
||||
if false:
|
||||
bindmeQuote()
|
||||
if false:
|
||||
bindmeTemplate()
|
||||
|
||||
@@ -302,3 +302,7 @@ block: # bug #21920
|
||||
discard
|
||||
|
||||
t[void]() # Error: expression has no type: discard
|
||||
|
||||
block: # issue #19865
|
||||
template f() = discard default(system.int)
|
||||
f()
|
||||
|
||||
@@ -354,6 +354,23 @@ block gensym3:
|
||||
echo a ! b ! c ! d ! e
|
||||
echo x,y,z
|
||||
|
||||
block: # issue #2465
|
||||
template t() =
|
||||
template declX(str: string) {.gensym.} =
|
||||
var x {.inject.} : string = str
|
||||
|
||||
t()
|
||||
doAssert not declared(declX)
|
||||
doAssert not compiles(declX("a string"))
|
||||
|
||||
template t2() =
|
||||
template fooGensym() {.gensym.} =
|
||||
echo 42
|
||||
|
||||
t2()
|
||||
doAssert not declared(fooGensym)
|
||||
doAssert not compiles(fooGensym())
|
||||
|
||||
|
||||
block identifier_construction_with_overridden_symbol:
|
||||
# could use add, but wanna make sure it's an override no matter what
|
||||
@@ -368,3 +385,22 @@ block identifier_construction_with_overridden_symbol:
|
||||
`examplefn n`()
|
||||
|
||||
exampletempl(1)
|
||||
|
||||
import typetraits
|
||||
|
||||
block: # issue #4596
|
||||
type
|
||||
T0 = object
|
||||
T1 = object
|
||||
|
||||
template printFuncsT() =
|
||||
proc getV[A](a: typedesc[A]): string =
|
||||
var s {. global .} = name(A)
|
||||
return s
|
||||
|
||||
printFuncsT()
|
||||
|
||||
doAssert getV(T1) == "T1"
|
||||
doAssert getV(T0) == "T0"
|
||||
doAssert getV(T0) == "T0"
|
||||
doAssert getV(T1) == "T1"
|
||||
|
||||
80
tests/template/tgenericparam.nim
Normal file
80
tests/template/tgenericparam.nim
Normal file
@@ -0,0 +1,80 @@
|
||||
block: # basic template generic parameter substitution
|
||||
block: # issue #13527
|
||||
template typeNameTempl[T](a: T): string = $T
|
||||
proc typeNameProc[T](a: T): string = $T
|
||||
doAssert typeNameTempl(1) == typeNameProc(1)
|
||||
doAssert typeNameTempl(true) == typeNameProc(true)
|
||||
doAssert typeNameTempl(1.0) == typeNameProc(1.0)
|
||||
doAssert typeNameTempl(1u8) == typeNameProc(1u8)
|
||||
|
||||
template isDefault[T](a: T): bool = a == default(T)
|
||||
doAssert isDefault(0.0)
|
||||
|
||||
block: # issue #17240
|
||||
func to(c: int, t: typedesc[float]): t = discard
|
||||
template converted[I, T](i: seq[I], t: typedesc[T]): seq[T] =
|
||||
var result = newSeq[T](2)
|
||||
result[0] = i[0].to(T)
|
||||
result
|
||||
doAssert newSeq[int](3).converted(float) == @[0.0, 0.0]
|
||||
|
||||
block: # issue #6340
|
||||
type A[T] = object
|
||||
v: T
|
||||
proc foo(x: int): string = "int"
|
||||
proc foo(x: typedesc[int]): string = "typedesc[int]"
|
||||
template fooT(x: int): string = "int"
|
||||
template fooT(x: typedesc[int]): string = "typedesc[int]"
|
||||
proc foo[T](x: A[T]): (string, string) =
|
||||
(foo(T), fooT(T))
|
||||
template fooT[T](x: A[T]): (string, string) =
|
||||
(foo(T), fooT(T))
|
||||
var x: A[int]
|
||||
doAssert foo(x) == fooT(x)
|
||||
|
||||
block: # issue #20033
|
||||
template run[T](): T = default(T)
|
||||
doAssert run[int]() == 0
|
||||
|
||||
import options, tables
|
||||
|
||||
block: # complex cases of above with imports
|
||||
block: # issue #19576, complex case
|
||||
type RegistryKey = object
|
||||
key, val: string
|
||||
var regKey = @[RegistryKey(key: "abc", val: "def")]
|
||||
template findFirst[T](s: seq[T], pred: proc(x: T): bool): Option[T] =
|
||||
var res = none(T) # important line
|
||||
for x in s:
|
||||
if pred(x):
|
||||
res = some(x)
|
||||
break
|
||||
res
|
||||
proc getval(searchKey: string): Option[string] =
|
||||
let found = regKey.findFirst(proc (rk: RegistryKey): bool = rk.key == searchKey)
|
||||
if found.isNone: none(string)
|
||||
else: some(found.get().val)
|
||||
doAssert getval("strange") == none(string)
|
||||
doAssert getval("abc") == some("def")
|
||||
block: # issue #19076
|
||||
block: # case 1
|
||||
var tested: Table[string,int]
|
||||
template `[]`[V](t:Table[string,V],key:string):untyped =
|
||||
$V
|
||||
doAssert tested["abc"] == "int"
|
||||
template `{}`[V](t:Table[string,V],key:string):untyped =
|
||||
($V, tables.`[]`(t, key))
|
||||
doAssert (try: tested{"abc"} except KeyError: ("not there", 123)) == ("not there", 123)
|
||||
tables.`[]=`(tested, "abc", 456)
|
||||
doAssert tested["abc"] == "int"
|
||||
doAssert tested{"abc"} == ("int", 456)
|
||||
block: # case 2
|
||||
type Foo[A,T] = object
|
||||
t:T
|
||||
proc init[A,T](f:type Foo,a:typedesc[A],t:T):Foo[A,T] = Foo[A,T](t:t)
|
||||
template fromOption[A](o:Option[A]):auto =
|
||||
when o.isSome:
|
||||
Foo.init(A,35)
|
||||
else:
|
||||
Foo.init(A,"hi")
|
||||
let op = fromOption(some(5))
|
||||
@@ -1,12 +1,21 @@
|
||||
var x = 0
|
||||
block: # issue #16005
|
||||
var x = 0
|
||||
|
||||
block:
|
||||
type Foo = object
|
||||
x: float # ok
|
||||
|
||||
template main() =
|
||||
block:
|
||||
type Foo = object
|
||||
x: float # Error: cannot use symbol of kind 'var' as a 'field'
|
||||
x: float # ok
|
||||
|
||||
main()
|
||||
template main() =
|
||||
block:
|
||||
type Foo = object
|
||||
x: float # Error: cannot use symbol of kind 'var' as a 'field'
|
||||
|
||||
main()
|
||||
|
||||
block: # issue #19552
|
||||
template test =
|
||||
type
|
||||
test2 = ref object
|
||||
reset: int
|
||||
|
||||
test()
|
||||
|
||||
32
tests/types/t5648.nim
Normal file
32
tests/types/t5648.nim
Normal file
@@ -0,0 +1,32 @@
|
||||
discard """
|
||||
output: '''
|
||||
ptr Foo
|
||||
'''
|
||||
joinable: false
|
||||
"""
|
||||
# not joinable because it causes out of memory with --gc:boehm
|
||||
|
||||
# issue #5648
|
||||
|
||||
import typetraits
|
||||
|
||||
type Foo = object
|
||||
bar: int
|
||||
|
||||
proc main() =
|
||||
var f = create(Foo)
|
||||
f.bar = 3
|
||||
echo f.type.name
|
||||
|
||||
discard realloc(f, 0)
|
||||
|
||||
var g = Foo()
|
||||
g.bar = 3
|
||||
|
||||
var
|
||||
mainPtr = cast[pointer](main)
|
||||
mainFromPtr = cast[typeof(main)](mainPtr)
|
||||
|
||||
doAssert main == mainFromPtr
|
||||
|
||||
main()
|
||||
@@ -3,7 +3,6 @@ discard """
|
||||
true
|
||||
true
|
||||
true
|
||||
ptr Foo
|
||||
(member: "hello world")
|
||||
(member: 123.456)
|
||||
(member: "hello world", x: ...)
|
||||
@@ -11,10 +10,7 @@ ptr Foo
|
||||
0
|
||||
false
|
||||
'''
|
||||
joinable: false
|
||||
"""
|
||||
# not joinable because it causes out of memory with --gc:boehm
|
||||
import typetraits
|
||||
|
||||
block t1252:
|
||||
echo float32 isnot float64
|
||||
@@ -29,28 +25,6 @@ block t5640:
|
||||
|
||||
var v = vec2([0.0'f32, 0.0'f32])
|
||||
|
||||
block t5648:
|
||||
type Foo = object
|
||||
bar: int
|
||||
|
||||
proc main() =
|
||||
var f = create(Foo)
|
||||
f.bar = 3
|
||||
echo f.type.name
|
||||
|
||||
discard realloc(f, 0)
|
||||
|
||||
var g = Foo()
|
||||
g.bar = 3
|
||||
|
||||
var
|
||||
mainPtr = cast[pointer](main)
|
||||
mainFromPtr = cast[typeof(main)](mainPtr)
|
||||
|
||||
doAssert main == mainFromPtr
|
||||
|
||||
main()
|
||||
|
||||
block t7581:
|
||||
discard int -1
|
||||
|
||||
@@ -107,3 +81,18 @@ block:
|
||||
|
||||
var f1: Foo
|
||||
echo f1.bar
|
||||
|
||||
import macros
|
||||
|
||||
block: # issue #12582
|
||||
macro foo(T: type): type =
|
||||
nnkBracketExpr.newTree(bindSym "array", newLit 1, T)
|
||||
var
|
||||
_: foo(int) # fine
|
||||
type
|
||||
Foo = object
|
||||
x: foo(int) # fine
|
||||
Bar = ref object
|
||||
x: foo(int) # error
|
||||
let b = Bar()
|
||||
let b2 = Bar(x: [123])
|
||||
|
||||
32
tests/vm/tnoreturn.nim
Normal file
32
tests/vm/tnoreturn.nim
Normal file
@@ -0,0 +1,32 @@
|
||||
block: # issue #22216
|
||||
type
|
||||
Result[T, E] = object
|
||||
case oVal: bool
|
||||
of false:
|
||||
eVal: E
|
||||
of true:
|
||||
vVal: T
|
||||
|
||||
func raiseResultDefect(m: string) {.noreturn, noinline.} =
|
||||
raise (ref Defect)(msg: m)
|
||||
|
||||
template withAssertOk(self: Result, body: untyped): untyped =
|
||||
case self.oVal
|
||||
of false:
|
||||
raiseResultDefect("Trying to access value with err Result")
|
||||
else:
|
||||
body
|
||||
|
||||
func value[T, E](self: Result[T, E]): T {.inline.} =
|
||||
withAssertOk(self):
|
||||
self.vVal
|
||||
|
||||
const
|
||||
x = Result[int, string](oVal: true, vVal: 123)
|
||||
z = x.value()
|
||||
|
||||
let
|
||||
xx = Result[int, string](oVal: true, vVal: 123)
|
||||
zz = x.value()
|
||||
|
||||
doAssert z == zz
|
||||
18
tests/vm/ttypedesc.nim
Normal file
18
tests/vm/ttypedesc.nim
Normal file
@@ -0,0 +1,18 @@
|
||||
block: # issue #15760
|
||||
type
|
||||
Banana = object
|
||||
SpecialBanana = object
|
||||
|
||||
proc getName(_: type Banana): string = "Banana"
|
||||
proc getName(_: type SpecialBanana): string = "SpecialBanana"
|
||||
|
||||
proc x[T](): string =
|
||||
const n = getName(T) # this one works
|
||||
result = n
|
||||
|
||||
proc y(T: type): string =
|
||||
const n = getName(T) # this one failed to compile
|
||||
result = n
|
||||
|
||||
doAssert x[SpecialBanana]() == "SpecialBanana"
|
||||
doAssert y(SpecialBanana) == "SpecialBanana"
|
||||
3
tests/vm/tunsupportedintfloatcast.nim
Normal file
3
tests/vm/tunsupportedintfloatcast.nim
Normal file
@@ -0,0 +1,3 @@
|
||||
static:
|
||||
echo cast[int32](12.0) #[tt.Error
|
||||
^ VM does not support 'cast' from tyFloat with size 8 to tyInt32 with size 4 due to different sizes]#
|
||||
@@ -1,10 +1,11 @@
|
||||
# bug #4462
|
||||
import macros
|
||||
import os
|
||||
|
||||
# bug #4462
|
||||
block:
|
||||
proc foo(t: typedesc) {.compileTime.} =
|
||||
assert sameType(getType(t), getType(int))
|
||||
assert sameType(getType(t), getType(typedesc[int]))
|
||||
assert sameType(getType(t), getType(type int))
|
||||
|
||||
static:
|
||||
foo(int)
|
||||
@@ -733,3 +734,34 @@ block: # bug #22190
|
||||
tab = mkOpTable(Berlin)
|
||||
|
||||
doAssert not tab
|
||||
|
||||
block: # issue #22524
|
||||
const cnst = cstring(nil)
|
||||
doAssert cnst.isNil
|
||||
doAssert cnst == nil
|
||||
let b = cnst
|
||||
doAssert b.isNil
|
||||
doAssert b == nil
|
||||
|
||||
let a = static: cstring(nil)
|
||||
doAssert a.isNil
|
||||
|
||||
static:
|
||||
var x: cstring
|
||||
doAssert x.isNil
|
||||
doAssert x == nil
|
||||
doAssert x != ""
|
||||
|
||||
block: # issue #15730
|
||||
const s: cstring = ""
|
||||
doAssert s != nil
|
||||
|
||||
static:
|
||||
let s: cstring = ""
|
||||
doAssert not s.isNil
|
||||
doAssert s != nil
|
||||
doAssert s == ""
|
||||
|
||||
static: # more nil cstring issues
|
||||
let x = cstring(nil)
|
||||
doAssert x.len == 0
|
||||
|
||||
@@ -630,6 +630,7 @@ v("MSG_EOR")
|
||||
v("MSG_OOB")
|
||||
v("SCM_RIGHTS")
|
||||
v("SO_ACCEPTCONN")
|
||||
v("SO_BINDTODEVICE")
|
||||
v("SO_BROADCAST")
|
||||
v("SO_DEBUG")
|
||||
v("SO_DONTROUTE")
|
||||
|
||||
Reference in New Issue
Block a user