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:
parent
a9eee6db65
commit
da29222f86
53 changed files with 355 additions and 257 deletions
|
|
@ -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 != {}:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue