diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2020-06-23 10:53:57 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-23 10:53:57 +0200 |
commit | da29222f86f7689227ffe12605842d18c9bf0fc1 (patch) | |
tree | 312152d96e2313a81170c772ff7b51475299f344 /compiler | |
parent | a9eee6db65e72e0e11cbf5faf0794b1b6ac8bd0c (diff) | |
download | Nim-da29222f86f7689227ffe12605842d18c9bf0fc1.tar.gz |
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
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 12 | ||||
-rw-r--r-- | compiler/ccgcalls.nim | 14 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 12 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 2 | ||||
-rw-r--r-- | compiler/dfa.nim | 6 | ||||
-rw-r--r-- | compiler/guards.nim | 2 | ||||
-rw-r--r-- | compiler/jsgen.nim | 2 | ||||
-rw-r--r-- | compiler/lineinfos.nim | 2 | ||||
-rw-r--r-- | compiler/lowerings.nim | 2 | ||||
-rw-r--r-- | compiler/nim.cfg | 4 | ||||
-rw-r--r-- | compiler/nimsets.nim | 32 | ||||
-rw-r--r-- | compiler/parampatterns.nim | 6 | ||||
-rw-r--r-- | compiler/parser.nim | 6 | ||||
-rw-r--r-- | compiler/renderer.nim | 8 | ||||
-rw-r--r-- | compiler/renderverbatim.nim | 1 | ||||
-rw-r--r-- | compiler/semcall.nim | 2 | ||||
-rw-r--r-- | compiler/semexprs.nim | 6 | ||||
-rw-r--r-- | compiler/semmagic.nim | 3 | ||||
-rw-r--r-- | compiler/semobjconstr.nim | 2 | ||||
-rw-r--r-- | compiler/sempass2.nim | 219 | ||||
-rw-r--r-- | compiler/semstmts.nim | 18 | ||||
-rw-r--r-- | compiler/semtypes.nim | 8 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 12 | ||||
-rw-r--r-- | compiler/spawn.nim | 4 | ||||
-rw-r--r-- | compiler/transf.nim | 10 | ||||
-rw-r--r-- | compiler/types.nim | 2 | ||||
-rw-r--r-- | compiler/writetracking.nim | 6 |
27 files changed, 210 insertions, 193 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 9639f52d3..66a1a253b 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 3dd2b54d4..80f02b6c3 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -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) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 2850ab750..a59529021 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -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: diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 199d5c918..11743499d 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -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) diff --git a/compiler/dfa.nim b/compiler/dfa.nim index a0ec31ac6..c393b2c81 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -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]): diff --git a/compiler/guards.nim b/compiler/guards.nim index e4f87bae4..a6ca44978 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -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 = diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 99d2bc4f2..57a6b8094 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -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") diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index bc3c51d53..6287e21aa 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -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", diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 575bfe8aa..5e75c36de 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -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) diff --git a/compiler/nim.cfg b/compiler/nim.cfg index a77fa84d3..8e733bdf8 100644 --- a/compiler/nim.cfg +++ b/compiler/nim.cfg @@ -21,3 +21,7 @@ define:useStdoutAsStdmsg #define:useNodeIds #gc:markAndSweep + +@if nimHasWarningObservableStores: + warning[ObservableStores]: off +@end diff --git a/compiler/nimsets.nim b/compiler/nimsets.nim index 3876a114e..8683604af 100644 --- a/compiler/nimsets.nim +++ b/compiler/nimsets.nim @@ -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 = diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index e97631b77..ce9a855d8 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -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 diff --git a/compiler/parser.nim b/compiler/parser.nim index 868054f36..ccb7ca3b1 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -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) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 6c953dc18..4b8c78cc7 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -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) diff --git a/compiler/renderverbatim.nim b/compiler/renderverbatim.nim index d20ee1549..2dce6824c 100644 --- a/compiler/renderverbatim.nim +++ b/compiler/renderverbatim.nim @@ -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]) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 665eb4ea4..405de52ee 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -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 diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 200d1d60a..6f267b4eb 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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! diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 438f2dbc7..e7a964d81 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -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]) diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index 682e74440..f8639b000 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -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.") diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index 6808b1b9b..49fa44ca2 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -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 diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 6ffaa9dda..5875a3b68 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -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 diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index eba8dd397..5407b9435 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index e99269c41..e663f96b6 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -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: diff --git a/compiler/spawn.nim b/compiler/spawn.nim index 8b1f89e15..9d837b993 100644 --- a/compiler/spawn.nim +++ b/compiler/spawn.nim @@ -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}: diff --git a/compiler/transf.nim b/compiler/transf.nim index bd9f567ed..10a2680ae 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -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: diff --git a/compiler/types.nim b/compiler/types.nim index aaaa8e99f..b8f58c950 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -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, diff --git a/compiler/writetracking.nim b/compiler/writetracking.nim index 3db60a19a..44ef3a937 100644 --- a/compiler/writetracking.nim +++ b/compiler/writetracking.nim @@ -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 != {}: |