Fix fat pointers, object copying, magic double evals on JS (#9411) [backport]
* Add a test for issue #9389 * Fixes #9389. * Make object contructors copy objects properly by checking whether the expressions passed to them don't need to be copied. * Make mArrToSeq implementation actually check if a copy needs to be made. * Avoid unnecessary copy in mChr impl * Assume set constructor elements need no copy * Add a test for issue #9410 * Add a test * fix passing fat pointers (#9410) * Enhance tests * More tests and fixes * Add more (failing) tests [ci skip] * Added equality operator for fat pointers, more tests and fixes * Fix printing uninitialized strings * Fix mInc, mDec double eval, add more tests * Tests * Refactored, fixed multiple evals, revamped the tests, added missing ops * Fix ups * Fix #9643 and #9644 * add pointer normalization
This commit is contained in:
parent
07744b6e47
commit
e3e5ae287f
6 changed files with 745 additions and 83 deletions
454
tests/js/t9410.nim
Normal file
454
tests/js/t9410.nim
Normal file
|
|
@ -0,0 +1,454 @@
|
|||
template doAssert(exp: untyped) =
|
||||
when defined(echot9410):
|
||||
let r = exp
|
||||
echo $(instantiationInfo().line) & ":\n " & astToStr(exp) & "\n was " & repr(r)
|
||||
when not defined(noassertt9410):
|
||||
system.doAssert r
|
||||
else:
|
||||
when not defined(noassertt9410):
|
||||
system.doAssert exp
|
||||
|
||||
template tests =
|
||||
block:
|
||||
var i = 0
|
||||
i = 2
|
||||
|
||||
var y: ptr int
|
||||
doAssert y == nil
|
||||
doAssert isNil(y)
|
||||
y = i.addr
|
||||
y[] = 3
|
||||
doAssert i == 3
|
||||
doAssert i == y[]
|
||||
|
||||
let z = i.addr
|
||||
z[] = 4
|
||||
doAssert i == 4
|
||||
doAssert i == y[] and y[] == z[]
|
||||
|
||||
var hmm = (a: (b: z))
|
||||
var hmmptr = hmm.a.b.addr
|
||||
hmmptr[][] = 5
|
||||
|
||||
doAssert i == 5
|
||||
doAssert y == z
|
||||
doAssert z == hmmptr[]
|
||||
doAssert 5 == y[] and 5 == z[] and 5 == hmmptr[][]
|
||||
|
||||
block:
|
||||
var someint = 500
|
||||
|
||||
let p: ptr int = someint.addr
|
||||
let tup = (f: p)
|
||||
let tcopy = tup
|
||||
var vtcopy = tcopy
|
||||
p[] = 654
|
||||
doAssert p[] == 654
|
||||
doAssert tup.f[] == 654
|
||||
doAssert tcopy.f[] == 654
|
||||
doAssert vtcopy.f[] == 654
|
||||
|
||||
block:
|
||||
var someint = 500
|
||||
|
||||
var p: ptr int = someint.addr
|
||||
let arr = [p]
|
||||
let arrc = arr
|
||||
p[] = 256
|
||||
doAssert someint == 256
|
||||
doAssert p[] == 256
|
||||
doAssert arr[0][] == 256
|
||||
doAssert arrc[0][] == 256
|
||||
|
||||
block:
|
||||
var someref: ref int
|
||||
new(someref)
|
||||
var someref2 = someref
|
||||
|
||||
var tup1 = (f: someref)
|
||||
tup1.f = someref
|
||||
let tup2 = tup1
|
||||
|
||||
someref[] = 543
|
||||
|
||||
proc passref(r: var ref int): var ref int = r
|
||||
new(passref(someref))
|
||||
|
||||
doAssert someref[] == 0
|
||||
doAssert tup1.f[] == 543
|
||||
doAssert tup2.f[] == 543
|
||||
doAssert someref2[] == 543
|
||||
|
||||
block:
|
||||
type Whatever = object
|
||||
i: ref int
|
||||
|
||||
var someref: ref int
|
||||
new(someref)
|
||||
someref[] = 10
|
||||
|
||||
let w = Whatever(i: someref)
|
||||
var wcopy = w
|
||||
|
||||
someref[] = 20
|
||||
|
||||
doAssert w.i[] == 20
|
||||
doAssert someref[] == 20
|
||||
doAssert wcopy.i[] == 20
|
||||
doAssert w.i == wcopy.i
|
||||
#echo w.i[], " ", someref[], " ", wcopy.i[]
|
||||
|
||||
block:
|
||||
var oneseq: ref seq[ref int]
|
||||
new(oneseq)
|
||||
var aref: ref int
|
||||
new(aref)
|
||||
aref[] = 123
|
||||
let arefs = [aref]
|
||||
oneseq[] &= arefs[0]
|
||||
oneseq[] &= aref
|
||||
aref[] = 222
|
||||
new(aref)
|
||||
doAssert oneseq[0] == oneseq[1]
|
||||
doAssert oneseq[0][] == 222
|
||||
doAssert oneseq[1][] == 222
|
||||
doAssert aref[] == 0
|
||||
|
||||
block:
|
||||
var seqs: ref seq[ref seq[ref int]]
|
||||
new(seqs)
|
||||
seqs[] = newSeq[ref seq[ref int]](1)
|
||||
new(seqs[0])
|
||||
seqs[0][] = newSeq[ref int](0)
|
||||
|
||||
var aref: ref int
|
||||
new aref
|
||||
aref[] = 654
|
||||
|
||||
let arefs = [aref]
|
||||
doAssert arefs[0] == aref
|
||||
seqs[0][] &= arefs[0]
|
||||
seqs[0][] &= aref
|
||||
seqs[0][1][] = 456
|
||||
let seqs2 = seqs
|
||||
let same = seqs2[0][0] == seqs2[0][1]
|
||||
doAssert arefs[0] == aref
|
||||
doAssert aref[] == 456
|
||||
doAssert seqs[].len == 1
|
||||
doAssert seqs[0][].len == 2
|
||||
doAssert seqs[0][0][] == 456
|
||||
doAssert seqs[0][1][] == 456
|
||||
doAssert same
|
||||
|
||||
block:
|
||||
type Obj = object
|
||||
x, y: int
|
||||
|
||||
var objrefs: seq[ref Obj] = @[(ref Obj)(nil), nil, nil]
|
||||
objrefs[2].new
|
||||
objrefs[2][] = Obj(x: 123, y: 321)
|
||||
objrefs[1] = objrefs[2]
|
||||
doAssert objrefs[0] == nil
|
||||
doAssert objrefs[1].y == 321
|
||||
doAssert objrefs[2].y == 321
|
||||
doAssert objrefs[1] == objrefs[2]
|
||||
|
||||
block:
|
||||
var refs: seq[ref string] = @[(ref string)(nil), nil, nil]
|
||||
refs[1].new
|
||||
refs[1][] = "it's a ref!"
|
||||
refs[0] = refs[1]
|
||||
refs[2] = refs[1]
|
||||
new(refs[0])
|
||||
doAssert refs[0][] == ""
|
||||
doAssert refs[1][] == "it's a ref!"
|
||||
doAssert refs[2][] == "it's a ref!"
|
||||
doAssert refs[1] == refs[2]
|
||||
|
||||
block:
|
||||
var retaddr_calls = 0
|
||||
proc retaddr(p: var int): var int =
|
||||
retaddr_calls += 1
|
||||
p
|
||||
|
||||
var tfoo_calls = 0
|
||||
proc tfoo(x: var int) =
|
||||
tfoo_calls += 1
|
||||
x += 10
|
||||
var y = x.addr
|
||||
y[] += 20
|
||||
retaddr(x) += 30
|
||||
let z = retaddr(x).addr
|
||||
z[] += 40
|
||||
|
||||
var ints = @[1, 2, 3]
|
||||
tfoo(ints[1])
|
||||
doAssert retaddr_calls == 2
|
||||
doAssert tfoo_calls == 1
|
||||
doAssert ints[1] == 102
|
||||
|
||||
var tbar_calls = 0
|
||||
proc tbar(x: var int): var int =
|
||||
tbar_calls += 1
|
||||
x
|
||||
|
||||
tbar(ints[2]) += 10
|
||||
tbar(ints[2]) *= 2
|
||||
doAssert tbar_calls == 2
|
||||
|
||||
var tqux_calls = 0
|
||||
proc tqux(x: var int): ptr int =
|
||||
tqux_calls += 1
|
||||
x.addr
|
||||
|
||||
discard tqux(ints[2]) == tqux(ints[2])
|
||||
doAssert tqux_calls == 2
|
||||
doAssert isNil(tqux(ints[2])) == false
|
||||
doAssert tqux_calls == 3
|
||||
|
||||
var tseq_calls = 0
|
||||
proc tseq(x: var seq[int]): var seq[int] =
|
||||
tseq_calls += 1
|
||||
x
|
||||
|
||||
tseq(ints) &= 999
|
||||
doAssert tseq_calls == 1
|
||||
doAssert ints == @[1, 102, 26, 999]
|
||||
|
||||
var rawints = @[555]
|
||||
rawints &= 666
|
||||
doAssert rawints == @[555, 666]
|
||||
|
||||
var resetints_calls = 0
|
||||
proc resetInts(): int =
|
||||
resetints_calls += 1
|
||||
ints = @[0, 0, 0]
|
||||
1
|
||||
|
||||
proc incr(x: var int; b: int): var int =
|
||||
x = x + b
|
||||
x
|
||||
|
||||
var q = 0
|
||||
var qp = q.addr
|
||||
qp[] += 123
|
||||
doAssert q == 123
|
||||
# check order of evaluation
|
||||
doAssert (resetInts() + incr(q, tqux(ints[2])[])) == 124
|
||||
|
||||
block: # reset
|
||||
var calls = 0
|
||||
proc passsomething(x: var int): var int =
|
||||
calls += 1
|
||||
x
|
||||
|
||||
var
|
||||
a = 123
|
||||
b = 500
|
||||
c = a.addr
|
||||
reset(passsomething(a))
|
||||
doAssert calls == 1
|
||||
reset(b)
|
||||
doAssert a == b
|
||||
reset(c)
|
||||
doAssert c == nil
|
||||
|
||||
block: # strings
|
||||
var calls = 0
|
||||
proc stringtest(s: var string): var string =
|
||||
calls += 1
|
||||
s
|
||||
|
||||
var somestr: string
|
||||
|
||||
stringtest(somestr) &= 'a'
|
||||
stringtest(somestr) &= 'b'
|
||||
doAssert calls == 2
|
||||
doAssert somestr == "ab"
|
||||
stringtest(somestr) &= "woot!"
|
||||
doAssert somestr == "abwoot!"
|
||||
doAssert calls == 3
|
||||
|
||||
doAssert stringtest(somestr).len == 7
|
||||
doAssert calls == 4
|
||||
doAssert high(stringtest(somestr)) == 6
|
||||
doAssert calls == 5
|
||||
|
||||
var somestr2: string
|
||||
stringtest(somestr2).setLen(stringtest(somestr).len)
|
||||
doAssert calls == 7
|
||||
doAssert somestr2.len == somestr.len
|
||||
|
||||
var somestr3: string
|
||||
doAssert (somestr3 & "foo") == "foo"
|
||||
|
||||
block:
|
||||
var a, b, c, d: string
|
||||
d = a & b & c
|
||||
doAssert d == ""
|
||||
d = stringtest(a) & stringtest(b) & stringtest(c)
|
||||
doAssert calls == 10
|
||||
doAssert d == ""
|
||||
|
||||
block: # seqs
|
||||
var calls = 0
|
||||
proc seqtest(s: var seq[int]): var seq[int] =
|
||||
calls += 1
|
||||
s
|
||||
|
||||
var someseq: seq[int]
|
||||
|
||||
seqtest(someseq) &= 1
|
||||
seqtest(someseq) &= 2
|
||||
doAssert calls == 2
|
||||
doAssert someseq == @[1, 2]
|
||||
seqtest(someseq) &= @[3, 4, 5]
|
||||
doAssert someseq == @[1, 2, 3, 4, 5]
|
||||
doAssert calls == 3
|
||||
|
||||
doAssert seqtest(someseq).len == 5
|
||||
doAssert calls == 4
|
||||
doAssert high(seqtest(someseq)) == 4
|
||||
doAssert calls == 5
|
||||
|
||||
# genArrayAddr
|
||||
doAssert seqtest(someseq)[2] == 3
|
||||
doAssert calls == 6
|
||||
|
||||
seqtest(someseq).setLen(seqtest(someseq).len)
|
||||
doAssert calls == 8
|
||||
|
||||
var somenilseq: seq[int]
|
||||
seqtest(somenilseq).setLen(3)
|
||||
doAssert calls == 9
|
||||
doAssert somenilseq[1] == 0
|
||||
|
||||
someseq = @[1, 2, 3]
|
||||
doAssert (seqtest(someseq) & seqtest(someseq)) == @[1, 2, 3, 1, 2, 3]
|
||||
|
||||
|
||||
block: # mInc, mDec
|
||||
var calls = 0
|
||||
proc someint(x: var int): var int =
|
||||
calls += 1
|
||||
x
|
||||
|
||||
var x = 10
|
||||
|
||||
inc(someint(x))
|
||||
doAssert x == 11
|
||||
doAssert calls == 1
|
||||
|
||||
dec(someint(x))
|
||||
doAssert x == 10
|
||||
doAssert calls == 2
|
||||
|
||||
block: # uints
|
||||
var calls = 0
|
||||
proc passuint(x: var uint32): var uint32 =
|
||||
calls += 1
|
||||
x
|
||||
|
||||
var u: uint32 = 5
|
||||
passuint(u) += 1
|
||||
doAssert u == 6
|
||||
doAssert calls == 1
|
||||
|
||||
passuint(u) -= 1
|
||||
doAssert u == 5
|
||||
doAssert calls == 2
|
||||
|
||||
passuint(u) *= 2
|
||||
doAssert u == 10
|
||||
doAssert calls == 3
|
||||
|
||||
block: # objs
|
||||
type Thing = ref object
|
||||
x, y: int
|
||||
|
||||
var a, b: Thing
|
||||
a = Thing()
|
||||
b = a
|
||||
|
||||
doAssert a == b
|
||||
|
||||
var calls = 0
|
||||
proc passobj(o: var Thing): var Thing =
|
||||
calls += 1
|
||||
o
|
||||
|
||||
passobj(b) = Thing(x: 123)
|
||||
doAssert calls == 1
|
||||
doAssert a != b
|
||||
doAssert b.x == 123
|
||||
|
||||
var passobjptr_calls = 0
|
||||
proc passobjptr(o: var Thing): ptr Thing =
|
||||
passobjptr_calls += 1
|
||||
o.addr
|
||||
|
||||
passobjptr(b)[] = Thing(x: 234)
|
||||
doAssert passobjptr_calls == 1
|
||||
doAssert a != b
|
||||
doAssert b.x == 234
|
||||
passobjptr(b)[].x = 500
|
||||
doAssert b.x == 500
|
||||
|
||||
var pptr = passobjptr(b)
|
||||
pptr.x += 100
|
||||
doAssert b.x == 600
|
||||
|
||||
proc getuninitptr(): ptr int =
|
||||
return
|
||||
|
||||
doAssert getuninitptr() == nil
|
||||
|
||||
block: # pointer casting
|
||||
var obj = (x: 321, y: 543)
|
||||
var x = 500
|
||||
|
||||
var objptr = obj.addr
|
||||
var xptr = x.addr
|
||||
|
||||
var p1, p2: pointer
|
||||
p1 = cast[pointer](objptr)
|
||||
p2 = cast[pointer](xptr)
|
||||
doAssert p1 != p2
|
||||
|
||||
p1 = cast[pointer](objptr)
|
||||
p2 = cast[pointer](objptr)
|
||||
doAssert p1 == p2
|
||||
|
||||
let objptr2 = cast[type(objptr)](p2)
|
||||
doAssert objptr == objptr2
|
||||
|
||||
p1 = cast[pointer](xptr)
|
||||
p2 = cast[pointer](xptr)
|
||||
doAssert p1 == p2
|
||||
|
||||
let xptr2 = cast[type(xptr)](p2)
|
||||
doAssert xptr == xptr2
|
||||
|
||||
when false:
|
||||
block: # openarray
|
||||
# Error: internal error: genAddr: nkStmtListExpr
|
||||
var calls = 0
|
||||
proc getvarint(x: var openarray[int]): var int =
|
||||
calls += 1
|
||||
if true:
|
||||
x[1]
|
||||
else:
|
||||
x[0]
|
||||
|
||||
var arr = [1, 2, 3]
|
||||
getvarint(arr) += 5
|
||||
doAssert calls == 1
|
||||
doAssert arr[1] == 7
|
||||
|
||||
proc tests_in_proc =
|
||||
tests
|
||||
|
||||
# since pointers are handled differently in global/local contexts
|
||||
# let's just run all of them twice
|
||||
tests_in_proc()
|
||||
tests
|
||||
|
|
@ -2,6 +2,10 @@ discard """
|
|||
output: '''123
|
||||
2 9
|
||||
2 9
|
||||
1 124
|
||||
true false
|
||||
100 300 100
|
||||
1
|
||||
'''
|
||||
"""
|
||||
|
||||
|
|
@ -35,3 +39,34 @@ block:
|
|||
obj.ary2[1] = 9
|
||||
|
||||
echo ary1[1], " ", obj.ary2[1]
|
||||
|
||||
block:
|
||||
type TestObj = object
|
||||
x, y: int
|
||||
|
||||
let obj = TestObj(x: 1, y: 2)
|
||||
var s = @[obj]
|
||||
s[0].x += 123
|
||||
echo obj.x, " ", s[0].x
|
||||
|
||||
block:
|
||||
var nums = {1, 2, 3, 4}
|
||||
let obj = (n: nums)
|
||||
nums.incl 5
|
||||
echo (5 in nums), " ", (5 in obj.n)
|
||||
|
||||
block:
|
||||
let tup1 = (a: 100)
|
||||
var tup2 = (t: (t2: tup1))
|
||||
var tup3 = tup1
|
||||
tup2.t.t2.a = 300
|
||||
echo tup1.a, " ", tup2.t.t2.a, " ", tup3.a
|
||||
|
||||
block:
|
||||
proc foo(arr: array[2, int]) =
|
||||
var s = @arr
|
||||
s[0] = 500
|
||||
|
||||
var nums = [1, 2]
|
||||
foo(nums)
|
||||
echo nums[0]
|
||||
Loading…
Add table
Add a link
Reference in a new issue