mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-27 17:11:40 +00:00
init checks and 'out' parameters (#14521)
* I don't care about observable stores * enforce explicit initializations * cleaner code for the stdlib * stdlib: use explicit initializations * make tests green * algorithm.nim: set result explicitly * remove out parameters and bring the PR into a mergable state * updated the changelog
This commit is contained in:
10
changelog.md
10
changelog.md
@@ -60,7 +60,7 @@
|
||||
accept an existing string to modify, which avoids memory
|
||||
allocations, similar to `streams.readLine` (#13857).
|
||||
|
||||
- Added high-level `asyncnet.sendTo` and `asyncnet.recvFrom`. UDP functionality.
|
||||
- Added high-level `asyncnet.sendTo` and `asyncnet.recvFrom` UDP functionality.
|
||||
|
||||
- `dollars.$` now works for unsigned ints with `nim js`
|
||||
|
||||
@@ -116,7 +116,11 @@
|
||||
- Add `random.gauss`, that uses the ratio of uniforms method of sampling from a Gaussian distribution.
|
||||
|
||||
## Language changes
|
||||
- In the newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this:
|
||||
- In the newruntime it is now allowed to assign to the discriminator field
|
||||
without restrictions as long as case object doesn't have custom destructor.
|
||||
The discriminator value doesn't have to be a constant either. If you have a
|
||||
custom destructor for a case object and you do want to freely assign discriminator
|
||||
fields, it is recommended to refactor object into 2 objects like this:
|
||||
|
||||
```nim
|
||||
type
|
||||
@@ -175,6 +179,8 @@ proc mydiv(a, b): int {.raises: [].} =
|
||||
The reason for this is that `DivByZeroDefect` inherits from `Defect` and
|
||||
with `--panics:on` `Defects` become unrecoverable errors.
|
||||
|
||||
- Added the `thiscall` calling convention as specified by Microsoft.
|
||||
|
||||
- Added `thiscall` calling convention as specified by Microsoft, mostly for hooking purpose
|
||||
- Deprecated `{.unroll.}` pragma, was ignored by the compiler anyways, was a nop.
|
||||
|
||||
|
||||
@@ -435,7 +435,8 @@ type
|
||||
# be any type.
|
||||
|
||||
tyOptDeprecated
|
||||
# deadcode: was `tyOpt`, Builtin optional type
|
||||
# 'out' parameter. Comparable to a 'var' parameter but every
|
||||
# path must assign a value to it before it can be read from.
|
||||
|
||||
tyVoid
|
||||
# now different from tyEmpty, hurray!
|
||||
@@ -1802,12 +1803,12 @@ proc skipStmtList*(n: PNode): PNode =
|
||||
else:
|
||||
result = n
|
||||
|
||||
proc toVar*(typ: PType): PType =
|
||||
proc toVar*(typ: PType; kind: TTypeKind): PType =
|
||||
## If ``typ`` is not a tyVar then it is converted into a `var <typ>` and
|
||||
## returned. Otherwise ``typ`` is simply returned as-is.
|
||||
result = typ
|
||||
if typ.kind != tyVar:
|
||||
result = newType(tyVar, typ.owner)
|
||||
if typ.kind != kind:
|
||||
result = newType(kind, typ.owner)
|
||||
rawAddSon(result, typ)
|
||||
|
||||
proc toRef*(typ: PType): PType =
|
||||
@@ -1934,3 +1935,6 @@ proc toHumanStr*(kind: TSymKind): string =
|
||||
proc toHumanStr*(kind: TTypeKind): string =
|
||||
## strips leading `tk`
|
||||
result = toHumanStrImpl(kind, 2)
|
||||
|
||||
proc skipAddr*(n: PNode): PNode {.inline.} =
|
||||
(if n.kind == nkHiddenAddr: n[0] else: n)
|
||||
|
||||
@@ -178,10 +178,10 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
|
||||
result = "($4*)($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dest]
|
||||
of tyString, tySequence:
|
||||
let atyp = skipTypes(a.t, abstractInst)
|
||||
if formalType.skipTypes(abstractInst).kind == tyVar and atyp.kind == tyString and
|
||||
if formalType.skipTypes(abstractInst).kind in {tyVar} and atyp.kind == tyString and
|
||||
optSeqDestructors in p.config.globalOptions:
|
||||
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
||||
if atyp.kind == tyVar and not compileToCpp(p.module):
|
||||
if atyp.kind in {tyVar} and not compileToCpp(p.module):
|
||||
result = "($5*)(*$1)$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest]
|
||||
else:
|
||||
result = "($5*)$1$4+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), dataField(p), dest]
|
||||
@@ -194,10 +194,10 @@ proc openArrayLoc(p: BProc, formalType: PType, n: PNode): Rope =
|
||||
result = "$1, $1Len_0" % [rdLoc(a)]
|
||||
of tyString, tySequence:
|
||||
let ntyp = skipTypes(n.typ, abstractInst)
|
||||
if formalType.skipTypes(abstractInst).kind == tyVar and ntyp.kind == tyString and
|
||||
if formalType.skipTypes(abstractInst).kind in {tyVar} and ntyp.kind == tyString and
|
||||
optSeqDestructors in p.config.globalOptions:
|
||||
linefmt(p, cpsStmts, "#nimPrepareStrMutationV2($1);$n", [byRefLoc(p, a)])
|
||||
if ntyp.kind == tyVar and not compileToCpp(p.module):
|
||||
if ntyp.kind in {tyVar} and not compileToCpp(p.module):
|
||||
var t: TLoc
|
||||
t.r = "(*$1)" % [a.rdLoc]
|
||||
result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)]
|
||||
@@ -232,7 +232,7 @@ proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): Rope =
|
||||
elif ccgIntroducedPtr(p.config, param, call[0].typ[0]):
|
||||
initLocExpr(p, n, a)
|
||||
result = addrLoc(p.config, a)
|
||||
elif p.module.compileToCpp and param.typ.kind == tyVar and
|
||||
elif p.module.compileToCpp and param.typ.kind in {tyVar} and
|
||||
n.kind == nkHiddenAddr:
|
||||
initLocExprSingleUse(p, n[0], a)
|
||||
# if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
|
||||
@@ -372,7 +372,7 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
|
||||
assert(paramType.kind == nkSym)
|
||||
if paramType.typ.isCompileTimeOnly:
|
||||
result = nil
|
||||
elif typ[i].kind == tyVar and ri[i].kind == nkHiddenAddr:
|
||||
elif typ[i].kind in {tyVar} and ri[i].kind == nkHiddenAddr:
|
||||
result = genArgNoParam(p, ri[i][0])
|
||||
else:
|
||||
result = genArgNoParam(p, ri[i]) #, typ.n[i].sym)
|
||||
@@ -449,7 +449,7 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
|
||||
var ri = ri[i]
|
||||
while ri.kind == nkObjDownConv: ri = ri[0]
|
||||
let t = typ[i].skipTypes({tyGenericInst, tyAlias, tySink})
|
||||
if t.kind == tyVar:
|
||||
if t.kind in {tyVar}:
|
||||
let x = if ri.kind == nkHiddenAddr: ri[0] else: ri
|
||||
if x.typ.kind == tyPtr:
|
||||
result = genArgNoParam(p, x)
|
||||
|
||||
@@ -126,9 +126,8 @@ proc genRawSetData(cs: TBitSet, size: int): Rope =
|
||||
result = intLiteral(cast[BiggestInt](bitSetToWord(cs, size)))
|
||||
|
||||
proc genSetNode(p: BProc, n: PNode): Rope =
|
||||
var cs: TBitSet
|
||||
var size = int(getSize(p.config, n.typ))
|
||||
toBitSet(p.config, n, cs)
|
||||
let cs = toBitSet(p.config, n)
|
||||
if size > 8:
|
||||
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
|
||||
result = p.module.tmpBase & rope(id)
|
||||
@@ -676,7 +675,7 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
|
||||
proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
|
||||
result = p.module.compileToCpp and
|
||||
skipTypes(typ, abstractInstOwned).kind == tyVar and
|
||||
skipTypes(typ, abstractInstOwned).kind in {tyVar} and
|
||||
tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags
|
||||
|
||||
proc genDeref(p: BProc, e: PNode, d: var TLoc) =
|
||||
@@ -693,7 +692,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
|
||||
if typ.kind in {tyUserTypeClass, tyUserTypeClassInst} and typ.isResolvedUserTypeClass:
|
||||
typ = typ.lastSon
|
||||
typ = typ.skipTypes(abstractInstOwned)
|
||||
if typ.kind == tyVar and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr:
|
||||
if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and p.module.compileToCpp and e[0].kind == nkHiddenAddr:
|
||||
initLocExprSingleUse(p, e[0][0], d)
|
||||
return
|
||||
else:
|
||||
@@ -716,7 +715,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
|
||||
else:
|
||||
internalError(p.config, e.info, "genDeref " & $typ.kind)
|
||||
elif p.module.compileToCpp:
|
||||
if typ.kind == tyVar and tfVarIsPtr notin typ.flags and
|
||||
if typ.kind in {tyVar} and tfVarIsPtr notin typ.flags and
|
||||
e.kind == nkHiddenDeref:
|
||||
putIntoDest(p, d, e, rdLoc(a), a.storage)
|
||||
return
|
||||
@@ -2960,8 +2959,7 @@ proc genBracedInit(p: BProc, n: PNode; isConst: bool): Rope =
|
||||
ty = skipTypes(n.typ, abstractInstOwned + {tyStatic}).kind
|
||||
case ty
|
||||
of tySet:
|
||||
var cs: TBitSet
|
||||
toBitSet(p.config, n, cs)
|
||||
let cs = toBitSet(p.config, n)
|
||||
result = genRawSetData(cs, int(getSize(p.config, n.typ)))
|
||||
of tySequence:
|
||||
if optSeqDestructors in p.config.globalOptions:
|
||||
|
||||
@@ -701,7 +701,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||
return
|
||||
case t.kind
|
||||
of tyRef, tyPtr, tyVar, tyLent:
|
||||
var star = if t.kind == tyVar and tfVarIsPtr notin origTyp.flags and
|
||||
var star = if t.kind in {tyVar} and tfVarIsPtr notin origTyp.flags and
|
||||
compileToCpp(m): "&" else: "*"
|
||||
var et = origTyp.skipTypes(abstractInst).lastSon
|
||||
var etB = et.skipTypes(abstractInst)
|
||||
|
||||
@@ -715,10 +715,8 @@ proc genCall(c: var Con; n: PNode) =
|
||||
for i in 1..<n.len:
|
||||
gen(c, n[i])
|
||||
when false:
|
||||
if t != nil and i < t.len and t[i].kind == tyVar:
|
||||
# This is wrong! Pass by var is a 'might def', not a 'must def'
|
||||
# like the other defs we emit. This is not good enough for a move
|
||||
# optimizer.
|
||||
if t != nil and i < t.len and t[i].kind == tyOut:
|
||||
# Pass by 'out' is a 'must def'. Good enough for a move optimizer.
|
||||
genDef(c, n[i])
|
||||
# every call can potentially raise:
|
||||
if c.inTryStmt > 0 and canRaiseConservative(n[0]):
|
||||
|
||||
@@ -46,7 +46,7 @@ proc isLet(n: PNode): bool =
|
||||
if n.sym.kind in {skLet, skTemp, skForVar}:
|
||||
result = true
|
||||
elif n.sym.kind == skParam and skipTypes(n.sym.typ,
|
||||
abstractInst).kind != tyVar:
|
||||
abstractInst).kind notin {tyVar}:
|
||||
result = true
|
||||
|
||||
proc isVar(n: PNode): bool =
|
||||
|
||||
@@ -1053,7 +1053,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||
lineF(p, "$1 = nimCopy(null, $2, $3);$n",
|
||||
[a.rdLoc, b.res, genTypeInfo(p, y.typ)])
|
||||
of etyObject:
|
||||
if x.typ.kind == tyVar or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
|
||||
if x.typ.kind in {tyVar} or (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
|
||||
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
||||
else:
|
||||
useMagic(p, "nimCopy")
|
||||
|
||||
@@ -113,7 +113,7 @@ const
|
||||
warnStaticIndexCheck: "$1",
|
||||
warnGcUnsafe: "not GC-safe: '$1'",
|
||||
warnGcUnsafe2: "$1",
|
||||
warnUninit: "'$1' might not have been initialized",
|
||||
warnUninit: "use explicit initialization of '$1' for clarity",
|
||||
warnGcMem: "'$1' uses GC'ed memory",
|
||||
warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.",
|
||||
warnLockLevel: "$1",
|
||||
|
||||
@@ -59,7 +59,7 @@ proc newFastAsgnStmt*(le, ri: PNode): PNode =
|
||||
result[0] = le
|
||||
result[1] = ri
|
||||
|
||||
proc newFastMoveStmt*(g: ModuleGraph, le, ri: PNode): PNode =
|
||||
proc newFastMoveStmt*(g: ModuleGraph, le, ri: PNode): PNode =
|
||||
result = newNodeI(nkFastAsgn, le.info, 2)
|
||||
result[0] = le
|
||||
result[1] = newNodeIT(nkCall, ri.info, ri.typ)
|
||||
|
||||
@@ -21,3 +21,7 @@ define:useStdoutAsStdmsg
|
||||
|
||||
#define:useNodeIds
|
||||
#gc:markAndSweep
|
||||
|
||||
@if nimHasWarningObservableStores:
|
||||
warning[ObservableStores]: off
|
||||
@end
|
||||
|
||||
@@ -58,18 +58,18 @@ proc someInSet*(s: PNode, a, b: PNode): bool =
|
||||
return true
|
||||
result = false
|
||||
|
||||
proc toBitSet*(conf: ConfigRef; s: PNode, b: var TBitSet) =
|
||||
proc toBitSet*(conf: ConfigRef; s: PNode): TBitSet =
|
||||
var first, j: Int128
|
||||
first = firstOrd(conf, s.typ[0])
|
||||
bitSetInit(b, int(getSize(conf, s.typ)))
|
||||
bitSetInit(result, int(getSize(conf, s.typ)))
|
||||
for i in 0..<s.len:
|
||||
if s[i].kind == nkRange:
|
||||
j = getOrdValue(s[i][0], first)
|
||||
while j <= getOrdValue(s[i][1], first):
|
||||
bitSetIncl(b, toInt64(j - first))
|
||||
bitSetIncl(result, toInt64(j - first))
|
||||
inc(j)
|
||||
else:
|
||||
bitSetIncl(b, toInt64(getOrdValue(s[i]) - first))
|
||||
bitSetIncl(result, toInt64(getOrdValue(s[i]) - first))
|
||||
|
||||
proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): PNode =
|
||||
var
|
||||
@@ -106,9 +106,8 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
|
||||
inc(e)
|
||||
|
||||
template nodeSetOp(a, b: PNode, op: untyped) {.dirty.} =
|
||||
var x, y: TBitSet
|
||||
toBitSet(conf, a, x)
|
||||
toBitSet(conf, b, y)
|
||||
var x = toBitSet(conf, a)
|
||||
let y = toBitSet(conf, b)
|
||||
op(x, y)
|
||||
result = toTreeSet(conf, x, a.typ, a.info)
|
||||
|
||||
@@ -118,31 +117,26 @@ proc intersectSets*(conf: ConfigRef; a, b: PNode): PNode = nodeSetOp(a, b, bitSe
|
||||
proc symdiffSets*(conf: ConfigRef; a, b: PNode): PNode = nodeSetOp(a, b, bitSetSymDiff)
|
||||
|
||||
proc containsSets*(conf: ConfigRef; a, b: PNode): bool =
|
||||
var x, y: TBitSet
|
||||
toBitSet(conf, a, x)
|
||||
toBitSet(conf, b, y)
|
||||
let x = toBitSet(conf, a)
|
||||
let y = toBitSet(conf, b)
|
||||
result = bitSetContains(x, y)
|
||||
|
||||
proc equalSets*(conf: ConfigRef; a, b: PNode): bool =
|
||||
var x, y: TBitSet
|
||||
toBitSet(conf, a, x)
|
||||
toBitSet(conf, b, y)
|
||||
let x = toBitSet(conf, a)
|
||||
let y = toBitSet(conf, b)
|
||||
result = bitSetEquals(x, y)
|
||||
|
||||
proc complement*(conf: ConfigRef; a: PNode): PNode =
|
||||
var x: TBitSet
|
||||
toBitSet(conf, a, x)
|
||||
var x = toBitSet(conf, a)
|
||||
for i in 0..high(x): x[i] = not x[i]
|
||||
result = toTreeSet(conf, x, a.typ, a.info)
|
||||
|
||||
proc deduplicate*(conf: ConfigRef; a: PNode): PNode =
|
||||
var x: TBitSet
|
||||
toBitSet(conf, a, x)
|
||||
let x = toBitSet(conf, a)
|
||||
result = toTreeSet(conf, x, a.typ, a.info)
|
||||
|
||||
proc cardSet*(conf: ConfigRef; a: PNode): BiggestInt =
|
||||
var x: TBitSet
|
||||
toBitSet(conf, a, x)
|
||||
let x = toBitSet(conf, a)
|
||||
result = bitSetCard(x)
|
||||
|
||||
proc setHasRange*(s: PNode): bool =
|
||||
|
||||
@@ -214,7 +214,7 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
|
||||
result = arNone
|
||||
case n.kind
|
||||
of nkEmpty:
|
||||
if n.typ != nil and n.typ.kind == tyVar:
|
||||
if n.typ != nil and n.typ.kind in {tyVar}:
|
||||
result = arLValue
|
||||
of nkSym:
|
||||
let kinds = if isUnsafeAddr: {skVar, skResult, skTemp, skParam, skLet, skForVar}
|
||||
@@ -231,7 +231,7 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
|
||||
result = arLValue
|
||||
elif n.sym.kind == skType:
|
||||
let t = n.sym.typ.skipTypes({tyTypeDesc})
|
||||
if t.kind == tyVar: result = arStrange
|
||||
if t.kind in {tyVar}: result = arStrange
|
||||
of nkDotExpr:
|
||||
let t = skipTypes(n[0].typ, abstractInst-{tyTypeDesc})
|
||||
if t.kind in {tyVar, tySink, tyPtr, tyRef}:
|
||||
@@ -277,7 +277,7 @@ proc isAssignable*(owner: PSym, n: PNode; isUnsafeAddr=false): TAssignableResult
|
||||
# builtin slice keeps lvalue-ness:
|
||||
if getMagic(n) in {mArrGet, mSlice}:
|
||||
result = isAssignable(owner, n[1], isUnsafeAddr)
|
||||
elif n.typ != nil and n.typ.kind == tyVar:
|
||||
elif n.typ != nil and n.typ.kind in {tyVar}:
|
||||
result = arLValue
|
||||
elif isUnsafeAddr and n.typ != nil and n.typ.kind == tyLent:
|
||||
result = arLValue
|
||||
|
||||
@@ -793,7 +793,7 @@ proc primarySuffix(p: var TParser, r: PNode,
|
||||
break
|
||||
result = namedParams(p, result, nkCurlyExpr, tkCurlyRi)
|
||||
of tkSymbol, tkAccent, tkIntLit..tkCharLit, tkNil, tkCast,
|
||||
tkOpr, tkDotDot, tkVar, tkStatic, tkType, tkEnum, tkTuple,
|
||||
tkOpr, tkDotDot, tkVar, tkOut, tkStatic, tkType, tkEnum, tkTuple,
|
||||
tkObject, tkProc:
|
||||
# XXX: In type sections we allow the free application of the
|
||||
# command syntax, with the exception of expressions such as
|
||||
@@ -1300,6 +1300,10 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
|
||||
optInd(p, result)
|
||||
result.add(primary(p, pmNormal))
|
||||
of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode)
|
||||
of tkOut:
|
||||
# I like this parser extension to be in 1.4 as it still might turn out
|
||||
# useful in the long run.
|
||||
result = parseTypeDescKAux(p, nkMutableTy, mode)
|
||||
of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode)
|
||||
of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode)
|
||||
of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode)
|
||||
|
||||
@@ -309,8 +309,8 @@ proc lsub(g: TSrcGen; n: PNode): int
|
||||
proc litAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
|
||||
proc skip(t: PType): PType =
|
||||
result = t
|
||||
while result != nil and result.kind in {tyGenericInst, tyRange, tyVar, tyLent, tyDistinct,
|
||||
tyOrdinal, tyAlias, tySink}:
|
||||
while result != nil and result.kind in {tyGenericInst, tyRange, tyVar,
|
||||
tyLent, tyDistinct, tyOrdinal, tyAlias, tySink}:
|
||||
result = lastSon(result)
|
||||
|
||||
let typ = n.typ.skip
|
||||
@@ -883,7 +883,7 @@ proc bracketKind*(g: TSrcGen, n: PNode): BracketKind =
|
||||
case n.kind
|
||||
of nkClosedSymChoice, nkOpenSymChoice:
|
||||
if n.len > 0: result = bracketKind(g, n[0])
|
||||
of nkSym:
|
||||
of nkSym:
|
||||
result = case n.sym.name.s
|
||||
of "[]": bkBracket
|
||||
of "[]=": bkBracketAsgn
|
||||
@@ -974,7 +974,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
put(g, tkParRi, ")")
|
||||
put(g, tkColon, ":")
|
||||
gsub(g, n, n.len-1)
|
||||
elif n.len >= 1:
|
||||
elif n.len >= 1:
|
||||
case bracketKind(g, n[0])
|
||||
of bkBracket:
|
||||
gsub(g, n, 1)
|
||||
|
||||
@@ -107,6 +107,7 @@ proc extractRunnableExamplesSource*(conf: ConfigRef; n: PNode): string =
|
||||
var indent = info.col
|
||||
let numLines = numLines(conf, info.fileIndex).uint16
|
||||
var lastNonemptyPos = 0
|
||||
result = ""
|
||||
|
||||
var ldata = LineData(lineFirst: first.line.int, conf: conf)
|
||||
visitMultilineStrings(ldata, n[^1])
|
||||
|
||||
@@ -676,7 +676,7 @@ proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
|
||||
if t.kind == tyDistinct or param.typ.kind == tyDistinct: hasDistinct = true
|
||||
var x: PType
|
||||
if param.typ.kind == tyVar:
|
||||
x = newTypeS(tyVar, c)
|
||||
x = newTypeS(param.typ.kind, c)
|
||||
x.addSonSkipIntLit t.baseOfDistinct
|
||||
else:
|
||||
x = t.baseOfDistinct
|
||||
|
||||
@@ -712,7 +712,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
||||
# note sometimes this is eval'ed twice so we check for nkHiddenAddr here:
|
||||
for i in 1..<n.len:
|
||||
if i < t.len and t[i] != nil and
|
||||
skipTypes(t[i], abstractInst-{tyTypeDesc}).kind == tyVar:
|
||||
skipTypes(t[i], abstractInst-{tyTypeDesc}).kind in {tyVar}:
|
||||
let it = n[i]
|
||||
if isAssignable(c, it) notin {arLValue, arLocalLValue}:
|
||||
if it.kind != nkHiddenAddr:
|
||||
@@ -733,7 +733,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
|
||||
# calls and then they wouldn't be analysed otherwise
|
||||
analyseIfAddressTakenInCall(c, n[i])
|
||||
if i < t.len and
|
||||
skipTypes(t[i], abstractInst-{tyTypeDesc}).kind == tyVar:
|
||||
skipTypes(t[i], abstractInst-{tyTypeDesc}).kind in {tyVar}:
|
||||
if n[i].kind != nkHiddenAddr:
|
||||
n[i] = analyseIfAddressTaken(c, n[i])
|
||||
|
||||
@@ -1711,7 +1711,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||
var le = a.typ
|
||||
if le == nil:
|
||||
localError(c.config, a.info, "expression has no type")
|
||||
elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind != tyVar and
|
||||
elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind notin {tyVar} and
|
||||
isAssignable(c, a) in {arNone, arLentValue}) or
|
||||
skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs}:
|
||||
# Direct assignment to a discriminant is allowed!
|
||||
|
||||
@@ -42,9 +42,6 @@ type
|
||||
proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode
|
||||
proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode
|
||||
|
||||
proc skipAddr(n: PNode): PNode {.inline.} =
|
||||
(if n.kind == nkHiddenAddr: n[0] else: n)
|
||||
|
||||
proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
|
||||
result = newNodeI(nkBracketExpr, n.info)
|
||||
for i in 1..<n.len: result.add(n[i])
|
||||
|
||||
@@ -249,7 +249,7 @@ proc semConstructFields(c: PContext, recNode: PNode,
|
||||
else:
|
||||
badDiscriminatorError()
|
||||
elif discriminatorVal.sym.kind notin {skLet, skParam} or
|
||||
discriminatorVal.sym.typ.kind == tyVar:
|
||||
discriminatorVal.sym.typ.kind in {tyVar}:
|
||||
localError(c.config, discriminatorVal.info,
|
||||
"runtime discriminator must be immutable if branch fields are " &
|
||||
"initialized, a 'let' binding is required.")
|
||||
|
||||
@@ -66,7 +66,7 @@ type
|
||||
TEffects = object
|
||||
exc: PNode # stack of exceptions
|
||||
tags: PNode # list of tags
|
||||
bottom, inTryStmt, inExceptOrFinallyStmt: int
|
||||
bottom, inTryStmt, inExceptOrFinallyStmt, leftPartOfAsgn: int
|
||||
owner: PSym
|
||||
ownerModule: PSym
|
||||
init: seq[int] # list of initialized variables
|
||||
@@ -87,6 +87,7 @@ proc `==`(a, b: TLockLevel): bool {.borrow.}
|
||||
proc max(a, b: TLockLevel): TLockLevel {.borrow.}
|
||||
|
||||
proc isLocalVar(a: PEffects, s: PSym): bool =
|
||||
# and (s.kind != skParam or s.typ.kind == tyOut)
|
||||
s.kind in {skVar, skResult} and sfGlobal notin s.flags and
|
||||
s.owner == a.owner and s.typ != nil
|
||||
|
||||
@@ -246,6 +247,18 @@ proc listGcUnsafety(s: PSym; onlyWarning: bool; conf: ConfigRef) =
|
||||
var cycleCheck = initIntSet()
|
||||
listGcUnsafety(s, onlyWarning, cycleCheck, conf)
|
||||
|
||||
proc useVarNoInitCheck(a: PEffects; n: PNode; s: PSym) =
|
||||
if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and
|
||||
s.magic != mNimvm:
|
||||
if s.guard != nil: guardGlobal(a, n, s.guard)
|
||||
if {sfGlobal, sfThread} * s.flags == {sfGlobal} and
|
||||
(tfHasGCedMem in s.typ.flags or s.typ.isGCedMem):
|
||||
#if a.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n)
|
||||
markGcUnsafe(a, s)
|
||||
markSideEffect(a, s)
|
||||
else:
|
||||
markSideEffect(a, s)
|
||||
|
||||
proc useVar(a: PEffects, n: PNode) =
|
||||
let s = n.sym
|
||||
if a.inExceptOrFinallyStmt > 0:
|
||||
@@ -257,20 +270,11 @@ proc useVar(a: PEffects, n: PNode) =
|
||||
elif s.id notin a.init:
|
||||
if s.typ.requiresInit:
|
||||
message(a.config, n.info, warnProveInit, s.name.s)
|
||||
else:
|
||||
elif a.leftPartOfAsgn <= 0:
|
||||
message(a.config, n.info, warnUninit, s.name.s)
|
||||
# prevent superfluous warnings about the same variable:
|
||||
a.init.add s.id
|
||||
if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and
|
||||
s.magic != mNimvm:
|
||||
if s.guard != nil: guardGlobal(a, n, s.guard)
|
||||
if {sfGlobal, sfThread} * s.flags == {sfGlobal} and
|
||||
(tfHasGCedMem in s.typ.flags or s.typ.isGCedMem):
|
||||
#if a.config.hasWarn(warnGcUnsafe): warnAboutGcUnsafe(n)
|
||||
markGcUnsafe(a, s)
|
||||
markSideEffect(a, s)
|
||||
else:
|
||||
markSideEffect(a, s)
|
||||
useVarNoInitCheck(a, n, s)
|
||||
|
||||
|
||||
type
|
||||
@@ -538,7 +542,7 @@ proc isNoEffectList(n: PNode): bool {.inline.} =
|
||||
proc isTrival(caller: PNode): bool {.inline.} =
|
||||
result = caller.kind == nkSym and caller.sym.magic in {mEqProc, mIsNil, mMove, mWasMoved}
|
||||
|
||||
proc trackOperand(tracked: PEffects, n: PNode, paramType: PType; caller: PNode) =
|
||||
proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, paramType: PType; caller: PNode) =
|
||||
let a = skipConvAndClosure(n)
|
||||
let op = a.typ
|
||||
# assume indirect calls are taken here:
|
||||
@@ -572,7 +576,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType; caller: PNode)
|
||||
markGcUnsafe(tracked, a)
|
||||
elif tfNoSideEffect notin op.flags:
|
||||
markSideEffect(tracked, a)
|
||||
if paramType != nil and paramType.kind == tyVar:
|
||||
if paramType != nil and paramType.kind in {tyVar}:
|
||||
invalidateFacts(tracked.guards, n)
|
||||
if n.kind == nkSym and isLocalVar(tracked, n.sym):
|
||||
makeVolatile(tracked, n.sym)
|
||||
@@ -732,7 +736,7 @@ proc createTypeBoundOps(tracked: PEffects, typ: PType; info: TLineInfo) =
|
||||
optSeqDestructors in tracked.config.globalOptions:
|
||||
tracked.owner.flags.incl sfInjectDestructors
|
||||
|
||||
proc track(tracked: PEffects, n: PNode) =
|
||||
proc trackCall(tracked: PEffects; n: PNode) =
|
||||
template gcsafeAndSideeffectCheck() =
|
||||
if notGcSafe(op) and not importedFromC(a):
|
||||
# and it's not a recursive call:
|
||||
@@ -744,11 +748,105 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
if not (a.kind == nkSym and a.sym == tracked.owner):
|
||||
markSideEffect(tracked, a)
|
||||
|
||||
# p's effects are ours too:
|
||||
var a = n[0]
|
||||
#if canRaise(a):
|
||||
# echo "this can raise ", tracked.config $ n.info
|
||||
let op = a.typ
|
||||
if n.typ != nil:
|
||||
if tracked.owner.kind != skMacro and n.typ.skipTypes(abstractVar).kind != tyOpenArray:
|
||||
createTypeBoundOps(tracked, n.typ, n.info)
|
||||
if getConstExpr(tracked.ownerModule, n, tracked.graph) != nil:
|
||||
return
|
||||
if a.kind == nkCast and a[1].typ.kind == tyProc:
|
||||
a = a[1]
|
||||
# XXX: in rare situations, templates and macros will reach here after
|
||||
# calling getAst(templateOrMacro()). Currently, templates and macros
|
||||
# are indistinguishable from normal procs (both have tyProc type) and
|
||||
# we can detect them only by checking for attached nkEffectList.
|
||||
if op != nil and op.kind == tyProc and op.n[0].kind == nkEffectList:
|
||||
if a.kind == nkSym:
|
||||
if a.sym == tracked.owner: tracked.isRecursive = true
|
||||
# even for recursive calls we need to check the lock levels (!):
|
||||
mergeLockLevels(tracked, n, a.sym.getLockLevel)
|
||||
if sfSideEffect in a.sym.flags: markSideEffect(tracked, a)
|
||||
else:
|
||||
mergeLockLevels(tracked, n, op.lockLevel)
|
||||
var effectList = op.n[0]
|
||||
if a.kind == nkSym and a.sym.kind == skMethod:
|
||||
propagateEffects(tracked, n, a.sym)
|
||||
elif isNoEffectList(effectList):
|
||||
if isForwardedProc(a):
|
||||
propagateEffects(tracked, n, a.sym)
|
||||
elif isIndirectCall(a, tracked.owner):
|
||||
assumeTheWorst(tracked, n, op)
|
||||
gcsafeAndSideeffectCheck()
|
||||
else:
|
||||
mergeEffects(tracked, effectList[exceptionEffects], n)
|
||||
mergeTags(tracked, effectList[tagEffects], n)
|
||||
gcsafeAndSideeffectCheck()
|
||||
if a.kind != nkSym or a.sym.magic != mNBindSym:
|
||||
for i in 1..<n.len: trackOperandForIndirectCall(tracked, n[i], paramType(op, i), a)
|
||||
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
|
||||
# may not look like an assignment, but it is:
|
||||
let arg = n[1]
|
||||
initVarViaNew(tracked, arg)
|
||||
if arg.typ.len != 0 and {tfRequiresInit} * arg.typ.lastSon.flags != {}:
|
||||
if a.sym.magic == mNewSeq and n[2].kind in {nkCharLit..nkUInt64Lit} and
|
||||
n[2].intVal == 0:
|
||||
# var s: seq[notnil]; newSeq(s, 0) is a special case!
|
||||
discard
|
||||
else:
|
||||
message(tracked.config, arg.info, warnProveInit, $arg)
|
||||
|
||||
# check required for 'nim check':
|
||||
if n[1].typ.len > 0:
|
||||
createTypeBoundOps(tracked, n[1].typ.lastSon, n.info)
|
||||
createTypeBoundOps(tracked, n[1].typ, n.info)
|
||||
# new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'?
|
||||
|
||||
elif a.kind == nkSym and a.sym.magic in {mArrGet, mArrPut} and
|
||||
optStaticBoundsCheck in tracked.currOptions:
|
||||
checkBounds(tracked, n[1], n[2])
|
||||
|
||||
if a.kind == nkSym and a.sym.name.s.len > 0 and a.sym.name.s[0] == '=' and
|
||||
tracked.owner.kind != skMacro:
|
||||
let opKind = find(AttachedOpToStr, a.sym.name.s.normalize)
|
||||
if opKind != -1:
|
||||
# rebind type bounds operations after createTypeBoundOps call
|
||||
let t = n[1].typ.skipTypes({tyAlias, tyVar})
|
||||
if a.sym != t.attachedOps[TTypeAttachedOp(opKind)]:
|
||||
createTypeBoundOps(tracked, t, n.info)
|
||||
let op = t.attachedOps[TTypeAttachedOp(opKind)]
|
||||
if op != nil:
|
||||
n[0].sym = op
|
||||
|
||||
if a.kind != nkSym or a.sym.magic != mRunnableExamples:
|
||||
for i in 0..<n.safeLen:
|
||||
track(tracked, n[i])
|
||||
if op != nil and op.kind == tyProc:
|
||||
for i in 1..<min(n.safeLen, op.len):
|
||||
case op[i].kind
|
||||
of tySink:
|
||||
checkForSink(tracked.config, tracked.owner, n[i])
|
||||
#of tyOut:
|
||||
# consider this case: p(out x, x); we want to remark that 'x' is not
|
||||
# initialized until after the call. Since we do this after we analysed the
|
||||
# call, this is fine.
|
||||
# initVar(tracked, n[i].skipAddr, false)
|
||||
else: discard
|
||||
|
||||
proc track(tracked: PEffects, n: PNode) =
|
||||
case n.kind
|
||||
of nkSym:
|
||||
useVar(tracked, n)
|
||||
if n.sym.typ != nil and tfHasAsgn in n.sym.typ.flags:
|
||||
tracked.owner.flags.incl sfInjectDestructors
|
||||
of nkHiddenAddr, nkAddr:
|
||||
if n[0].kind == nkSym and isLocalVar(tracked, n[0].sym):
|
||||
useVarNoInitCheck(tracked, n[0], n[0].sym)
|
||||
else:
|
||||
track(tracked, n[0])
|
||||
of nkRaiseStmt:
|
||||
if n[0].kind != nkEmpty:
|
||||
n[0].info = n.info
|
||||
@@ -763,86 +861,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
# Here we add a `Exception` tag in order to cover both the cases.
|
||||
addEffect(tracked, createRaise(tracked.graph, n), nil)
|
||||
of nkCallKinds:
|
||||
# p's effects are ours too:
|
||||
var a = n[0]
|
||||
#if canRaise(a):
|
||||
# echo "this can raise ", tracked.config $ n.info
|
||||
let op = a.typ
|
||||
if n.typ != nil:
|
||||
if tracked.owner.kind != skMacro and n.typ.skipTypes(abstractVar).kind != tyOpenArray:
|
||||
createTypeBoundOps(tracked, n.typ, n.info)
|
||||
if getConstExpr(tracked.ownerModule, n, tracked.graph) != nil:
|
||||
return
|
||||
if a.kind == nkCast and a[1].typ.kind == tyProc:
|
||||
a = a[1]
|
||||
# XXX: in rare situations, templates and macros will reach here after
|
||||
# calling getAst(templateOrMacro()). Currently, templates and macros
|
||||
# are indistinguishable from normal procs (both have tyProc type) and
|
||||
# we can detect them only by checking for attached nkEffectList.
|
||||
if op != nil and op.kind == tyProc and op.n[0].kind == nkEffectList:
|
||||
if a.kind == nkSym:
|
||||
if a.sym == tracked.owner: tracked.isRecursive = true
|
||||
# even for recursive calls we need to check the lock levels (!):
|
||||
mergeLockLevels(tracked, n, a.sym.getLockLevel)
|
||||
if sfSideEffect in a.sym.flags: markSideEffect(tracked, a)
|
||||
else:
|
||||
mergeLockLevels(tracked, n, op.lockLevel)
|
||||
var effectList = op.n[0]
|
||||
if a.kind == nkSym and a.sym.kind == skMethod:
|
||||
propagateEffects(tracked, n, a.sym)
|
||||
elif isNoEffectList(effectList):
|
||||
if isForwardedProc(a):
|
||||
propagateEffects(tracked, n, a.sym)
|
||||
elif isIndirectCall(a, tracked.owner):
|
||||
assumeTheWorst(tracked, n, op)
|
||||
gcsafeAndSideeffectCheck()
|
||||
else:
|
||||
mergeEffects(tracked, effectList[exceptionEffects], n)
|
||||
mergeTags(tracked, effectList[tagEffects], n)
|
||||
gcsafeAndSideeffectCheck()
|
||||
if a.kind != nkSym or a.sym.magic != mNBindSym:
|
||||
for i in 1..<n.len: trackOperand(tracked, n[i], paramType(op, i), a)
|
||||
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
|
||||
# may not look like an assignment, but it is:
|
||||
let arg = n[1]
|
||||
initVarViaNew(tracked, arg)
|
||||
if arg.typ.len != 0 and {tfRequiresInit} * arg.typ.lastSon.flags != {}:
|
||||
if a.sym.magic == mNewSeq and n[2].kind in {nkCharLit..nkUInt64Lit} and
|
||||
n[2].intVal == 0:
|
||||
# var s: seq[notnil]; newSeq(s, 0) is a special case!
|
||||
discard
|
||||
else:
|
||||
message(tracked.config, arg.info, warnProveInit, $arg)
|
||||
|
||||
# check required for 'nim check':
|
||||
if n[1].typ.len > 0:
|
||||
createTypeBoundOps(tracked, n[1].typ.lastSon, n.info)
|
||||
createTypeBoundOps(tracked, n[1].typ, n.info)
|
||||
# new(x, finalizer): Problem: how to move finalizer into 'createTypeBoundOps'?
|
||||
|
||||
elif a.kind == nkSym and a.sym.magic in {mArrGet, mArrPut} and
|
||||
optStaticBoundsCheck in tracked.currOptions:
|
||||
checkBounds(tracked, n[1], n[2])
|
||||
|
||||
if a.kind == nkSym and a.sym.name.s.len > 0 and a.sym.name.s[0] == '=' and
|
||||
tracked.owner.kind != skMacro:
|
||||
let opKind = find(AttachedOpToStr, a.sym.name.s.normalize)
|
||||
if opKind != -1:
|
||||
# rebind type bounds operations after createTypeBoundOps call
|
||||
let t = n[1].typ.skipTypes({tyAlias, tyVar})
|
||||
if a.sym != t.attachedOps[TTypeAttachedOp(opKind)]:
|
||||
createTypeBoundOps(tracked, t, n.info)
|
||||
let op = t.attachedOps[TTypeAttachedOp(opKind)]
|
||||
if op != nil:
|
||||
n[0].sym = op
|
||||
|
||||
if a.kind != nkSym or a.sym.magic != mRunnableExamples:
|
||||
for i in 0..<n.safeLen:
|
||||
track(tracked, n[i])
|
||||
if op != nil and op.kind == tyProc:
|
||||
for i in 1..<min(n.safeLen, op.len):
|
||||
if op[i].kind == tySink:
|
||||
checkForSink(tracked.config, tracked.owner, n[i])
|
||||
trackCall(tracked, n)
|
||||
of nkDotExpr:
|
||||
guardDotAccess(tracked, n)
|
||||
for i in 0..<n.len: track(tracked, n[i])
|
||||
@@ -856,7 +875,9 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
track(tracked, n[1])
|
||||
initVar(tracked, n[0], volatileCheck=true)
|
||||
invalidateFacts(tracked.guards, n[0])
|
||||
inc tracked.leftPartOfAsgn
|
||||
track(tracked, n[0])
|
||||
dec tracked.leftPartOfAsgn
|
||||
addAsgnFact(tracked.guards, n[0], n[1])
|
||||
notNilCheck(tracked, n[1], n[0].typ)
|
||||
when false: cstringCheck(tracked, n)
|
||||
@@ -1042,7 +1063,10 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
if optStaticBoundsCheck in tracked.currOptions and n.len == 2:
|
||||
if n[0].typ != nil and skipTypes(n[0].typ, abstractVar).kind != tyTuple:
|
||||
checkBounds(tracked, n[0], n[1])
|
||||
for i in 0 ..< n.len: track(tracked, n[i])
|
||||
track(tracked, n[0])
|
||||
dec tracked.leftPartOfAsgn
|
||||
for i in 1 ..< n.len: track(tracked, n[i])
|
||||
inc tracked.leftPartOfAsgn
|
||||
else:
|
||||
for i in 0..<n.safeLen: track(tracked, n[i])
|
||||
|
||||
@@ -1180,6 +1204,9 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
|
||||
if isSinkTypeForParam(typ) or
|
||||
(t.config.selectedGC in {gcArc, gcOrc} and isClosure(typ.skipTypes(abstractInst))):
|
||||
createTypeBoundOps(t, typ, param.info)
|
||||
when false:
|
||||
if typ.kind == tyOut and param.id notin t.init:
|
||||
message(g.config, param.info, warnProveInit, param.name.s)
|
||||
|
||||
if not isEmptyType(s.typ[0]) and
|
||||
(s.typ[0].requiresInit or s.typ[0].skipTypes(abstractInst).kind == tyVar) and
|
||||
|
||||
@@ -731,13 +731,8 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
var v = symForVar(c, n[0][i])
|
||||
if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
|
||||
case iter.kind
|
||||
of tyVar:
|
||||
v.typ = newTypeS(tyVar, c)
|
||||
v.typ.add iterAfterVarLent[i]
|
||||
if tfVarIsPtr in iter.flags:
|
||||
v.typ.flags.incl tfVarIsPtr
|
||||
of tyLent:
|
||||
v.typ = newTypeS(tyLent, c)
|
||||
of tyVar, tyLent:
|
||||
v.typ = newTypeS(iter.kind, c)
|
||||
v.typ.add iterAfterVarLent[i]
|
||||
if tfVarIsPtr in iter.flags:
|
||||
v.typ.flags.incl tfVarIsPtr
|
||||
@@ -794,13 +789,8 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||
var v = symForVar(c, n[i])
|
||||
if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
|
||||
case iter.kind
|
||||
of tyVar:
|
||||
v.typ = newTypeS(tyVar, c)
|
||||
v.typ.add iterAfterVarLent[i]
|
||||
if tfVarIsPtr in iter.flags:
|
||||
v.typ.flags.incl tfVarIsPtr
|
||||
of tyLent:
|
||||
v.typ = newTypeS(tyLent, c)
|
||||
of tyVar, tyLent:
|
||||
v.typ = newTypeS(iter.kind, c)
|
||||
v.typ.add iterAfterVarLent[i]
|
||||
if tfVarIsPtr in iter.flags:
|
||||
v.typ.flags.incl tfVarIsPtr
|
||||
|
||||
@@ -193,16 +193,16 @@ proc semVarargs(c: PContext, n: PNode, prev: PType): PType =
|
||||
localError(c.config, n.info, errXExpectsOneTypeParam % "varargs")
|
||||
addSonSkipIntLit(result, errorType(c))
|
||||
|
||||
proc semVarType(c: PContext, n: PNode, prev: PType): PType =
|
||||
proc semVarOutType(c: PContext, n: PNode, prev: PType; kind: TTypeKind): PType =
|
||||
if n.len == 1:
|
||||
result = newOrPrevType(tyVar, prev, c)
|
||||
result = newOrPrevType(kind, prev, c)
|
||||
var base = semTypeNode(c, n[0], nil).skipTypes({tyTypeDesc})
|
||||
if base.kind == tyVar:
|
||||
localError(c.config, n.info, "type 'var var' is not allowed")
|
||||
base = base[0]
|
||||
addSonSkipIntLit(result, base)
|
||||
else:
|
||||
result = newConstraint(c, tyVar)
|
||||
result = newConstraint(c, kind)
|
||||
|
||||
proc semDistinct(c: PContext, n: PNode, prev: PType): PType =
|
||||
if n.len == 0: return newConstraint(c, tyDistinct)
|
||||
@@ -1915,7 +1915,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
of nkTypeClassTy: result = semTypeClass(c, n, prev)
|
||||
of nkRefTy: result = semAnyRef(c, n, tyRef, prev)
|
||||
of nkPtrTy: result = semAnyRef(c, n, tyPtr, prev)
|
||||
of nkVarTy: result = semVarType(c, n, prev)
|
||||
of nkVarTy: result = semVarOutType(c, n, prev, tyVar)
|
||||
of nkDistinctTy: result = semDistinct(c, n, prev)
|
||||
of nkStaticTy: result = semStaticType(c, n[0], prev)
|
||||
of nkIteratorTy:
|
||||
|
||||
@@ -1902,7 +1902,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||
if destIsGeneric:
|
||||
dest = generateTypeInstance(c, m.bindings, arg, dest)
|
||||
let fdest = typeRel(m, f, dest)
|
||||
if fdest in {isEqual, isGeneric} and not (dest.kind == tyLent and f.kind == tyVar):
|
||||
if fdest in {isEqual, isGeneric} and not (dest.kind == tyLent and f.kind in {tyVar}):
|
||||
markUsed(c, arg.info, c.converters[i])
|
||||
var s = newSymNode(c.converters[i])
|
||||
s.typ = c.converters[i].typ
|
||||
@@ -1915,7 +1915,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||
var param: PNode = nil
|
||||
if srca == isSubtype:
|
||||
param = implicitConv(nkHiddenSubConv, src, copyTree(arg), m, c)
|
||||
elif src.kind == tyVar:
|
||||
elif src.kind in {tyVar}:
|
||||
# Analyse the converter return type
|
||||
param = newNodeIT(nkHiddenAddr, arg.info, s.typ[1])
|
||||
param.add copyTree(arg)
|
||||
@@ -2082,7 +2082,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
|
||||
of isSubrange:
|
||||
inc(m.subtypeMatches)
|
||||
if f.kind == tyVar:
|
||||
if f.kind in {tyVar}:
|
||||
result = arg
|
||||
else:
|
||||
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
|
||||
@@ -2327,10 +2327,10 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
noMatch()
|
||||
return
|
||||
|
||||
if formal.typ.kind == tyVar:
|
||||
if formal.typ.kind in {tyVar}:
|
||||
let argConverter = if arg.kind == nkHiddenDeref: arg[0] else: arg
|
||||
if argConverter.kind == nkHiddenCallConv:
|
||||
if argConverter.typ.kind != tyVar:
|
||||
if argConverter.typ.kind notin {tyVar}:
|
||||
m.firstMismatch.kind = kVarNeeded
|
||||
noMatch()
|
||||
return
|
||||
@@ -2604,7 +2604,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
|
||||
if op == attachedDeepCopy:
|
||||
if f.kind in {tyRef, tyPtr}: f = f.lastSon
|
||||
else:
|
||||
if f.kind == tyVar: f = f.lastSon
|
||||
if f.kind in {tyVar}: f = f.lastSon
|
||||
if typeRel(m, f, t) == isNone:
|
||||
localError(c.config, info, "cannot instantiate: '" & dc.name.s & "'")
|
||||
else:
|
||||
|
||||
@@ -37,7 +37,7 @@ proc spawnResult*(t: PType; inParallel: bool): TSpawnResult =
|
||||
else: srFlowVar
|
||||
|
||||
proc flowVarKind(c: ConfigRef, t: PType): TFlowVarKind =
|
||||
if c.selectedGC in {gcArc, gcOrc}: fvBlob
|
||||
if c.selectedGC in {gcArc, gcOrc}: fvBlob
|
||||
elif t.skipTypes(abstractInst).kind in {tyRef, tyString, tySequence}: fvGC
|
||||
elif containsGarbageCollectedRef(t): fvInvalid
|
||||
else: fvBlob
|
||||
@@ -201,7 +201,7 @@ proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType;
|
||||
# we pick n's type here, which hopefully is 'tyArray' and not
|
||||
# 'tyOpenArray':
|
||||
var argType = n[i].typ.skipTypes(abstractInst)
|
||||
if i < formals.len:
|
||||
if i < formals.len:
|
||||
if formals[i].typ.kind in {tyVar, tyLent}:
|
||||
localError(g.config, n[i].info, "'spawn'ed function cannot have a 'var' parameter")
|
||||
if formals[i].typ.kind in {tyTypeDesc, tyStatic}:
|
||||
|
||||
@@ -423,7 +423,7 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PNode =
|
||||
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
|
||||
result.typ = n.typ
|
||||
elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
|
||||
result.typ = toVar(result.typ)
|
||||
result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind)
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
var m = n[0][1]
|
||||
if m.kind == a or m.kind == b:
|
||||
@@ -433,7 +433,7 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PNode =
|
||||
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
|
||||
result.typ = n.typ
|
||||
elif n.typ.skipTypes(abstractInst).kind in {tyVar}:
|
||||
result.typ = toVar(result.typ)
|
||||
result.typ = toVar(result.typ, n.typ.skipTypes(abstractInst).kind)
|
||||
else:
|
||||
if n[0].kind == a or n[0].kind == b:
|
||||
# addr ( deref ( x )) --> x
|
||||
@@ -569,14 +569,14 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
|
||||
result = putArgInto(arg[0], formal)
|
||||
of nkCurly, nkBracket:
|
||||
for i in 0..<arg.len:
|
||||
if putArgInto(arg[i], formal) != paDirectMapping:
|
||||
if putArgInto(arg[i], formal) != paDirectMapping:
|
||||
return paFastAsgn
|
||||
result = paDirectMapping
|
||||
of nkPar, nkTupleConstr, nkObjConstr:
|
||||
for i in 0..<arg.len:
|
||||
let a = if arg[i].kind == nkExprColonExpr: arg[i][1]
|
||||
else: arg[0]
|
||||
if putArgInto(a, formal) != paDirectMapping:
|
||||
if putArgInto(a, formal) != paDirectMapping:
|
||||
return paFastAsgn
|
||||
result = paDirectMapping
|
||||
else:
|
||||
@@ -667,7 +667,7 @@ proc transformFor(c: PTransf, n: PNode): PNode =
|
||||
stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg))
|
||||
idNodeTablePut(newC.mapping, formal, temp)
|
||||
of paVarAsgn:
|
||||
assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
|
||||
assert(skipTypes(formal.typ, abstractInst).kind in {tyVar})
|
||||
idNodeTablePut(newC.mapping, formal, arg)
|
||||
# XXX BUG still not correct if the arg has a side effect!
|
||||
of paComplexOpenarray:
|
||||
|
||||
@@ -438,7 +438,7 @@ const
|
||||
"lent ", "varargs[$1]", "UncheckedArray[$1]", "Error Type",
|
||||
"BuiltInTypeClass", "UserTypeClass",
|
||||
"UserTypeClassInst", "CompositeTypeClass", "inferred",
|
||||
"and", "or", "not", "any", "static", "TypeFromExpr", "FieldAccessor",
|
||||
"and", "or", "not", "any", "static", "TypeFromExpr", "out ",
|
||||
"void"]
|
||||
|
||||
const preferToResolveSymbols = {preferName, preferTypeName, preferModuleInfo,
|
||||
|
||||
@@ -85,7 +85,7 @@ proc allRoots(n: PNode; result: var seq[ptr TSym]; info: var set[RootInfo]) =
|
||||
assert(typ.n[i].kind == nkSym)
|
||||
let paramType = typ.n[i]
|
||||
if paramType.typ.isCompileTimeOnly: continue
|
||||
if sfEscapes in paramType.sym.flags or paramType.typ.kind == tyVar:
|
||||
if sfEscapes in paramType.sym.flags or paramType.typ.kind in {tyVar}:
|
||||
allRoots(it, result, info)
|
||||
else:
|
||||
allRoots(it, result, info)
|
||||
@@ -164,7 +164,7 @@ proc depsArgs(w: var W; n: PNode) =
|
||||
let paramType = typ.n[i]
|
||||
if paramType.typ.isCompileTimeOnly: continue
|
||||
var destInfo: set[RootInfo] = {}
|
||||
if sfWrittenTo in paramType.sym.flags or paramType.typ.kind == tyVar:
|
||||
if sfWrittenTo in paramType.sym.flags or paramType.typ.kind in {tyVar}:
|
||||
# p(f(x, y), X, g(h, z))
|
||||
destInfo.incl markAsWrittenTo
|
||||
if sfEscapes in paramType.sym.flags:
|
||||
@@ -247,7 +247,7 @@ proc markWriteOrEscape(w: var W; conf: ConfigRef) =
|
||||
for p in a.dest:
|
||||
if p.kind == skParam and p.owner == w.owner:
|
||||
incl(p.flags, sfWrittenTo)
|
||||
if w.owner.kind == skFunc and p.typ.kind != tyVar:
|
||||
if w.owner.kind == skFunc and p.typ.kind notin {tyVar}:
|
||||
localError(conf, a.info, "write access to non-var parameter: " & p.name.s)
|
||||
|
||||
if {rootIsResultOrParam, rootIsHeapAccess, markAsEscaping}*a.destInfo != {}:
|
||||
|
||||
@@ -2458,12 +2458,13 @@ matches) is preferred:
|
||||
gen(ri) # "ref T"
|
||||
|
||||
|
||||
Overloading based on 'var T'
|
||||
----------------------------
|
||||
Overloading based on 'var T' / 'out T'
|
||||
--------------------------------------
|
||||
|
||||
If the formal parameter ``f`` is of type ``var T`` in addition to the ordinary
|
||||
type checking, the argument is checked to be an `l-value`:idx:. ``var T``
|
||||
matches better than just ``T`` then.
|
||||
If the formal parameter ``f`` is of type ``var T`` (or ``out T``)
|
||||
in addition to the ordinary
|
||||
type checking, the argument is checked to be an `l-value`:idx:.
|
||||
``var T`` (or ``out T``) matches better than just ``T`` then.
|
||||
|
||||
.. code-block:: nim
|
||||
proc sayHi(x: int): string =
|
||||
@@ -2482,6 +2483,17 @@ matches better than just ``T`` then.
|
||||
# 13
|
||||
|
||||
|
||||
An l-value matches ``var T`` and ``out T`` equally well, hence
|
||||
the following is ambiguous:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
proc p(x: out string) = x = ""
|
||||
proc p(x: var string) = x = ""
|
||||
var v: string
|
||||
p(v) # ambiguous
|
||||
|
||||
|
||||
Lazy type resolution for untyped
|
||||
--------------------------------
|
||||
|
||||
@@ -4230,9 +4242,7 @@ error message from ``e``, and for such situations it is enough to use
|
||||
Custom exceptions
|
||||
-----------------
|
||||
|
||||
Is it possible to create custom exceptions. These make it easy to distinguish between exceptions raised by nim and those from your own code.
|
||||
|
||||
A custom exception is a custom type:
|
||||
Is it possible to create custom exceptions. A custom exception is a custom type:
|
||||
|
||||
.. code-block:: nim
|
||||
type
|
||||
@@ -4782,7 +4792,7 @@ of "typedesc"-ness is stripped off:
|
||||
Generic inference restrictions
|
||||
------------------------------
|
||||
|
||||
The types ``var T`` and ``typedesc[T]`` cannot be inferred in a generic
|
||||
The types ``var T``, ``out T`` and ``typedesc[T]`` cannot be inferred in a generic
|
||||
instantiation. The following is not allowed:
|
||||
|
||||
.. code-block:: nim
|
||||
@@ -5930,7 +5940,7 @@ noSideEffect pragma
|
||||
The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side
|
||||
effects. This means that the proc/iterator only changes locations that are
|
||||
reachable from its parameters and the return value only depends on the
|
||||
arguments. If none of its parameters have the type ``var T``
|
||||
arguments. If none of its parameters have the type ``var T`` or ``out T``
|
||||
or ``ref T`` or ``ptr T`` this means no locations are modified. It is a static
|
||||
error to mark a proc/iterator to have no side effect if the compiler cannot
|
||||
verify this.
|
||||
@@ -6593,7 +6603,7 @@ during semantic analysis:
|
||||
Emit pragma
|
||||
-----------
|
||||
The ``emit`` pragma can be used to directly affect the output of the
|
||||
compiler's code generator. So it makes your code unportable to other code
|
||||
compiler's code generator. The code is then unportable to other code
|
||||
generators/backends. Its usage is highly discouraged! However, it can be
|
||||
extremely useful for interfacing with `C++`:idx: or `Objective C`:idx: code.
|
||||
|
||||
|
||||
@@ -482,7 +482,7 @@ nil`` annotation to exclude ``nil`` as a valid value:
|
||||
|
||||
.. code-block:: nim
|
||||
{.experimental: "notnil"}
|
||||
|
||||
|
||||
type
|
||||
PObject = ref TObj not nil
|
||||
TProc = (proc (x, y: int)) not nil
|
||||
@@ -1828,8 +1828,8 @@ Aliasing restrictions in parameter passing
|
||||
implementation and need to be fleshed out further.
|
||||
|
||||
"Aliasing" here means that the underlying storage locations overlap in memory
|
||||
at runtime. An "output parameter" is a parameter of type ``var T``, an input
|
||||
parameter is any parameter that is not of type ``var``.
|
||||
at runtime. An "output parameter" is a parameter of type ``var T``,
|
||||
an input parameter is any parameter that is not of type ``var``.
|
||||
|
||||
1. Two output parameters should never be aliased.
|
||||
2. An input and an output parameter should not be aliased.
|
||||
|
||||
@@ -535,9 +535,7 @@ proc copyLineInfo*(arg: NimNode, info: NimNode) {.magic: "NLineInfo", noSideEffe
|
||||
|
||||
proc lineInfoObj*(n: NimNode): LineInfo {.compileTime.} =
|
||||
## Returns ``LineInfo`` of ``n``, using absolute path for ``filename``.
|
||||
result.filename = n.getFile
|
||||
result.line = n.getLine
|
||||
result.column = n.getColumn
|
||||
result = LineInfo(filename: n.getFile, line: n.getLine, column: n.getColumn)
|
||||
|
||||
proc lineInfo*(arg: NimNode): string {.compileTime.} =
|
||||
## Return line info in the form `filepath(line, column)`.
|
||||
@@ -878,12 +876,14 @@ proc treeRepr*(n: NimNode): string {.compileTime, benign.} =
|
||||
## Convert the AST `n` to a human-readable tree-like string.
|
||||
##
|
||||
## See also `repr`, `lispRepr`, and `astGenRepr`.
|
||||
result = ""
|
||||
n.treeTraverse(result, isLisp = false, indented = true)
|
||||
|
||||
proc lispRepr*(n: NimNode; indented = false): string {.compileTime, benign.} =
|
||||
## Convert the AST ``n`` to a human-readable lisp-like string.
|
||||
##
|
||||
## See also ``repr``, ``treeRepr``, and ``astGenRepr``.
|
||||
result = ""
|
||||
n.treeTraverse(result, isLisp = true, indented = indented)
|
||||
|
||||
proc astGenRepr*(n: NimNode): string {.compileTime, benign.} =
|
||||
@@ -1611,6 +1611,7 @@ macro getCustomPragmaVal*(n: typed, cp: typed{nkSym}): untyped =
|
||||
## assert(o.myField.getCustomPragmaVal(serializationKey) == "mf")
|
||||
## assert(o.getCustomPragmaVal(serializationKey) == "mo")
|
||||
## assert(MyObj.getCustomPragmaVal(serializationKey) == "mo")
|
||||
result = nil
|
||||
let pragmaNode = customPragmaNode(n)
|
||||
for p in pragmaNode:
|
||||
if p.kind in nnkPragmaCallKinds and p.len > 0 and p[0].kind == nnkSym and p[0] == cp:
|
||||
|
||||
@@ -187,6 +187,7 @@ proc binarySearch*[T, K](a: openArray[T], key: K,
|
||||
else:
|
||||
return -1
|
||||
|
||||
result = 0
|
||||
if (len and (len - 1)) == 0:
|
||||
# when `len` is a power of 2, a faster shr can be used.
|
||||
var step = len shr 1
|
||||
|
||||
@@ -395,6 +395,8 @@ proc firstSetBitNim(x: uint64): int {.inline, noSideEffect.} =
|
||||
if k == 0:
|
||||
k = uint32(v shr 32'u32) and 0xFFFFFFFF'u32
|
||||
result = 32
|
||||
else:
|
||||
result = 0
|
||||
result += firstSetBitNim(k)
|
||||
|
||||
proc fastlog2Nim(x: uint32): int {.inline, noSideEffect.} =
|
||||
|
||||
@@ -417,7 +417,8 @@ proc relativePath*(path, base: string, sep = DirSep): string {.
|
||||
if not sameRoot(path, base):
|
||||
return path
|
||||
|
||||
var f, b: PathIter
|
||||
var f = default PathIter
|
||||
var b = default PathIter
|
||||
var ff = (0, -1)
|
||||
var bb = (0, -1) # (int, int)
|
||||
result = newStringOfCap(path.len)
|
||||
@@ -1053,6 +1054,7 @@ when defined(windows) or defined(posix) or defined(nintendoswitch):
|
||||
assert quoteShellCommand(["aaa", "", "c d"]) == "aaa \"\" \"c d\""
|
||||
|
||||
# can't use `map` pending https://github.com/nim-lang/Nim/issues/8303
|
||||
result = ""
|
||||
for i in 0..<args.len:
|
||||
if i > 0: result.add " "
|
||||
result.add quoteShell(args[i])
|
||||
@@ -2981,7 +2983,7 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noW
|
||||
setLen(result, L)
|
||||
break
|
||||
elif defined(macosx):
|
||||
var size: cuint32
|
||||
var size = cuint32(0)
|
||||
getExecPath1(nil, size)
|
||||
result = newString(int(size))
|
||||
if getExecPath2(result, size):
|
||||
|
||||
@@ -249,6 +249,7 @@ proc skipWhitespace*(s: string, start = 0): int {.inline.} =
|
||||
doAssert skipWhitespace(" Hello World", 0) == 1
|
||||
doAssert skipWhitespace("Hello World", 5) == 1
|
||||
doAssert skipWhitespace("Hello World", 5) == 2
|
||||
result = 0
|
||||
while start+result < s.len and s[start+result] in Whitespace: inc(result)
|
||||
|
||||
proc skip*(s, token: string, start = 0): int {.inline.} =
|
||||
@@ -260,6 +261,7 @@ proc skip*(s, token: string, start = 0): int {.inline.} =
|
||||
doAssert skip("2019-01-22", "19", 2) == 2
|
||||
doAssert skip("CAPlow", "CAP", 0) == 3
|
||||
doAssert skip("CAPlow", "cap", 0) == 0
|
||||
result = 0
|
||||
while start+result < s.len and result < token.len and
|
||||
s[result+start] == token[result]:
|
||||
inc(result)
|
||||
@@ -270,6 +272,7 @@ proc skipIgnoreCase*(s, token: string, start = 0): int =
|
||||
runnableExamples:
|
||||
doAssert skipIgnoreCase("CAPlow", "CAP", 0) == 3
|
||||
doAssert skipIgnoreCase("CAPlow", "cap", 0) == 3
|
||||
result = 0
|
||||
while start+result < s.len and result < token.len and
|
||||
toLower(s[result+start]) == toLower(token[result]): inc(result)
|
||||
if result != token.len: result = 0
|
||||
@@ -282,6 +285,7 @@ proc skipUntil*(s: string, until: set[char], start = 0): int {.inline.} =
|
||||
doAssert skipUntil("Hello World", {'W', 'e'}, 0) == 1
|
||||
doAssert skipUntil("Hello World", {'W'}, 0) == 6
|
||||
doAssert skipUntil("Hello World", {'W', 'd'}, 0) == 6
|
||||
result = 0
|
||||
while start+result < s.len and s[result+start] notin until: inc(result)
|
||||
|
||||
proc skipUntil*(s: string, until: char, start = 0): int {.inline.} =
|
||||
@@ -293,6 +297,7 @@ proc skipUntil*(s: string, until: char, start = 0): int {.inline.} =
|
||||
doAssert skipUntil("Hello World", 'o', 4) == 0
|
||||
doAssert skipUntil("Hello World", 'W', 0) == 6
|
||||
doAssert skipUntil("Hello World", 'w', 0) == 11
|
||||
result = 0
|
||||
while start+result < s.len and s[result+start] != until: inc(result)
|
||||
|
||||
proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} =
|
||||
@@ -302,6 +307,7 @@ proc skipWhile*(s: string, toSkip: set[char], start = 0): int {.inline.} =
|
||||
doAssert skipWhile("Hello World", {'H', 'e'}) == 2
|
||||
doAssert skipWhile("Hello World", {'e'}) == 0
|
||||
doAssert skipWhile("Hello World", {'W', 'o', 'r'}, 6) == 3
|
||||
result = 0
|
||||
while start+result < s.len and s[result+start] in toSkip: inc(result)
|
||||
|
||||
proc parseUntil*(s: string, token: var string, until: set[char],
|
||||
@@ -437,7 +443,7 @@ proc parseBiggestInt*(s: string, number: var BiggestInt, start = 0): int {.
|
||||
var res: BiggestInt
|
||||
doAssert parseBiggestInt("9223372036854775807", res, 0) == 19
|
||||
doAssert res == 9223372036854775807
|
||||
var res: BiggestInt
|
||||
var res = BiggestInt(0)
|
||||
# use 'res' for exception safety (don't write to 'number' in case of an
|
||||
# overflow exception):
|
||||
result = rawParseInt(s, res, start)
|
||||
@@ -455,7 +461,7 @@ proc parseInt*(s: string, number: var int, start = 0): int {.
|
||||
doAssert res == 2019
|
||||
doAssert parseInt("2019", res, 2) == 2
|
||||
doAssert res == 19
|
||||
var res: BiggestInt
|
||||
var res = BiggestInt(0)
|
||||
result = parseBiggestInt(s, res, start)
|
||||
when sizeof(int) <= 4:
|
||||
if res < low(int) or res > high(int):
|
||||
@@ -518,7 +524,7 @@ proc parseBiggestUInt*(s: string, number: var BiggestUInt, start = 0): int {.
|
||||
doAssert res == 12
|
||||
doAssert parseBiggestUInt("1111111111111111111", res, 0) == 19
|
||||
doAssert res == 1111111111111111111'u64
|
||||
var res: BiggestUInt
|
||||
var res = BiggestUInt(0)
|
||||
# use 'res' for exception safety (don't write to 'number' in case of an
|
||||
# overflow exception):
|
||||
result = rawParseUInt(s, res, start)
|
||||
@@ -536,7 +542,7 @@ proc parseUInt*(s: string, number: var uint, start = 0): int {.
|
||||
doAssert res == 3450
|
||||
doAssert parseUInt("3450", res, 2) == 2
|
||||
doAssert res == 50
|
||||
var res: BiggestUInt
|
||||
var res = BiggestUInt(0)
|
||||
result = parseBiggestUInt(s, res, start)
|
||||
when sizeof(BiggestUInt) > sizeof(uint) and sizeof(uint) <= 4:
|
||||
if res > 0xFFFF_FFFF'u64:
|
||||
@@ -563,7 +569,7 @@ proc parseFloat*(s: string, number: var float, start = 0): int {.
|
||||
doAssert res == 32.57
|
||||
doAssert parseFloat("32.57", res, 3) == 2
|
||||
doAssert res == 57.00
|
||||
var bf: BiggestFloat
|
||||
var bf = BiggestFloat(0.0)
|
||||
result = parseBiggestFloat(s, bf, start)
|
||||
if result != 0:
|
||||
number = bf
|
||||
|
||||
@@ -44,7 +44,7 @@ proc next*(it: var PathIter; x: string): (int, int) =
|
||||
it.notFirst = true
|
||||
|
||||
iterator dirs(x: string): (int, int) =
|
||||
var it: PathIter
|
||||
var it = default PathIter
|
||||
while hasNext(it, x): yield next(it, x)
|
||||
|
||||
proc isDot(x: string; bounds: (int, int)): bool =
|
||||
|
||||
@@ -1103,6 +1103,7 @@ proc parseInt*(s: string): int {.noSideEffect,
|
||||
## If `s` is not a valid integer, `ValueError` is raised.
|
||||
runnableExamples:
|
||||
doAssert parseInt("-0042") == -42
|
||||
result = 0
|
||||
let L = parseutils.parseInt(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid integer: " & s)
|
||||
@@ -1112,6 +1113,7 @@ proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect,
|
||||
## Parses a decimal integer value contained in `s`.
|
||||
##
|
||||
## If `s` is not a valid integer, `ValueError` is raised.
|
||||
result = BiggestInt(0)
|
||||
let L = parseutils.parseBiggestInt(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid integer: " & s)
|
||||
@@ -1121,6 +1123,7 @@ proc parseUInt*(s: string): uint {.noSideEffect,
|
||||
## Parses a decimal unsigned integer value contained in `s`.
|
||||
##
|
||||
## If `s` is not a valid integer, `ValueError` is raised.
|
||||
result = uint(0)
|
||||
let L = parseutils.parseUInt(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid unsigned integer: " & s)
|
||||
@@ -1130,6 +1133,7 @@ proc parseBiggestUInt*(s: string): BiggestUInt {.noSideEffect,
|
||||
## Parses a decimal unsigned integer value contained in `s`.
|
||||
##
|
||||
## If `s` is not a valid integer, `ValueError` is raised.
|
||||
result = BiggestUInt(0)
|
||||
let L = parseutils.parseBiggestUInt(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid unsigned integer: " & s)
|
||||
@@ -1143,6 +1147,7 @@ proc parseFloat*(s: string): float {.noSideEffect,
|
||||
runnableExamples:
|
||||
doAssert parseFloat("3.14") == 3.14
|
||||
doAssert parseFloat("inf") == 1.0/0
|
||||
result = 0.0
|
||||
let L = parseutils.parseFloat(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid float: " & s)
|
||||
@@ -1161,6 +1166,7 @@ proc parseBinInt*(s: string): int {.noSideEffect,
|
||||
doAssert a.parseBinInt() == 53
|
||||
doAssert b.parseBinInt() == 7
|
||||
|
||||
result = 0
|
||||
let L = parseutils.parseBin(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid binary integer: " & s)
|
||||
@@ -1172,6 +1178,7 @@ proc parseOctInt*(s: string): int {.noSideEffect,
|
||||
## If `s` is not a valid oct integer, `ValueError` is raised. `s` can have one
|
||||
## of the following optional prefixes: ``0o``, ``0O``. Underscores within
|
||||
## `s` are ignored.
|
||||
result = 0
|
||||
let L = parseutils.parseOct(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid oct integer: " & s)
|
||||
@@ -1183,6 +1190,7 @@ proc parseHexInt*(s: string): int {.noSideEffect,
|
||||
## If `s` is not a valid hex integer, `ValueError` is raised. `s` can have one
|
||||
## of the following optional prefixes: ``0x``, ``0X``, ``#``. Underscores
|
||||
## within `s` are ignored.
|
||||
result = 0
|
||||
let L = parseutils.parseHex(s, result, 0)
|
||||
if L != s.len or L == 0:
|
||||
raise newException(ValueError, "invalid hex integer: " & s)
|
||||
@@ -1270,9 +1278,9 @@ macro genEnumStmt(typ: typedesc, argSym: typed, default: typed): untyped =
|
||||
result = nnkCaseStmt.newTree(nnkDotExpr.newTree(argSym,
|
||||
bindSym"nimIdentNormalize"))
|
||||
# stores all processed field strings to give error msg for ambiguous enums
|
||||
var foundFields: seq[string]
|
||||
var fStr: string # string of current field
|
||||
var fNum: BiggestInt # int value of current field
|
||||
var foundFields: seq[string] = @[]
|
||||
var fStr = "" # string of current field
|
||||
var fNum = BiggestInt(0) # int value of current field
|
||||
for f in impl:
|
||||
case f.kind
|
||||
of nnkEmpty: continue # skip first node of `enumTy`
|
||||
@@ -2028,6 +2036,7 @@ proc rfind*(s, sub: string, start: Natural = 0, last = -1): int {.noSideEffect,
|
||||
if sub.len == 0:
|
||||
return -1
|
||||
let last = if last == -1: s.high else: last
|
||||
result = 0
|
||||
for i in countdown(last - sub.len + 1, start):
|
||||
for j in 0..sub.len-1:
|
||||
result = i
|
||||
@@ -2044,6 +2053,7 @@ proc count*(s: string, sub: char): int {.noSideEffect,
|
||||
##
|
||||
## See also:
|
||||
## * `countLines proc<#countLines,string>`_
|
||||
result = 0
|
||||
for c in s:
|
||||
if c == sub: inc result
|
||||
|
||||
@@ -2054,6 +2064,7 @@ proc count*(s: string, subs: set[char]): int {.noSideEffect,
|
||||
## See also:
|
||||
## * `countLines proc<#countLines,string>`_
|
||||
doAssert card(subs) > 0
|
||||
result = 0
|
||||
for c in s:
|
||||
if c in subs: inc result
|
||||
|
||||
@@ -2066,6 +2077,7 @@ proc count*(s: string, sub: string, overlapping: bool = false): int {.
|
||||
## See also:
|
||||
## * `countLines proc<#countLines,string>`_
|
||||
doAssert sub.len > 0
|
||||
result = 0
|
||||
var i = 0
|
||||
while true:
|
||||
i = s.find(sub, i)
|
||||
@@ -2313,7 +2325,7 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
|
||||
case s[i+1]:
|
||||
of 'x':
|
||||
inc i, 2
|
||||
var c: int
|
||||
var c = 0
|
||||
i += parseutils.parseHex(s, c, i, maxLen = 2)
|
||||
result.add(chr(c))
|
||||
dec i, 2
|
||||
@@ -2514,7 +2526,7 @@ proc formatSize*(bytes: int64,
|
||||
xb: int64 = bytes
|
||||
fbytes: float
|
||||
lastXb: int64 = bytes
|
||||
matchedIndex: int
|
||||
matchedIndex = 0
|
||||
prefixes: array[9, string]
|
||||
if prefix == bpColloquial:
|
||||
prefixes = collPrefixes
|
||||
|
||||
@@ -895,16 +895,16 @@ proc getTime*(): Time {.tags: [TimeEffect], benign.} =
|
||||
millis mod convert(Seconds, Milliseconds, 1).int)
|
||||
result = initTime(seconds, nanos)
|
||||
elif defined(macosx):
|
||||
var a: Timeval
|
||||
var a {.noinit.}: Timeval
|
||||
gettimeofday(a)
|
||||
result = initTime(a.tv_sec.int64,
|
||||
convert(Microseconds, Nanoseconds, a.tv_usec.int))
|
||||
elif defined(posix):
|
||||
var ts: Timespec
|
||||
var ts {.noinit.}: Timespec
|
||||
discard clock_gettime(CLOCK_REALTIME, ts)
|
||||
result = initTime(ts.tv_sec.int64, ts.tv_nsec.int)
|
||||
elif defined(windows):
|
||||
var f: FILETIME
|
||||
var f {.noinit.}: FILETIME
|
||||
getSystemTimeAsFileTime(f)
|
||||
result = fromWinTime(rdFileTime(f))
|
||||
|
||||
@@ -1756,7 +1756,7 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string,
|
||||
proc parsePattern(input: string, pattern: FormatPattern, i: var int,
|
||||
parsed: var ParsedTime, loc: DateTimeLocale): bool =
|
||||
template takeInt(allowedWidth: Slice[int], allowSign = false): int =
|
||||
var sv: int
|
||||
var sv = 0
|
||||
var pd = parseInt(input, sv, i, allowedWidth.b, allowSign)
|
||||
if pd < allowedWidth.a:
|
||||
return false
|
||||
@@ -1987,6 +1987,7 @@ proc format*(dt: DateTime, f: TimeFormat,
|
||||
let dt = initDateTime(01, mJan, 2000, 00, 00, 00, utc())
|
||||
doAssert "2000-01-01" == dt.format(f)
|
||||
assertDateTimeInitialized dt
|
||||
result = ""
|
||||
var idx = 0
|
||||
while idx <= f.patterns.high:
|
||||
case f.patterns[idx].FormatPattern
|
||||
@@ -2284,7 +2285,7 @@ proc between*(startDt, endDt: DateTime): TimeInterval =
|
||||
endDate.monthday.dec
|
||||
|
||||
# Years
|
||||
result.years.inc endDate.year - startDate.year - 1
|
||||
result.years = endDate.year - startDate.year - 1
|
||||
if (startDate.month, startDate.monthday) <= (endDate.month, endDate.monthday):
|
||||
result.years.inc
|
||||
startDate.year.inc result.years
|
||||
@@ -2441,6 +2442,7 @@ proc evaluateInterval(dt: DateTime, interval: TimeInterval):
|
||||
var months = interval.years * 12 + interval.months
|
||||
var curYear = dt.year
|
||||
var curMonth = dt.month
|
||||
result = default(tuple[adjDur, absDur: Duration])
|
||||
# Subtracting
|
||||
if months < 0:
|
||||
for mth in countdown(-1 * months, 1):
|
||||
@@ -2562,17 +2564,17 @@ proc epochTime*(): float {.tags: [TimeEffect].} =
|
||||
##
|
||||
## ``getTime`` should generally be preferred over this proc.
|
||||
when defined(macosx):
|
||||
var a: Timeval
|
||||
var a {.noinit.}: Timeval
|
||||
gettimeofday(a)
|
||||
result = toBiggestFloat(a.tv_sec.int64) + toBiggestFloat(
|
||||
a.tv_usec)*0.00_0001
|
||||
elif defined(posix):
|
||||
var ts: Timespec
|
||||
var ts {.noinit.}: Timespec
|
||||
discard clock_gettime(CLOCK_REALTIME, ts)
|
||||
result = toBiggestFloat(ts.tv_sec.int64) +
|
||||
toBiggestFloat(ts.tv_nsec.int64) / 1_000_000_000
|
||||
elif defined(windows):
|
||||
var f: winlean.FILETIME
|
||||
var f {.noinit.}: winlean.FILETIME
|
||||
getSystemTimeAsFileTime(f)
|
||||
var i64 = rdFileTime(f) - epochDiff
|
||||
var secs = i64 div rateDiff
|
||||
|
||||
@@ -112,7 +112,7 @@ macro genericParamsImpl(T: typedesc): untyped =
|
||||
of nnkBracketExpr:
|
||||
for i in 1..<impl.len:
|
||||
let ai = impl[i]
|
||||
var ret: NimNode
|
||||
var ret: NimNode = nil
|
||||
case ai.typeKind
|
||||
of ntyTypeDesc:
|
||||
ret = ai
|
||||
|
||||
@@ -39,6 +39,7 @@ proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} =
|
||||
doAssert a.runeLen == 6
|
||||
## note: a.len == 8
|
||||
|
||||
result = 0
|
||||
var i = 0
|
||||
while i < len(s):
|
||||
if uint(s[i]) <= 127: inc(i)
|
||||
|
||||
@@ -4,7 +4,7 @@ const NimStackTraceMsgs = compileOption("stacktraceMsgs")
|
||||
template procName*(): string =
|
||||
## returns current C/C++ function name
|
||||
when defined(c) or defined(cpp):
|
||||
var name {.inject.}: cstring
|
||||
var name {.inject, noinit.}: cstring
|
||||
{.emit: "`name` = __func__;".}
|
||||
$name
|
||||
|
||||
@@ -12,7 +12,7 @@ template getPFrame*(): PFrame =
|
||||
## avoids a function call (unlike `getFrame()`)
|
||||
block:
|
||||
when NimStackTrace:
|
||||
var framePtr {.inject.}: PFrame
|
||||
var framePtr {.inject, noinit.}: PFrame
|
||||
{.emit: "`framePtr` = &FR_;".}
|
||||
framePtr
|
||||
|
||||
@@ -21,7 +21,7 @@ template setFrameMsg*(msg: string, prefix = " ") =
|
||||
## in a given PFrame. Noop unless passing --stacktraceMsgs and --stacktrace
|
||||
when NimStackTrace and NimStackTraceMsgs:
|
||||
block:
|
||||
var fr {.inject.}: PFrame
|
||||
var fr {.inject, noinit.}: PFrame
|
||||
{.emit: "`fr` = &FR_;".}
|
||||
# consider setting a custom upper limit on size (analog to stack overflow)
|
||||
frameMsgBuf.setLen fr.frameMsgLen
|
||||
|
||||
@@ -1767,6 +1767,7 @@ export iterators
|
||||
proc find*[T, S](a: T, item: S): int {.inline.}=
|
||||
## Returns the first index of `item` in `a` or -1 if not found. This requires
|
||||
## appropriate `items` and `==` operations to work.
|
||||
result = 0
|
||||
for i in items(a):
|
||||
if i == item: return
|
||||
inc(result)
|
||||
@@ -2105,7 +2106,7 @@ when not defined(js):
|
||||
# Linux 64bit system. -- That's because the stack direction is the other
|
||||
# way around.
|
||||
when declared(nimGC_setStackBottom):
|
||||
var locals {.volatile.}: pointer
|
||||
var locals {.volatile, noinit.}: pointer
|
||||
locals = addr(locals)
|
||||
nimGC_setStackBottom(locals)
|
||||
|
||||
@@ -2274,7 +2275,9 @@ when notJSnotNims:
|
||||
of 2: d = uint(cast[ptr uint16](a + uint(n.offset))[])
|
||||
of 4: d = uint(cast[ptr uint32](a + uint(n.offset))[])
|
||||
of 8: d = uint(cast[ptr uint64](a + uint(n.offset))[])
|
||||
else: sysAssert(false, "getDiscriminant: invalid n.typ.size")
|
||||
else:
|
||||
d = 0'u
|
||||
sysAssert(false, "getDiscriminant: invalid n.typ.size")
|
||||
return d
|
||||
|
||||
proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode =
|
||||
|
||||
@@ -586,7 +586,8 @@ proc freeBigChunk(a: var MemRegion, c: PBigChunk) =
|
||||
proc getBigChunk(a: var MemRegion, size: int): PBigChunk =
|
||||
sysAssert(size > 0, "getBigChunk 2")
|
||||
var size = size # roundup(size, PageSize)
|
||||
var fl, sl: int
|
||||
var fl = 0
|
||||
var sl = 0
|
||||
mappingSearch(size, fl, sl)
|
||||
sysAssert((size and PageMask) == 0, "getBigChunk: unaligned chunk")
|
||||
result = findSuitableBlock(a, fl, sl)
|
||||
|
||||
@@ -11,6 +11,7 @@ proc `$`(x: int): string {.magic: "IntToStr", noSideEffect.}
|
||||
proc `$`(info: InstantiationInfo): string =
|
||||
# The +1 is needed here
|
||||
# instead of overriding `$` (and changing its meaning), consider explicit name.
|
||||
result = ""
|
||||
result.toLocation(info.filename, info.line, info.column+1)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -217,7 +217,7 @@ proc stackSize(stack: ptr GcStack): int {.noinline.} =
|
||||
when nimCoroutines:
|
||||
var pos = stack.pos
|
||||
else:
|
||||
var pos {.volatile.}: pointer
|
||||
var pos {.volatile, noinit.}: pointer
|
||||
pos = addr(pos)
|
||||
|
||||
if pos != nil:
|
||||
@@ -229,6 +229,7 @@ proc stackSize(stack: ptr GcStack): int {.noinline.} =
|
||||
result = 0
|
||||
|
||||
proc stackSize(): int {.noinline.} =
|
||||
result = 0
|
||||
for stack in gch.stack.items():
|
||||
result = result + stack.stackSize()
|
||||
|
||||
@@ -303,7 +304,7 @@ when not defined(useNimRtl):
|
||||
{.pop.}
|
||||
|
||||
proc isOnStack(p: pointer): bool =
|
||||
var stackTop {.volatile.}: pointer
|
||||
var stackTop {.volatile, noinit.}: pointer
|
||||
stackTop = addr(stackTop)
|
||||
var a = cast[ByteAddress](gch.getActiveStack().bottom)
|
||||
var b = cast[ByteAddress](stackTop)
|
||||
|
||||
@@ -424,12 +424,12 @@ proc write*(f: File, b: bool) {.tags: [WriteIOEffect], benign.} =
|
||||
else: write(f, "false")
|
||||
|
||||
proc write*(f: File, r: float32) {.tags: [WriteIOEffect], benign.} =
|
||||
var buffer: array[65, char]
|
||||
var buffer {.noinit.}: array[65, char]
|
||||
discard writeFloatToBuffer(buffer, r)
|
||||
if c_fprintf(f, "%s", buffer[0].addr) < 0: checkErr(f)
|
||||
|
||||
proc write*(f: File, r: BiggestFloat) {.tags: [WriteIOEffect], benign.} =
|
||||
var buffer: array[65, char]
|
||||
var buffer {.noinit.}: array[65, char]
|
||||
discard writeFloatToBuffer(buffer, r)
|
||||
if c_fprintf(f, "%s", buffer[0].addr) < 0: checkErr(f)
|
||||
|
||||
@@ -591,7 +591,7 @@ when defined(posix) and not defined(nimscript):
|
||||
|
||||
proc open*(f: var File, filename: string,
|
||||
mode: FileMode = fmRead,
|
||||
bufSize: int = -1): bool {.tags: [], raises: [], benign.} =
|
||||
bufSize: int = -1): bool {.tags: [], raises: [], benign.} =
|
||||
## Opens a file named `filename` with given `mode`.
|
||||
##
|
||||
## Default mode is readonly. Returns true if the file could be opened.
|
||||
@@ -605,7 +605,7 @@ proc open*(f: var File, filename: string,
|
||||
# How `fopen` handles opening a directory is not specified in ISO C and
|
||||
# POSIX. We do not want to handle directories as regular files that can
|
||||
# be opened.
|
||||
var res: Stat
|
||||
var res {.noinit.}: Stat
|
||||
if c_fstat(getFileHandle(f2), res) >= 0'i32 and modeIsDir(res.st_mode):
|
||||
close(f2)
|
||||
return false
|
||||
@@ -759,7 +759,7 @@ proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.}
|
||||
## Raises an IO exception in case of an error. If you need to call
|
||||
## this inside a compile time macro you can use `staticRead
|
||||
## <system.html#staticRead,string>`_.
|
||||
var f: File
|
||||
var f: File = nil
|
||||
if open(f, filename):
|
||||
try:
|
||||
result = readAll(f)
|
||||
@@ -772,7 +772,7 @@ proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.} =
|
||||
## Opens a file named `filename` for writing. Then writes the
|
||||
## `content` completely to the file and closes the file afterwards.
|
||||
## Raises an IO exception in case of an error.
|
||||
var f: File
|
||||
var f: File = nil
|
||||
if open(f, filename, fmWrite):
|
||||
try:
|
||||
f.write(content)
|
||||
@@ -785,7 +785,7 @@ proc writeFile*(filename: string, content: openArray[byte]) {.since: (1, 1).} =
|
||||
## Opens a file named `filename` for writing. Then writes the
|
||||
## `content` completely to the file and closes the file afterwards.
|
||||
## Raises an IO exception in case of an error.
|
||||
var f: File
|
||||
var f: File = nil
|
||||
if open(f, filename, fmWrite):
|
||||
try:
|
||||
f.writeBuffer(unsafeAddr content[0], content.len)
|
||||
@@ -799,7 +799,7 @@ proc readLines*(filename: string, n: Natural): seq[TaintedString] =
|
||||
## in case of an error. Raises EOF if file does not contain at least `n` lines.
|
||||
## Available at compile time. A line of text may be delimited by ``LF`` or ``CRLF``.
|
||||
## The newline character(s) are not part of the returned strings.
|
||||
var f: File
|
||||
var f: File = nil
|
||||
if open(f, filename):
|
||||
try:
|
||||
result = newSeq[TaintedString](n)
|
||||
|
||||
@@ -102,6 +102,7 @@ proc reprSetAux(result: var string, p: pointer, typ: PNimType) =
|
||||
of 4: u = cast[ptr uint32](p)[]
|
||||
of 8: u = cast[ptr uint64](p)[]
|
||||
else:
|
||||
u = uint64(0)
|
||||
var a = cast[PByteArray](p)
|
||||
for i in 0 .. typ.size*8-1:
|
||||
if (uint(a[i shr 3]) and (1'u shl (i and 7))) != 0:
|
||||
|
||||
@@ -31,6 +31,7 @@ proc countBits64(n: uint64): int {.compilerproc, inline.} =
|
||||
|
||||
proc cardSet(s: NimSet, len: int): int {.compilerproc, inline.} =
|
||||
var i = 0
|
||||
result = 0
|
||||
when defined(x86) or defined(amd64):
|
||||
while i < len - 8:
|
||||
inc(result, countBits64((cast[ptr uint64](s[i].unsafeAddr))[]))
|
||||
|
||||
@@ -94,7 +94,7 @@ proc addFloat*(result: var string; x: float) =
|
||||
when nimvm:
|
||||
result.add $x
|
||||
else:
|
||||
var buffer: array[65, char]
|
||||
var buffer {.noinit.}: array[65, char]
|
||||
let n = writeFloatToBuffer(buffer, x)
|
||||
result.addCstringN(cstring(buffer[0].addr), n)
|
||||
|
||||
@@ -131,8 +131,8 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
||||
i = start
|
||||
sign = 1.0
|
||||
kdigits, fdigits = 0
|
||||
exponent: int
|
||||
integer: uint64
|
||||
exponent = 0
|
||||
integer = uint64(0)
|
||||
fracExponent = 0
|
||||
expSign = 1
|
||||
firstDigit = -1
|
||||
|
||||
@@ -63,6 +63,7 @@ proc ord(arg: Utf16Char): int = int(cast[uint16](arg))
|
||||
proc len*(w: WideCString): int =
|
||||
## returns the length of a widestring. This traverses the whole string to
|
||||
## find the binary zero end marker!
|
||||
result = 0
|
||||
while int16(w[result]) != 0'i16: inc result
|
||||
|
||||
const
|
||||
|
||||
@@ -6,8 +6,8 @@ discard """
|
||||
const expected = """
|
||||
tassert_c.nim(35) tassert_c
|
||||
tassert_c.nim(34) foo
|
||||
assertions.nim(29) failedAssertImpl
|
||||
assertions.nim(22) raiseAssert
|
||||
assertions.nim(30) failedAssertImpl
|
||||
assertions.nim(23) raiseAssert
|
||||
fatal.nim(49) sysFatal"""
|
||||
|
||||
proc tmatch(x, p: string): bool =
|
||||
@@ -36,4 +36,5 @@ try:
|
||||
except AssertionDefect:
|
||||
let e = getCurrentException()
|
||||
let trace = e.getStackTrace
|
||||
if tmatch(trace, expected): echo true else: echo "wrong trace:\n" & trace
|
||||
if tmatch(trace, expected): echo true
|
||||
else: echo "wrong trace:\n" & trace
|
||||
|
||||
28
tests/effects/toutparam.nim
Normal file
28
tests/effects/toutparam.nim
Normal file
@@ -0,0 +1,28 @@
|
||||
discard """
|
||||
cmd: '''nim c --warningAsError[Uninit]:on --skipCfg --skipParentCfg $file'''
|
||||
errormsg: "use explicit initialization of 'x' for clarity [Uninit]"
|
||||
line: 24
|
||||
disabled: "true"
|
||||
"""
|
||||
|
||||
proc gah[T](x: out T) =
|
||||
x = 3
|
||||
|
||||
proc main =
|
||||
var a: array[2, int]
|
||||
var x: int
|
||||
gah(x)
|
||||
a[0] = 3
|
||||
a[x] = 3
|
||||
echo x
|
||||
|
||||
main()
|
||||
|
||||
proc mainB =
|
||||
var a: array[2, int]
|
||||
var x: int
|
||||
a[0] = 3
|
||||
a[x] = 3
|
||||
echo x
|
||||
|
||||
mainB()
|
||||
@@ -1,5 +1,5 @@
|
||||
discard """
|
||||
nimout: "Warning: 'y' might not have been initialized [Uninit]"
|
||||
nimout: "Warning: use explicit initialization of 'y' for clarity [Uninit]"
|
||||
line:34
|
||||
action: compile
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user