diff options
author | Parashurama <Rhagdamaziel@ymail.com> | 2017-09-02 22:53:22 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2017-09-02 22:53:22 +0200 |
commit | 0861249de75adabc5d9761c77f7f057644014fd2 (patch) | |
tree | 314d6863b0c8fa50afd83b30ff1d6ccf6c3abf89 | |
parent | 6ce6883fad6a31f92f71fe271c3b2c82a17d0562 (diff) | |
download | Nim-0861249de75adabc5d9761c77f7f057644014fd2.tar.gz |
Fix seq.setLen initialisation in VM (#6224)
-rw-r--r-- | compiler/ccgexprs.nim | 9 | ||||
-rw-r--r-- | compiler/vm.nim | 31 | ||||
-rw-r--r-- | tests/vm/tseq_badinit.nim | 58 |
3 files changed, 90 insertions, 8 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 74f8f90cd..926f30985 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -2315,6 +2315,15 @@ proc genConstExpr(p: BProc, n: PNode): Rope = var t = skipTypes(n.typ, abstractInst) if t.kind == tySequence: result = genConstSeq(p, n, n.typ) + elif t.kind == tyProc and t.callConv == ccClosure and not n.sons.isNil and + n.sons[0].kind == nkNilLit and n.sons[1].kind == nkNilLit: + # this hack fixes issue that nkNilLit is expanded to {NIM_NIL,NIM_NIL} + # this behaviour is needed since closure_var = nil must be + # expanded to {NIM_NIL,NIM_NIL} + # in VM closures are initialized with nkPar(nkNilLit, nkNilLit) + # leading to duplicate code like this: + # "{NIM_NIL,NIM_NIL}, {NIM_NIL,NIM_NIL}" + result = ~"{NIM_NIL,NIM_NIL}" else: result = genConstSimpleList(p, n) of nkObjConstr: diff --git a/compiler/vm.nim b/compiler/vm.nim index 2dd6d6a9c..93cf66c05 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -409,6 +409,28 @@ proc recSetFlagIsRef(arg: PNode) = for i in 0 ..< arg.safeLen: arg.sons[i].recSetFlagIsRef +proc setLenSeq(c: PCtx; node: PNode; newLen: int; info: TLineInfo) = + # FIXME: this doesn't attempt to solve incomplete + # support of tyPtr, tyRef in VM. + let typ = node.typ.skipTypes(abstractInst+{tyRange}-{tyTypeDesc}) + let typeEntry = typ.sons[0].skipTypes(abstractInst+{tyRange}-{tyTypeDesc}) + let typeKind = case typeEntry.kind + of tyUInt..tyUInt64: nkUIntLit + of tyRange, tyEnum, tyBool, tyChar, tyInt..tyInt64: nkIntLit + of tyFloat..tyFloat128: nkFloatLit + of tyString: nkStrLit + of tyObject: nkObjConstr + of tySequence: nkNilLit + of tyProc, tyTuple: nkPar + else: nkEmpty + + let oldLen = node.len + setLen(node.sons, newLen) + if oldLen < newLen: + # TODO: This is still not correct for tyPtr, tyRef default value + for i in oldLen .. <newLen: + node.sons[i] = newNodeI(typeKind, info) + proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = var pc = start var tos = tos @@ -1118,14 +1140,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = decodeB(rkNode) let newLen = regs[rb].intVal.int if regs[ra].node.isNil: stackTrace(c, tos, pc, errNilAccess) - else: - let oldLen = regs[ra].node.len - setLen(regs[ra].node.sons, newLen) - if oldLen < newLen: - # XXX This is still not entirely correct - # set to default value: - for i in oldLen .. <newLen: - regs[ra].node.sons[i] = newNodeI(nkEmpty, c.debug[pc]) + else: c.setLenSeq(regs[ra].node, newLen, c.debug[pc]) of opcReset: internalError(c.debug[pc], "too implement") of opcNarrowS: diff --git a/tests/vm/tseq_badinit.nim b/tests/vm/tseq_badinit.nim new file mode 100644 index 000000000..15889d60e --- /dev/null +++ b/tests/vm/tseq_badinit.nim @@ -0,0 +1,58 @@ + +type + AObj = object + i: int + d: float + ATup = tuple + i: int + d: float + MyEnum = enum + E01, E02, E03 + Myrange = range[0..10] + + MyProc = proc (x: int): bool + MyInt = distinct int + MyAlias = MyInt + MySet = set[char] + MyArray = array[4, char] + MySeq = seq[string] + +template test(typename, default: untyped) = + proc `abc typename`(): seq[typename] = + result = newSeq[typename]() + result.add(default) + result.setLen(3) + for i in 0 .. <2: + result[i] = default + + const constval = `abc typename`() + doAssert(constval == `abc typename`()) + + proc `arr typename`(): array[4, typename] = + for i in 0 .. <2: + result[i] = default + const constarr = `arr typename`() + doAssert(constarr == `arr typename`()) + +proc even(x: int): bool = x mod 2 == 0 +proc `==`(x, y: MyInt): bool = ord(x) == ord(y) +proc `$`(x: MyInt): string = $ord(x) +proc `$`(x: proc): string = + if x.isNil: "(nil)" else: "funcptr" + +test(int, 0) +test(uint, 0) +test(float, 0.1) +test(char, '0') +test(bool, false) +test(uint8, 2) +test(string, "data") +test(MyProc, even) +test(MyEnum, E02) +test(AObj, AObj()) +test(ATup, (i:11, d:9.99)) +test(Myrange, 4) +test(MyInt, MyInt(4)) +test(MyAlias, MyAlias(4)) +test(MyArray, ['0','1','2','3']) +test(MySeq, @["data"]) |