diff options
Diffstat (limited to 'tests')
345 files changed, 7971 insertions, 442 deletions
diff --git a/tests/alloc/tmembug.nim b/tests/alloc/tmembug.nim new file mode 100644 index 000000000..63b51ec5d --- /dev/null +++ b/tests/alloc/tmembug.nim @@ -0,0 +1,54 @@ +discard """ + joinable: false +""" + +import std / [atomics, strutils, sequtils] + +type + BackendMessage* = object + field*: seq[int] + +var + chan1: Channel[BackendMessage] + chan2: Channel[BackendMessage] + +chan1.open() +chan2.open() + +proc routeMessage*(msg: BackendMessage) = + discard chan2.trySend(msg) + +var + recv: Thread[void] + stopToken: Atomic[bool] + +proc recvMsg() = + while not stopToken.load(moRelaxed): + let resp = chan1.tryRecv() + if resp.dataAvailable: + routeMessage(resp.msg) + echo "child consumes ", formatSize getOccupiedMem() + +createThread[void](recv, recvMsg) + +const MESSAGE_COUNT = 100 + +proc main() = + let msg: BackendMessage = BackendMessage(field: (0..500).toSeq()) + for j in 0..0: #100: + echo "New iteration" + + for _ in 1..MESSAGE_COUNT: + chan1.send(msg) + echo "After sending" + + var counter = 0 + while counter < MESSAGE_COUNT: + let resp = recv(chan2) + counter.inc + echo "After receiving ", formatSize getOccupiedMem() + + stopToken.store true, moRelaxed + joinThreads(recv) + +main() diff --git a/tests/alloc/tmembug2.nim b/tests/alloc/tmembug2.nim new file mode 100644 index 000000000..01bce6f14 --- /dev/null +++ b/tests/alloc/tmembug2.nim @@ -0,0 +1,58 @@ +discard """ + disabled: "true" +""" + +import std / [atomics, strutils, sequtils, isolation] + +import threading / channels + +type + BackendMessage* = object + field*: seq[int] + +const MESSAGE_COUNT = 100 + +var + chan1 = newChan[BackendMessage](MESSAGE_COUNT*2) + chan2 = newChan[BackendMessage](MESSAGE_COUNT*2) + +#chan1.open() +#chan2.open() + +proc routeMessage*(msg: BackendMessage) = + var m = isolate(msg) + discard chan2.trySend(m) + +var + thr: Thread[void] + stopToken: Atomic[bool] + +proc recvMsg() = + while not stopToken.load(moRelaxed): + var resp: BackendMessage + if chan1.tryRecv(resp): + #if resp.dataAvailable: + routeMessage(resp) + echo "child consumes ", formatSize getOccupiedMem() + +createThread[void](thr, recvMsg) + +proc main() = + let msg: BackendMessage = BackendMessage(field: (0..5).toSeq()) + for j in 0..100: + echo "New iteration" + + for _ in 1..MESSAGE_COUNT: + chan1.send(msg) + echo "After sending" + + var counter = 0 + while counter < MESSAGE_COUNT: + let resp = recv(chan2) + counter.inc + echo "After receiving ", formatSize getOccupiedMem() + + stopToken.store true, moRelaxed + joinThreads(thr) + +main() diff --git a/tests/arc/t22218.nim b/tests/arc/t22218.nim new file mode 100644 index 000000000..7837ed1d0 --- /dev/null +++ b/tests/arc/t22218.nim @@ -0,0 +1,25 @@ +discard """ + cmd: "nim c --mm:arc $file" + errormsg: "'=copy' is not available for type <Obj>; requires a copy because it's not the last read of 'chan[]'; routine: test" +""" + +# bug #22218 +type Obj[T] = object + v: T + +proc `=copy`[T]( + dest: var Obj[T], + source: Obj[T] + ) {.error: "A channel cannot be copied".} + +from system/ansi_c import c_calloc + +proc test() = + var v: bool = true + var chan = cast[ptr Obj[int]](c_calloc(1, csize_t sizeof(Obj[int]))) + var copy = chan[] + + echo chan.v + echo v + +test() \ No newline at end of file diff --git a/tests/arc/t23247.nim b/tests/arc/t23247.nim new file mode 100644 index 000000000..0fadc50cd --- /dev/null +++ b/tests/arc/t23247.nim @@ -0,0 +1,52 @@ +discard """ + matrix: ";-d:useMalloc" +""" + +# bug #23247 +import std/hashes + +func baseAddr[T](x: openArray[T]): ptr T = + # Return the address of the zero:th element of x or `nil` if x is empty + if x.len == 0: nil else: cast[ptr T](x) + +func makeUncheckedArray[T](p: ptr T): ptr UncheckedArray[T] = + cast[ptr UncheckedArray[T]](p) + +type + LabelKey = object + data: seq[string] + refs: ptr UncheckedArray[string] + refslen: int + + Gauge = ref object + metrics: seq[seq[seq[string]]] + +template values(key: LabelKey): openArray[string] = + if key.refslen > 0: + key.refs.toOpenArray(0, key.refslen - 1) + else: + key.data + +proc hash(key: LabelKey): Hash = + hash(key.values) + +proc view(T: type LabelKey, values: openArray[string]): T = + # TODO some day, we might get view types - until then.. + LabelKey(refs: baseAddr(values).makeUncheckedArray(), refslen: values.len()) + +template withValue2(k: untyped) = + discard hash(k) + +proc setGauge( + collector: Gauge, + labelValues: openArray[string], +) = + let v = LabelKey.view(labelValues) + withValue2(v) + collector.metrics.add @[@labelValues, @labelValues] + discard @labelValues + +var nim_gc_mem_bytes = Gauge() +let threadID = $getThreadId() +setGauge(nim_gc_mem_bytes, @[threadID]) +setGauge(nim_gc_mem_bytes, @[threadID]) \ No newline at end of file diff --git a/tests/arc/tarc_macro.nim b/tests/arc/tarc_macro.nim index ea7d279fd..33ade1da4 100644 --- a/tests/arc/tarc_macro.nim +++ b/tests/arc/tarc_macro.nim @@ -43,4 +43,15 @@ macro bar2() = doAssert &%&%y == 1 # unary operator => need to escape doAssert y &% y == 2 # binary operator => no need to escape doAssert y == 3 -bar2() \ No newline at end of file +bar2() + +block: + macro foo(a: openArray[string] = []): string = + echo a # Segfault doesn't happen if this is removed + newLit "" + + proc bar(a: static[openArray[string]] = []) = + const tmp = foo(a) + + # bug #22909 + doAssert not compiles(bar()) diff --git a/tests/arc/tarc_orc.nim b/tests/arc/tarc_orc.nim index 594950d71..f2c7de2fc 100644 --- a/tests/arc/tarc_orc.nim +++ b/tests/arc/tarc_orc.nim @@ -136,4 +136,51 @@ proc main2 = doAssert a.len == 2 doAssert b.len == 0 -main2() \ No newline at end of file +main2() + +block: + type + TestObj = object of RootObj + name: string + + TestSubObj = object of TestObj + objname: string + + proc `=destroy`(x: TestObj) = + `=destroy`(x.name) + + proc `=destroy`(x: TestSubObj) = + `=destroy`(x.objname) + `=destroy`(TestObj(x)) + + proc testCase() = + let t1 {.used.} = TestSubObj(objname: "tso1", name: "to1") + + proc main() = + testCase() + + main() + +block: # bug #23858 + type Object = object + a: int + b: ref int + var x = 0 + proc fn(): auto {.cdecl.} = + inc x + return Object() + discard fn() + doAssert x == 1 + +block: # bug #24147 + type + O = object of RootObj + val: string + OO = object of O + + proc `=copy`(dest: var O, src: O) = + dest.val = src.val + + let oo = OO(val: "hello world") + var ooCopy : OO + `=copy`(ooCopy, oo) diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim index 3b60fcd02..b4476ef4f 100644 --- a/tests/arc/tarcmisc.nim +++ b/tests/arc/tarcmisc.nim @@ -1,5 +1,6 @@ discard """ output: ''' +Destructor for TestTestObj =destroy called 123xyzabc destroyed: false @@ -31,14 +32,39 @@ true copying 123 42 +@["", "d", ""] ok destroying variable: 20 destroying variable: 10 closed ''' - cmd: "nim c --gc:arc --deepcopy:on -d:nimAllocPagesViaMalloc $file" + cmd: "nim c --mm:arc --deepcopy:on -d:nimAllocPagesViaMalloc $file" """ +block: # bug #23627 + type + TestObj = object of RootObj + + Test2 = object of RootObj + foo: TestObj + + TestTestObj = object of RootObj + shit: TestObj + + proc `=destroy`(x: TestTestObj) = + echo "Destructor for TestTestObj" + let test = Test2(foo: TestObj()) + + proc testCaseT() = + let tt1 {.used.} = TestTestObj(shit: TestObj()) + + + proc main() = + testCaseT() + + main() + + # bug #9401 type @@ -46,13 +72,12 @@ type len: int data: ptr UncheckedArray[float] -proc `=destroy`*(m: var MyObj) = +proc `=destroy`*(m: MyObj) = echo "=destroy called" if m.data != nil: deallocShared(m.data) - m.data = nil type MyObjDistinct = distinct MyObj @@ -104,7 +129,7 @@ bbb("123") type Variable = ref object value: int -proc `=destroy`(self: var typeof(Variable()[])) = +proc `=destroy`(self: typeof(Variable()[])) = echo "destroying variable: ",self.value proc newVariable(value: int): Variable = @@ -158,7 +183,7 @@ type B = ref object of A x: int -proc `=destroy`(x: var AObj) = +proc `=destroy`(x: AObj) = close(x.io) echo "closed" @@ -688,3 +713,124 @@ block: # bug #22259 f(wrapper) main() + +block: + block: # bug #22923 + block: + let + a: int = 100 + b: int32 = 200'i32 + + let + x = arrayWith(a, 8) # compiles + y = arrayWith(b, 8) # internal error + z = arrayWith(14, 8) # integer literal also results in a crash + + doAssert x == [100, 100, 100, 100, 100, 100, 100, 100] + doAssert $y == "[200, 200, 200, 200, 200, 200, 200, 200]" + doAssert z == [14, 14, 14, 14, 14, 14, 14, 14] + + block: + let a: string = "nim" + doAssert arrayWith(a, 3) == ["nim", "nim", "nim"] + + let b: char = 'c' + doAssert arrayWith(b, 3) == ['c', 'c', 'c'] + + let c: uint = 300'u + doAssert $arrayWith(c, 3) == "[300, 300, 300]" + +block: # bug #23505 + type + K = object + C = object + value: ptr K + + proc init(T: type C): C = + let tmp = new K + C(value: addr tmp[]) + + discard init(C) + +block: # bug #23524 + type MyType = object + a: int + + proc `=destroy`(typ: MyType) = discard + + var t1 = MyType(a: 100) + var t2 = t1 # Should be a copy? + + proc main() = + t2 = t1 + doAssert t1.a == 100 + doAssert t2.a == 100 + + main() + +block: # bug #23907 + type + Thingy = object + value: int + + ExecProc[C] = proc(value: sink C): int {.nimcall.} + + proc `=copy`(a: var Thingy, b: Thingy) {.error.} + + var thingyDestroyCount = 0 + + proc `=destroy`(thingy: Thingy) = + assert(thingyDestroyCount <= 0) + thingyDestroyCount += 1 + + proc store(value: sink Thingy): int = + result = value.value + + let callback: ExecProc[Thingy] = store + + doAssert callback(Thingy(value: 123)) == 123 + +import std/strutils + +block: # bug #23974 + func g(e: seq[string]): lent seq[string] = result = e + proc k(f: string): seq[string] = f.split("/") + proc n() = + const r = "/d/" + let t = + if true: + k(r).g() + else: + k("/" & r).g() + echo t + + n() + +block: # bug #23973 + func g(e: seq[string]): lent seq[string] = result = e + proc k(f: string): seq[string] = f.split("/") + proc n() = + const r = "/test/empty" # or "/test/empty/1" + let a = k(r).g() + let t = + if true: + k(r).g() + else: + k("/" & r).g() # or raiseAssert "" + doAssert t == a + + n() + +block: # bug #24141 + func reverse(s: var openArray[char]) = + s[0] = 'f' + + func rev(s: var string) = + s.reverse + + proc main = + var abc = "abc" + abc.rev + doAssert abc == "fbc" + + main() diff --git a/tests/arc/tcaseobj.nim b/tests/arc/tcaseobj.nim index be1d722ed..3499f5c1e 100644 --- a/tests/arc/tcaseobj.nim +++ b/tests/arc/tcaseobj.nim @@ -338,3 +338,29 @@ block: doAssert ff.s == 12 mainSync() + +import std/sequtils + +# bug #23690 +type + SomeObj* = object of RootObj + + Item* = object + case kind*: 0..1 + of 0: + a*: int + b*: SomeObj + of 1: + c*: string + + ItemExt* = object + a*: Item + b*: string + +proc do1(x: int): seq[(string, Item)] = + result = @[("zero", Item(kind: 1, c: "first"))] + +proc do2(x: int, e: ItemExt): seq[(string, ItemExt)] = + do1(x).map(proc(v: (string, Item)): auto = (v[0], ItemExt(a: v[1], b: e.b))) + +doAssert $do2(0, ItemExt(a: Item(kind: 1, c: "second"), b: "third")) == """@[("zero", (a: (kind: 1, c: "first"), b: "third"))]""" diff --git a/tests/arc/titeration_doesnt_copy.nim b/tests/arc/titeration_doesnt_copy.nim index e1cdb6166..e510a6eff 100644 --- a/tests/arc/titeration_doesnt_copy.nim +++ b/tests/arc/titeration_doesnt_copy.nim @@ -54,3 +54,14 @@ proc toBinString*(data: openArray[uint8], col: int): string = doAssert @[0b0000_1111'u8, 0b1010_1010].toBinString(8) == "0000111110101010" doAssert @[0b1000_0000'u8, 0b0000_0000].toBinString(1) == "10" + +block: # bug #23982 + iterator `..`(a, b: ptr int16): ptr int16 = discard + var a: seq[int16] #; let p = a[0].addr + var b: seq[ptr int16] + + try: + for x in a[0].addr .. b[1]: # `p .. b[1]` works + discard + except IndexDefect: + discard diff --git a/tests/arc/topenarray.nim b/tests/arc/topenarray.nim index 67c512e4f..ba91666ba 100644 --- a/tests/arc/topenarray.nim +++ b/tests/arc/topenarray.nim @@ -68,3 +68,19 @@ block: doAssert foo(noBugConst) == expected let noBugSeq = @["0", "c", "a"] doAssert foo(noBugSeq) == expected + +block: # bug #20865 + var p: pointer + var x: array[0, int] + # echo toOpenArray(x, 0, 1)[0] # Raises IndexDefect + doAssertRaises(IndexDefect): + echo toOpenArray(cast[ptr array[0, int]](p)[], 0, 1)[0] # Does not raise IndexDefect + +block: # bug #20987 + var v: array[1, byte] + + var p = cast[ptr array[0, byte]](addr v) + + doAssertRaises(IndexDefect): + echo toOpenArray(p[], 1, 2) + diff --git a/tests/arc/tstringliteral.nim b/tests/arc/tstringliteral.nim new file mode 100644 index 000000000..c5fac22d8 --- /dev/null +++ b/tests/arc/tstringliteral.nim @@ -0,0 +1,17 @@ +discard """ + matrix: "--mm:arc; --mm:orc" +""" + +block: # issue #24080 + var a = (s: "a") + var b = "a" + a.s.setLen 0 + b = a.s + doAssert b == "" + +block: # issue #24080, longer string + var a = (s: "abc") + var b = "abc" + a.s.setLen 2 + b = a.s + doAssert b == "ab" diff --git a/tests/array/tlargeindex.nim b/tests/array/tlargeindex.nim new file mode 100644 index 000000000..61bcbd61d --- /dev/null +++ b/tests/array/tlargeindex.nim @@ -0,0 +1,18 @@ +discard """ + cmd: "nim check --hints:off $file" +""" + +# issue #17163 +var e: array[int32, byte] #[tt.Error + ^ index type 'int32' for array is too large]# +var f: array[uint32, byte] #[tt.Error + ^ index type 'uint32' for array is too large]# +var g: array[int64, byte] #[tt.Error + ^ index type 'int64' for array is too large]# +var h: array[uint64, byte] #[tt.Error + ^ index type 'uint64' for array is too large]# + +# crash in issue #23204 +proc y[N](): array[N, int] = default(array[N, int]) #[tt.Error + ^ index type 'int' for array is too large]# +discard y[int]() diff --git a/tests/async/tioselectors.nim b/tests/async/tioselectors.nim index 77d03f8f6..f53767408 100644 --- a/tests/async/tioselectors.nim +++ b/tests/async/tioselectors.nim @@ -58,7 +58,11 @@ when not defined(windows): registerHandle(selector, client_socket, {Event.Write}, 0) freeAddrInfo(aiList) - discard selector.select(100) + + # make sure both sockets are selected + var nevs = 0 + while nevs < 2: + nevs += selector.select(100).len var sockAddress: SockAddr var addrLen = sizeof(sockAddress).Socklen @@ -427,6 +431,20 @@ when not defined(windows): doAssert(res[0].fd == dirfd and {Event.Vnode, Event.VnodeDelete} <= res[0].events) + proc pipe_test(): bool = + # closing the read end of a pipe will result in it automatically + # being removed from the kqueue; make sure no exception is raised + var s = newSelector[int]() + var fds: array[2, cint] + discard pipe(fds) + s.registerHandle(fds[1], {Write}, 0) + discard close(fds[0]) + let res = s.select(-1) + doAssert(res.len == 1) + s.unregister(fds[1]) + discard close(fds[1]) + return true + when hasThreadSupport: var counter = 0 @@ -468,6 +486,7 @@ when not defined(windows): when defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd): processTest("File notification test...", vnode_test()) + processTest("Pipe test...", pipe_test()) echo("All tests passed!") else: import nativesockets, winlean, os, osproc diff --git a/tests/c/temit.nim b/tests/c/temit.nim index ee7455d4c..1943c94ea 100644 --- a/tests/c/temit.nim +++ b/tests/c/temit.nim @@ -4,6 +4,7 @@ discard """ # Test the new ``emit`` pragma: {.emit: """ +#include <stdio.h> static int cvariable = 420; """.} diff --git a/tests/casestmt/tcase_issues.nim b/tests/casestmt/tcase_issues.nim new file mode 100644 index 000000000..20a79df2c --- /dev/null +++ b/tests/casestmt/tcase_issues.nim @@ -0,0 +1,7 @@ +discard """ + targets: "c js" +""" + +block: # bug #24031 + case 0 + else: discard \ No newline at end of file diff --git a/tests/casestmt/tcasestmt.nim b/tests/casestmt/tcasestmt.nim index aea0c96a4..66de4183d 100644 --- a/tests/casestmt/tcasestmt.nim +++ b/tests/casestmt/tcasestmt.nim @@ -41,6 +41,11 @@ block t8333: case 0 of 'a': echo 0 else: echo 1 +block: # issue #11422 + var c: int = 5 + case c + of 'a' .. 'c': discard + else: discard block emptyset_when: diff --git a/tests/casestmt/trangeexhaustiveness.nim b/tests/casestmt/trangeexhaustiveness.nim new file mode 100644 index 000000000..2b7f3558e --- /dev/null +++ b/tests/casestmt/trangeexhaustiveness.nim @@ -0,0 +1,7 @@ +block: # issue #22661 + template foo(a: typed) = + a + + foo: + case false + of false..true: discard diff --git a/tests/ccgbugs/t10964.nim b/tests/ccgbugs/t10964.nim index a331b16cd..c19db6997 100644 --- a/tests/ccgbugs/t10964.nim +++ b/tests/ccgbugs/t10964.nim @@ -3,4 +3,5 @@ func test*(input: var openArray[int32], start: int = 0, fin: int = input.len - 1 var someSeq = @[1'i32] -test(someSeq) \ No newline at end of file +test(someSeq) +# bug with gcc 14 \ No newline at end of file diff --git a/tests/ccgbugs/t13062.nim b/tests/ccgbugs/t13062.nim index a8d2c1fec..cfda1da7c 100644 --- a/tests/ccgbugs/t13062.nim +++ b/tests/ccgbugs/t13062.nim @@ -24,7 +24,10 @@ type fulfilled: Atomic[bool] var x: Pledge -when defined(gcRefc): +when defined(cpp): + # TODO: fixme + discard "it doesn't work for refc/orc because of contrived `Atomic` in cpp" +elif defined(gcRefc): doAssert x.repr == "[p = nil]" -elif not defined(cpp): # fixme # bug #20081 +else: # fixme # bug #20081 doAssert x.repr == "Pledge(p: nil)" diff --git a/tests/ccgbugs/t20141.nim b/tests/ccgbugs/t20141.nim index 499cd21aa..60e130690 100644 --- a/tests/ccgbugs/t20141.nim +++ b/tests/ccgbugs/t20141.nim @@ -16,7 +16,7 @@ template n[T, U](x: U): T = proc k() = var res: A - m(n[B](res)) + m(n[B, A](res)) proc w(mounter: U) = discard @@ -24,4 +24,4 @@ proc mount(proto: U) = discard proc v() = mount k # This is required for failure -w(v) \ No newline at end of file +w(v) diff --git a/tests/ccgbugs/t22462.nim b/tests/ccgbugs/t22462.nim new file mode 100644 index 000000000..9adfbb19b --- /dev/null +++ b/tests/ccgbugs/t22462.nim @@ -0,0 +1,20 @@ +discard """ + action: "run" + output: ''' +1 +1 +1 +''' + matrix: "--mm:refc" + targets: "c cpp" +""" + +type Object = object + someComplexType: seq[int] + index: Natural + +func newObject(): Object = result.index.inc + +for i in 1..3: + let o = newObject() + echo o.index diff --git a/tests/ccgbugs/t23796.nim b/tests/ccgbugs/t23796.nim new file mode 100644 index 000000000..421ec04d8 --- /dev/null +++ b/tests/ccgbugs/t23796.nim @@ -0,0 +1,25 @@ +discard """ + targets: "c cpp" +""" + +# bug #23796 + +{.emit: """ +#ifdef __cplusplus +extern "C" { +#endif + +void fooArr(float data[3]) {} +void fooIntArr(int id, float data[3]) {} + +#ifdef __cplusplus +} +#endif +""".} + +proc fooArr(data: var array[3, cfloat]) {.importc.} +proc fooIntArr(id: cint, data: var array[3, cfloat]) {.importc, nodecl.} + +var arr = [cfloat 1, 2, 3] +fooArr(arr) +fooIntArr(1, arr) diff --git a/tests/ccgbugs/tcgbug.nim b/tests/ccgbugs/tcgbug.nim index 14ed390d4..2eddc6fdd 100644 --- a/tests/ccgbugs/tcgbug.nim +++ b/tests/ccgbugs/tcgbug.nim @@ -4,6 +4,7 @@ success M1 M2 ok ''' +matrix: "--mm:refc;--mm:orc" """ type @@ -123,3 +124,40 @@ proc bug19613 = doAssert x.bid.root.data[0] == 42 bug19613() + +proc foo = # bug #23280 + let foo = @[1,2,3,4,5,6] + doAssert toOpenArray(foo, 0, 5).len == 6 + doAssert toOpenArray(foo, 0, 5).len mod 6 == 0 # this should output 0 + doAssert toOpenArray(foo, 0, 5).max mod 6 == 0 + let L = toOpenArray(foo, 0, 5).len + doAssert L mod 6 == 0 + +foo() + +block: # bug #9940 + {.emit:"""/*TYPESECTION*/ +typedef struct { int base; } S; +""".} + + type S {.importc: "S", completeStruct.} = object + base: cint + proc init(x:ptr S) = + x.base = 1 + + type + Foo = object + a: seq[float] + b: seq[float] + c: seq[float] + d: seq[float] + s: S + + proc newT(): Foo = + var t: Foo + t.s.addr.init + doAssert t.s.base == 1 + t + + var t = newT() + doAssert t.s.base == 1 diff --git a/tests/ccgbugs/tsamename3.nim b/tests/ccgbugs/tsamename3.nim index a69391e5c..ded18e9f8 100644 --- a/tests/ccgbugs/tsamename3.nim +++ b/tests/ccgbugs/tsamename3.nim @@ -109,3 +109,12 @@ block: # make sure `hashType` doesn't recurse infinitely a, b: PFoo c: int var a: PFoo + +block: # issue #22571 + macro foo(x: typed) = + result = x + + block: # or `proc main =` + foo: + type Foo = object + doAssert $Foo() == "()" diff --git a/tests/closure/t8550.nim b/tests/closure/t8550.nim index 153246f08..a07f45cdc 100644 --- a/tests/closure/t8550.nim +++ b/tests/closure/t8550.nim @@ -1,4 +1,5 @@ discard """ + targets: "c js" output: "@[\"42\"]" """ diff --git a/tests/closure/tnested.nim b/tests/closure/tnested.nim index 31963ea86..ec5af9b13 100644 --- a/tests/closure/tnested.nim +++ b/tests/closure/tnested.nim @@ -1,4 +1,5 @@ discard """ +targets: "c js" output: ''' foo88 23 24foo 88 @@ -183,14 +184,32 @@ block tclosure2: import typetraits -proc myDiscard[T](a: T) = discard +block: + proc myDiscard[T](a: T) = discard -proc foo() = - let a = 5 - let f = (proc() = - myDiscard (proc() = echo a) - ) - echo name(typeof(f)) + proc foo() = + let a = 5 + let f = (proc() = + myDiscard (proc() = echo a) + ) + echo name(typeof(f)) -foo() + foo() + +block: + iterator foo: int {.closure.} = + yield 1 + yield 2 + yield 3 + + proc pork = + let call = foo + for i in call(): + discard i + + let call2 = foo + while not finished(call2): + discard call2() + + pork() diff --git a/tests/codegen/titaniummangle.nim b/tests/codegen/titaniummangle.nim new file mode 100644 index 000000000..4b45e59ae --- /dev/null +++ b/tests/codegen/titaniummangle.nim @@ -0,0 +1,193 @@ +discard """ + targets: "c" + matrix: "--debugger:native" + ccodecheck: "'_ZN14titaniummangle8testFuncE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE6stringN14titaniummangle3FooE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE3int7varargsI6stringE'" + ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle3BooE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE8typeDescIN14titaniummangle17EnumAnotherSampleEE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE3ptrI14uncheckedArrayI3intEE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE3setIN14titaniummangle10EnumSampleEE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE4procI6string6stringE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE3intN10Comparable10ComparableE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE3int3int'" + ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle10EnumSampleE'" + ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle17EnumAnotherSampleE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE3int3int'" + ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle10EnumSampleE'" + ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle17EnumAnotherSampleE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE5tupleI3int3intE7cstring'" + ccodecheck: "'_ZN14titaniummangle8testFuncE5tupleI5float5floatE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE3ptrI3intE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE3ptrIN14titaniummangle3FooEE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE3ptrI3ptrI3intEE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE3refIN14titaniummangle3FooEE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE3varIN14titaniummangle3FooEE5int325int323refIN14titaniummangle3FooEE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE3varI3intE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE9openArrayI6stringE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE5arrayI7range013intE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE9ContainerI3intE'" + ccodecheck: "'_ZN14titaniummangle8testFuncE10Container2I5int325int32E'" + ccodecheck: "'_ZN14titaniummangle8testFuncE9ContainerI10Container2I5int325int32EE'" +""" + +#When debugging this notice that if one check fails, it can be due to any of the above. + +type + Comparable = concept x, y + (x < y) is bool + + Foo = object + a: int32 + b: int32 + + FooTuple = tuple + a: int + b: int + + Container[T] = object + data: T + + Container2[T, T2] = object + data: T + data2: T2 + + Boo = distinct Foo + + Coo = Foo + + Doo = Boo | Foo + + TestProc = proc(a:string): string + +type EnumSample = enum + a, b, c + +type EnumAnotherSample = enum + a, b, c + +proc testFunc(a: set[EnumSample]) = + echo $a + +proc testFunc(a: typedesc) = + echo $a + +proc testFunc(a: ptr Foo) = + echo repr a + +proc testFunc(s: string, a: Coo) = + echo repr a + +proc testFunc(s: int, a: Comparable) = + echo repr a + +proc testFunc(a: TestProc) = + let b = "" + echo repr a("") + +proc testFunc(a: ref Foo) = + echo repr a + +proc testFunc(b: Boo) = + echo repr b + +proc testFunc(a: ptr UncheckedArray[int]) = + echo repr a + +proc testFunc(a: ptr int) = + echo repr a + +proc testFunc(a: ptr ptr int) = + echo repr a + +proc testFunc(e: FooTuple, str: cstring) = + echo e + +proc testFunc(e: (float, float)) = + echo e + +proc testFunc(e: EnumSample) = + echo e + +proc testFunc(e: var int) = + echo e + +proc testFunc(e: var Foo, a, b: int32, refFoo: ref Foo) = + echo e + +proc testFunc(xs: Container[int]) = + let a = 2 + echo xs + +proc testFunc(xs: Container2[int32, int32]) = + let a = 2 + echo xs + +proc testFunc(xs: Container[Container2[int32, int32]]) = + let a = 2 + echo xs + +proc testFunc(xs: seq[int]) = + let a = 2 + echo xs + +proc testFunc(xs: openArray[string]) = + let a = 2 + echo xs + +proc testFunc(xs: array[2, int]) = + let a = 2 + echo xs + +proc testFunc(e: EnumAnotherSample) = + echo e + +proc testFunc(a, b: int) = + echo "hola" + discard + +proc testFunc(a: int, xs: varargs[string]) = + let a = 10 + for x in xs: + echo x + +proc testFunc() = + var a = 2 + var aPtr = a.addr + var foo = Foo() + let refFoo : ref Foo = new(Foo) + let b = Foo().Boo() + let d: Doo = Foo() + testFunc("", Coo()) + testFunc(1, ) + testFunc(b) + testFunc(EnumAnotherSample) + var t = [1, 2] + let uArr = cast[ptr UncheckedArray[int]](t.addr) + testFunc(uArr) + testFunc({}) + testFunc(proc(s:string): string = "test") + testFunc(20, a.int32) + testFunc(20, 2) + testFunc(EnumSample.c) + testFunc(EnumAnotherSample.c) + testFunc((2, 1), "adios") + testFunc((22.1, 1.2)) + testFunc(a.addr) + testFunc(foo.addr) + testFunc(aPtr.addr) + testFunc(refFoo) + testFunc(foo, 2, 1, refFoo) + testFunc(a) + testFunc(@[2, 1, 2]) + testFunc(@["hola"]) + testFunc(2, "hola", "adios") + let arr: array[2, int] = [2, 1] + testFunc(arr) + testFunc(Container[int](data: 10)) + let c2 = Container2[int32, int32](data: 10, data2: 20) + testFunc(c2) + testFunc(Container[Container2[int32, int32]](data: c2)) + + +testFunc() \ No newline at end of file diff --git a/tests/compileoption/texperimental.nim b/tests/compileoption/texperimental.nim new file mode 100644 index 000000000..be637e58a --- /dev/null +++ b/tests/compileoption/texperimental.nim @@ -0,0 +1,20 @@ +static: + doAssert compileOption("experimental", "dotOperators") + doAssert compileOption("experimental", "callOperator") + doAssert compileOption("experimental", "parallel") + doAssert compileOption("experimental", "destructor") + doAssert compileOption("experimental", "notnil") + doAssert compileOption("experimental", "dynamicBindSym") + doAssert compileOption("experimental", "codeReordering") + doAssert compileOption("experimental", "compiletimeFFI") + doAssert compileOption("experimental", "vmopsDanger") + doAssert compileOption("experimental", "strictFuncs") + doAssert compileOption("experimental", "views") + doAssert compileOption("experimental", "strictNotNil") + doAssert compileOption("experimental", "strictEffects") + doAssert compileOption("experimental", "flexibleOptionalParams") + doAssert compileOption("experimental", "strictDefs") + doAssert compileOption("experimental", "strictCaseObjects") + doAssert compileOption("experimental", "inferGenericTypes") + doAssert compileOption("experimental", "openSym") + doAssert compileOption("experimental", "vtables") diff --git a/tests/compileoption/texperimental.nims b/tests/compileoption/texperimental.nims new file mode 100644 index 000000000..c2c357caa --- /dev/null +++ b/tests/compileoption/texperimental.nims @@ -0,0 +1,19 @@ +switch("experimental", "dotOperators") +switch("experimental", "callOperator") +switch("experimental", "parallel") +switch("experimental", "destructor") +switch("experimental", "notnil") +switch("experimental", "dynamicBindSym") +switch("experimental", "codeReordering") +switch("experimental", "compiletimeFFI") +switch("experimental", "vmopsDanger") +switch("experimental", "strictFuncs") +switch("experimental", "views") +switch("experimental", "strictNotNil") +switch("experimental", "strictEffects") +switch("experimental", "flexibleOptionalParams") +switch("experimental", "strictDefs") +switch("experimental", "strictCaseObjects") +switch("experimental", "inferGenericTypes") +switch("experimental", "openSym") +switch("experimental", "vtables") diff --git a/tests/concepts/t976.nim b/tests/concepts/t976.nim new file mode 100644 index 000000000..776d53827 --- /dev/null +++ b/tests/concepts/t976.nim @@ -0,0 +1,57 @@ +discard """ + output: ''' +Printable +''' +joinable: false +""" + +#[ + The converter is a proper example of a confounding variable + Moved to an isolated file +]# + +type + Obj1[T] = object + v: T +converter toObj1[T](t: T): Obj1[T] = + return Obj1[T](v: t) +block t976: + type + int1 = distinct int + int2 = distinct int + int1g = concept x + x is int1 + int2g = concept x + x is int2 + + proc take[T: int1g](value: int1) = + when T is int2: + static: error("killed in take(int1)") + + proc take[T: int2g](vale: int2) = + when T is int1: + static: error("killed in take(int2)") + + var i1: int1 = 1.int1 + var i2: int2 = 2.int2 + + take[int1](i1) + take[int2](i2) + + template reject(e) = + static: assert(not compiles(e)) + + reject take[string](i2) + reject take[int1](i2) + + # bug #6249 + type + Obj2 = ref object + PrintAble = concept x + $x is string + + proc `$`[T](nt: Obj1[T]): string = + when T is PrintAble: result = "Printable" + else: result = "Non Printable" + + echo Obj2() \ No newline at end of file diff --git a/tests/concepts/tconcepts_issues.nim b/tests/concepts/tconcepts_issues.nim index 83f3085c3..c6d0267c5 100644 --- a/tests/concepts/tconcepts_issues.nim +++ b/tests/concepts/tconcepts_issues.nim @@ -1,7 +1,6 @@ discard """ output: ''' 20.0 USD -Printable true true true @@ -78,55 +77,6 @@ block t3414: let s2 = s1.find(10) - -type - Obj1[T] = object - v: T -converter toObj1[T](t: T): Obj1[T] = - return Obj1[T](v: t) -block t976: - type - int1 = distinct int - int2 = distinct int - int1g = concept x - x is int1 - int2g = concept x - x is int2 - - proc take[T: int1g](value: int1) = - when T is int2: - static: error("killed in take(int1)") - - proc take[T: int2g](vale: int2) = - when T is int1: - static: error("killed in take(int2)") - - var i1: int1 = 1.int1 - var i2: int2 = 2.int2 - - take[int1](i1) - take[int2](i2) - - template reject(e) = - static: assert(not compiles(e)) - - reject take[string](i2) - reject take[int1](i2) - - # bug #6249 - type - Obj2 = ref object - PrintAble = concept x - $x is string - - proc `$`[T](nt: Obj1[T]): string = - when T is PrintAble: result = "Printable" - else: result = "Non Printable" - - echo Obj2() - - - block t1128: type TFooContainer[T] = object @@ -560,7 +510,7 @@ proc depthOf*[V](orderType: typedesc[BreadthOrder], tree: AnyTree[V], root, goal if root == goal: return 0 var order = init[LevelNode[V]](orderType) - order.expand(tree, root, (leaf) => (1, leaf)) + order.expand(tree, root, (leaf) => (1.uint, leaf)) while order.hasNext(): let depthNode: LevelNode[V] = order.popNext() if depthNode.node == goal: @@ -580,3 +530,27 @@ block: # bug #12852 var tree = CappedStringTree(symbols: "^v><", cap: 5) doAssert BreadthOrder.depthOf(tree, "", ">>>") == 3 + +block: #bug #22723 + type + Node = concept n, type T + for i in n.children: + i is T + n.parent is T + + Nd = ref object + parent: Nd + children: seq[Nd] + + proc addChild(parent, child: Node) = + parent.children.add(child) + child.parent = parent + + proc foo = + var + a = Nd() + b = Nd() + a.addChild(b) + doAssert a.children.len == 1 + + foo() diff --git a/tests/concepts/tusertypeclasses2.nim b/tests/concepts/tusertypeclasses2.nim index c9978f6ef..6132bc2d8 100644 --- a/tests/concepts/tusertypeclasses2.nim +++ b/tests/concepts/tusertypeclasses2.nim @@ -1,3 +1,7 @@ +discard """ + targets: "c js" +""" + block: type hasFieldX = concept z @@ -42,3 +46,18 @@ block: foo2(x) foo3(x) foo4(x) + +block: # bug #9550 + block: + type Foo = concept c + for v in c: (v is char) + + func foo(c: Foo) = (for v in c: discard) + foo @['a', 'b' ,'c'] + + block: + type Foo = concept c + for v in c: (v is char) + + func foo(c: Foo) = (for v in c: discard) + foo ['a', 'b' ,'c'] diff --git a/tests/config.nims b/tests/config.nims index 690123c4a..0b2b66d81 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -43,5 +43,7 @@ switch("define", "nimPreviewRangeDefault") switch("define", "nimPreviewNonVarDestructor") switch("warningAserror", "UnnamedBreak") -switch("legacy", "verboseTypeMismatch") +when not defined(testsConciseTypeMismatch): + switch("legacy", "verboseTypeMismatch") switch("experimental", "vtables") +switch("experimental", "openSym") diff --git a/tests/controlflow/tunreachable2.nim b/tests/controlflow/tunreachable2.nim new file mode 100644 index 000000000..a658880f0 --- /dev/null +++ b/tests/controlflow/tunreachable2.nim @@ -0,0 +1,12 @@ +discard """ + matrix: "--warningAsError:UnreachableCode" +""" + +proc test(): bool = + block okay: + if true: break okay + return false + + return true # Line 7 is here + +doAssert test() diff --git a/tests/cpp/23962.h b/tests/cpp/23962.h new file mode 100644 index 000000000..2d8147bfb --- /dev/null +++ b/tests/cpp/23962.h @@ -0,0 +1,17 @@ +#include <iostream> + +struct Foo { + + Foo(int inX): x(inX) { + std::cout << "Ctor Foo(" << x << ")\n"; + } + ~Foo() { + std::cout << "Destory Foo(" << x << ")\n"; + } + + void print() { + std::cout << "Foo.x = " << x << '\n'; + } + + int x; +}; \ No newline at end of file diff --git a/tests/cpp/fam.h b/tests/cpp/fam.h new file mode 100644 index 000000000..ad576425b --- /dev/null +++ b/tests/cpp/fam.h @@ -0,0 +1,4 @@ +struct Test{ + ~Test() { + } +}; diff --git a/tests/cpp/t23306.nim b/tests/cpp/t23306.nim new file mode 100644 index 000000000..ebb4edb8d --- /dev/null +++ b/tests/cpp/t23306.nim @@ -0,0 +1,12 @@ +discard """ +targets: "cpp" +""" + +type K = object + h: iterator(f: K): K + +iterator d(g: K): K {.closure.} = + defer: + discard + +discard K(h: d) \ No newline at end of file diff --git a/tests/cpp/t23434.nim b/tests/cpp/t23434.nim new file mode 100644 index 000000000..04a83227e --- /dev/null +++ b/tests/cpp/t23434.nim @@ -0,0 +1,17 @@ +discard """ +cmd:"nim cpp $file" +errormsg: "type mismatch: got <proc (self: SomeObject){.member, gcsafe.}>" +line: 17 +""" +type SomeObject = object + value: int + +proc printValue(self: SomeObject) {.virtual.} = + echo "The value is ", self.value + +proc callAProc(p: proc(self: SomeObject){.noconv.}) = + let someObj = SomeObject(value: 4) + echo "calling param proc" + p(someObj) + +callAProc(printValue) \ No newline at end of file diff --git a/tests/cpp/t23657.nim b/tests/cpp/t23657.nim new file mode 100644 index 000000000..63deb7fb0 --- /dev/null +++ b/tests/cpp/t23657.nim @@ -0,0 +1,54 @@ +discard """ + targets: "cpp" + cmd: "nim cpp -r $file" + output: ''' +1.0 +1.0 +''' + +""" +{.emit:"""/*TYPESECTION*/ +struct Point { + float x, y, z; + Point(float x, float y, float z): x(x), y(y), z(z) {} + Point() = default; +}; +struct Direction { + float x, y, z; + Direction(float x, float y, float z): x(x), y(y), z(z) {} + Direction() = default; +}; +struct Axis { + Point origin; + Direction direction; + Axis(Point origin, Direction direction): origin(origin), direction(direction) {} + Axis() = default; +}; + +""".} + +type + Point {.importcpp.} = object + x, y, z: float + + Direction {.importcpp.} = object + x, y, z: float + + Axis {.importcpp.} = object + origin: Point + direction: Direction + +proc makeAxis(origin: Point, direction: Direction): Axis {. constructor, importcpp:"Axis(@)".} +proc makePoint(x, y, z: float): Point {. constructor, importcpp:"Point(@)".} +proc makeDirection(x, y, z: float): Direction {. constructor, importcpp:"Direction(@)".} + +var axis1 = makeAxis(Point(x: 1.0, y: 2.0, z: 3.0), Direction(x: 4.0, y: 5.0, z: 6.0)) #Triggers the error (T1) +var axis2Ctor = makeAxis(makePoint(1.0, 2.0, 3.0), makeDirection(4.0, 5.0, 6.0)) #Do not triggers + +proc main() = #Do not triggers as Tx are inside the body + let test = makeAxis(Point(x: 1.0, y: 2.0, z: 3.0), Direction(x: 4.0, y: 5.0, z: 6.0)) + echo test.origin.x + +main() + +echo $axis1.origin.x #Make sures it's init \ No newline at end of file diff --git a/tests/cpp/t23962.nim b/tests/cpp/t23962.nim new file mode 100644 index 000000000..c79d888df --- /dev/null +++ b/tests/cpp/t23962.nim @@ -0,0 +1,32 @@ +discard """ + cmd: "nim cpp $file" + output: ''' +Ctor Foo(-1) +Destory Foo(-1) +Ctor Foo(-1) +Destory Foo(-1) +Ctor Foo(-1) +Destory Foo(-1) +Foo.x = 1 +Foo.x = 2 +Foo.x = -1 +''' +""" + +type + Foo {.importcpp, header: "23962.h".} = object + x: cint + +proc print(f: Foo) {.importcpp.} + +#also tests the right constructor is used +proc makeFoo(x: int32 = -1): Foo {.importcpp:"Foo(#)", constructor.} + +proc test = + var xs = newSeq[Foo](3) + xs[0].x = 1 + xs[1].x = 2 + for x in xs: + x.print + +test() \ No newline at end of file diff --git a/tests/cpp/tcasts.nim b/tests/cpp/tcasts.nim index d968d87db..80527efff 100644 --- a/tests/cpp/tcasts.nim +++ b/tests/cpp/tcasts.nim @@ -1,6 +1,5 @@ discard """ cmd: "nim cpp $file" - output: '''{"vas": "kas", "123": "123"}''' targets: "cpp" """ @@ -18,4 +17,4 @@ import tables var t = initTable[string, string]() discard t.hasKeyOrPut("123", "123") discard t.mgetOrPut("vas", "kas") -echo t \ No newline at end of file +doAssert t.len == 2 diff --git a/tests/cpp/tconstructor.nim b/tests/cpp/tconstructor.nim index ac73b78e6..922ee54fd 100644 --- a/tests/cpp/tconstructor.nim +++ b/tests/cpp/tconstructor.nim @@ -115,4 +115,17 @@ type Foo {.exportc.} = object proc makeFoo(): Foo {.used, constructor, nodecl.} = discard -echo $Foo() \ No newline at end of file +echo $Foo() + +type Boo = object +proc `=copy`(dest: var Boo; src: Boo) = discard + +proc makeBoo(): Boo {.constructor.} = Boo() +proc makeBoo2(): Boo = Boo() + +block: + proc main = + var b = makeBoo() + var b2 = makeBoo2() + + main() \ No newline at end of file diff --git a/tests/cpp/tfam.nim b/tests/cpp/tfam.nim new file mode 100644 index 000000000..6bd89fe24 --- /dev/null +++ b/tests/cpp/tfam.nim @@ -0,0 +1,7 @@ +discard """ + targets: "cpp" +""" +type + Test {.importcpp, header: "fam.h".} = object + +let test = newSeq[Test]() \ No newline at end of file diff --git a/tests/cpp/tmember.nim b/tests/cpp/tmember.nim index 07bd5e0ee..1a5b6fd97 100644 --- a/tests/cpp/tmember.nim +++ b/tests/cpp/tmember.nim @@ -8,6 +8,8 @@ hello foo hello boo hello boo FunctorSupport! +static +static destructing destructing ''' @@ -34,7 +36,7 @@ echo doo == Doo(test: 1) #virtual proc newCpp*[T](): ptr T {.importcpp:"new '*0()".} type - Foo = object of RootObj + Foo {.exportc.} = object of RootObj FooPtr = ptr Foo Boo = object of Foo BooPtr = ptr Boo @@ -62,3 +64,12 @@ proc invoke(f: NimFunctor, n:int) {.member:"operator ()('2 #2)" .} = {.experimental: "callOperator".} proc `()`(f: NimFunctor, n:int) {.importcpp:"#(@)" .} NimFunctor()(1) + +#static +proc staticProc(self: FooPtr) {.member: "static $1()".} = + echo "static" + +proc importedStaticProc() {.importcpp:"Foo::staticProc()".} + +foo.staticProc() +importedStaticProc() diff --git a/tests/cpp/tmember_forward_declaration.nim b/tests/cpp/tmember_forward_declaration.nim new file mode 100644 index 000000000..2f4a79daa --- /dev/null +++ b/tests/cpp/tmember_forward_declaration.nim @@ -0,0 +1,27 @@ +discard """ + targets: "cpp" + cmd: "nim cpp $file" + output: ''' +abc called +def called +abc called +''' +""" + +type Foo = object + +proc abc(this: Foo, x: int): void {.member: "$1('2 #2)".} +proc def(this: Foo, y: int): void {.virtual: "$1('2 #2)".} + +proc abc(this: Foo, x: int): void = + echo "abc called" + if x > 0: + this.def(x - 1) + +proc def(this: Foo, y: int): void = + echo "def called" + this.abc(y) + +var x = Foo() +x.abc(1) + diff --git a/tests/cpp/torc.nim b/tests/cpp/torc.nim index 64c6c0e5f..9f1a41a21 100644 --- a/tests/cpp/torc.nim +++ b/tests/cpp/torc.nim @@ -39,3 +39,37 @@ proc asVector*[T](t: T): EnumVector[T] = # N_NIMCALL(std::vector<> , asvector_106028_3197418230)(SomeEnum t0) discard asVector(SomeEnum.A) + + +block: # bug #10219 + type + Vector[T] {.importcpp: "std::vector", header: "vector".} = object + + proc initVector[T](n: csize_t): Vector[T] + {.importcpp: "std::vector<'*0>(@)", header: "vector".} + + proc unsafeIndex[T](this: var Vector[T], i: csize_t): var T + {.importcpp: "#[#]", header: "vector".} + + proc `[]`[T](this: var Vector[T], i: Natural): var T {.inline, noinit.} = + when compileOption("boundChecks"): + # this.checkIndex i + discard + result = this.unsafeIndex(csize_t(i)) + + var v1 = initVector[int](10) + doAssert v1[0] == 0 + +block: # bug #12703 bug #19588 + type + cstringConstImpl {.importc:"const char*".} = cstring + constChar = distinct cstringConstImpl + + {.emit: """ + const char* foo() { + return "hello"; + } + """.} + proc foo(): constChar {.importcpp.} # change to importcpp for C++ backend + doAssert $(foo().cstring) == "hello" + diff --git a/tests/destructor/t23748.nim b/tests/destructor/t23748.nim new file mode 100644 index 000000000..a3738733e --- /dev/null +++ b/tests/destructor/t23748.nim @@ -0,0 +1,31 @@ +discard """ + matrix: "--gc:refc; --gc:arc" + output: ''' +hello 42 +hello 42 +len = 2 +''' +""" + +# bug #23748 + +type + O = ref object + s: string + cb: seq[proc()] + +proc push1(o: O, i: int) = + let o = o + echo o.s, " ", i + o.cb.add(proc() = echo o.s, " ", i) + +proc push2(o: O, i: int) = + let o = o + echo o.s, " ", i + proc p() = echo o.s, " ", i + o.cb.add(p) + +let o = O(s: "hello", cb: @[]) +o.push1(42) +o.push2(42) +echo "len = ", o.cb.len diff --git a/tests/destructor/t23837.nim b/tests/destructor/t23837.nim new file mode 100644 index 000000000..e219dd6b5 --- /dev/null +++ b/tests/destructor/t23837.nim @@ -0,0 +1,51 @@ +discard """ + output: ''' +Deallocating OwnedString +HelloWorld +''' + matrix: "--cursorinference:on; --cursorinference:off" + target: "c" +""" + +# bug #23837 +{. + emit: [ + """ +#include <stdlib.h> +#include <string.h> +char *allocCString() { + char *result = (char *) malloc(10 + 1); + strcpy(result, "HelloWorld"); + return result; +} + +""" + ] +.} + +proc rawWrapper(): cstring {.importc: "allocCString", cdecl.} +proc free(p: pointer) {.importc: "free", cdecl.} + +# ------------------------- + +type OwnedString = distinct cstring + +proc `=destroy`(s: OwnedString) = + free(cstring s) + echo "Deallocating OwnedString" + +func `$`(s: OwnedString): string {.borrow.} + +proc leakyWrapper(): string = + let ostring = rawWrapper().OwnedString + $ostring + +# ------------------------- + +proc main() = + # destructor not called - definitely lost: 11 bytes in 1 blocks + # doesn't leak with --cursorInference:off + let s = leakyWrapper() + echo s + +main() \ No newline at end of file diff --git a/tests/destructor/tatomicptrs.nim b/tests/destructor/tatomicptrs.nim index 7bd5482b2..82870ac82 100644 --- a/tests/destructor/tatomicptrs.nim +++ b/tests/destructor/tatomicptrs.nim @@ -143,11 +143,13 @@ proc `=sink`*[T](m: var MySeq[T], m2: MySeq[T]) {.inline.} = `=destroy`(m) m.len = m2.len m.data = m2.data + m.refcount = m2.refcount proc len*[T](m: MySeq[T]): int {.inline.} = m.len proc newMySeq*[T](size: int, initial_value: T): MySeq[T] = result.len = size + result.refcount = 1 if size > 0: result.data = cast[ptr UncheckedArray[T]](allocShared(sizeof(T) * size)) diff --git a/tests/destructor/tdistinctseq.nim b/tests/destructor/tdistinctseq.nim new file mode 100644 index 000000000..5a2ac5ead --- /dev/null +++ b/tests/destructor/tdistinctseq.nim @@ -0,0 +1,8 @@ +discard """ + matrix: "-u:nimPreviewNonVarDestructor;" +""" +type DistinctSeq* = distinct seq[int] + +# `=destroy`(cast[ptr DistinctSeq](0)[]) +var x = @[].DistinctSeq +`=destroy`(x) diff --git a/tests/destructor/tgotoexc_leak.nim b/tests/destructor/tgotoexc_leak.nim new file mode 100644 index 000000000..c8a234085 --- /dev/null +++ b/tests/destructor/tgotoexc_leak.nim @@ -0,0 +1,19 @@ +discard """ + output: '''0 +true''' + cmd: "nim c --gc:arc $file" +""" + +# bug #22398 + +for i in 0 ..< 10_000: + try: + try: + raise newException(ValueError, "") + except CatchableError: + discard + raise newException(ValueError, "") # or raise getCurrentException(), just raise works ok + except ValueError: + discard +echo getOccupiedMem() +echo getCurrentException() == nil diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim index a583a1704..cdc1eb1c0 100644 --- a/tests/destructor/tmove_objconstr.nim +++ b/tests/destructor/tmove_objconstr.nim @@ -137,28 +137,29 @@ doAssert seq3[0] == 1.0 var seq4, seq5: MySeqNonCopyable (seq4, i, seq5) = myfunc2(2, 3) -seq4 = block: - var tmp = newMySeq(4, 1.0) - tmp[0] = 3.0 - tmp +proc foo = + seq4 = block: + var tmp = newMySeq(4, 1.0) + tmp[0] = 3.0 + tmp -doAssert seq4[0] == 3.0 + doAssert seq4[0] == 3.0 -import macros -seq4 = - if i > 0: newMySeq(2, 5.0) - elif i < -100: raise newException(ValueError, "Parse Error") - else: newMySeq(2, 3.0) + seq4 = + if i > 0: newMySeq(2, 5.0) + elif i < -100: raise newException(ValueError, "Parse Error") + else: newMySeq(2, 3.0) -seq4 = - case (char) i: - of 'A', {'W'..'Z'}: newMySeq(2, 5.0) - of 'B': quit(-1) - else: - let (x1, x2, x3) = myfunc2(2, 3) - x3 + seq4 = + case (char) i: + of 'A', {'W'..'Z'}: newMySeq(2, 5.0) + of 'B': quit(-1) + else: + let (x1, x2, x3) = myfunc2(2, 3) + x3 +foo() #------------------------------------------------------------ #-- Move into array constructor diff --git a/tests/destructor/tsink.nim b/tests/destructor/tsink.nim new file mode 100644 index 000000000..e8750ad7c --- /dev/null +++ b/tests/destructor/tsink.nim @@ -0,0 +1,70 @@ +discard """ + matrix: "--mm:arc" +""" + +type AnObject = object of RootObj + value*: int + +proc mutate(shit: sink AnObject) = + shit.value = 1 + +proc foo = # bug #23359 + var bar = AnObject(value: 42) + mutate(bar) + doAssert bar.value == 42 + +foo() + +block: # bug #23902 + proc foo(a: sink string): auto = (a, a) + + proc bar(a: sink int): auto = return a + + proc foo(a: sink string) = + var x = (a, a) + +block: # bug #24175 + block: + func mutate(o: sink string): string = + o[1] = '1' + result = o + + static: + let s = "999" + let m = mutate(s) + doAssert s == "999" + doAssert m == "919" + + func foo() = + let s = "999" + let m = mutate(s) + doAssert s == "999" + doAssert m == "919" + + static: + foo() + foo() + + block: + type O = object + a: int + + func mutate(o: sink O): O = + o.a += 1 + o + + static: + let x = O(a: 1) + let y = mutate(x) + doAssert x.a == 1 + doAssert y.a == 2 + + proc foo() = + let x = O(a: 1) + let y = mutate(x) + doAssert x.a == 1 + doAssert y.a == 2 + + static: + foo() + foo() diff --git a/tests/destructor/tv2_cast.nim b/tests/destructor/tv2_cast.nim index 4ff2dc9a0..48bdf67dd 100644 --- a/tests/destructor/tv2_cast.nim +++ b/tests/destructor/tv2_cast.nim @@ -10,69 +10,41 @@ destroying O1''' var data :tmpD - :tmpD_1 - :tmpD_2 -data = - :tmpD = `=dup`(cast[string]( - :tmpD_2 = encode(cast[seq[byte]]( - :tmpD_1 = newString(100) - :tmpD_1)) - :tmpD_2)) - :tmpD -`=destroy`(:tmpD_2) -`=destroy_1`(:tmpD_1) -`=destroy_1`(data) +data = cast[string](encode(cast[seq[byte]]( + :tmpD = newString(100) + :tmpD))) +`=destroy`(:tmpD) +`=destroy`(data) -- end of expandArc ------------------------ --expandArc: main1 var s data - :tmpD - :tmpD_1 s = newString(100) -data = - :tmpD = `=dup`(cast[string]( - :tmpD_1 = encode(toOpenArrayByte(s, 0, len(s) - 1)) - :tmpD_1)) - :tmpD -`=destroy`(:tmpD_1) -`=destroy_1`(data) -`=destroy_1`(s) +data = cast[string](encode(toOpenArrayByte(s, 0, len(s) - 1))) +`=destroy`(data) +`=destroy`(s) -- end of expandArc ------------------------ --expandArc: main2 var s data - :tmpD - :tmpD_1 s = newSeq(100) -data = - :tmpD = `=dup`(cast[string]( - :tmpD_1 = encode(s) - :tmpD_1)) - :tmpD -`=destroy`(:tmpD_1) -`=destroy_1`(data) -`=destroy`(s) +data = cast[string](encode(s)) +`=destroy`(data) +`=destroy_1`(s) -- end of expandArc ------------------------ --expandArc: main3 var data :tmpD - :tmpD_1 - :tmpD_2 -data = - :tmpD = `=dup`(cast[string]( - :tmpD_2 = encode do: - :tmpD_1 = newSeq(100) - :tmpD_1 - :tmpD_2)) - :tmpD -`=destroy`(:tmpD_2) -`=destroy`(:tmpD_1) +data = cast[string](encode do: + :tmpD = newSeq(100) + :tmpD) +`=destroy`(:tmpD) `=destroy_1`(data) -- end of expandArc ------------------------ ''' diff --git a/tests/discard/t23677.nim b/tests/discard/t23677.nim new file mode 100644 index 000000000..1ed7386bd --- /dev/null +++ b/tests/discard/t23677.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "expression '0' is of type 'int literal(0)' and has to be used (or discarded); start of expression here: t23677.nim(1, 1)" + line: 10 + column: 3 +""" + +# issue #23677 + +if true: + 0 +else: + raise newException(ValueError, "err") diff --git a/tests/discard/tdiscardable.nim b/tests/discard/tdiscardable.nim index 69cb9f6a1..84b669ed8 100644 --- a/tests/discard/tdiscardable.nim +++ b/tests/discard/tdiscardable.nim @@ -5,6 +5,7 @@ tdiscardable 1 something defered something defered +hi ''' """ @@ -110,3 +111,65 @@ block: doAssertRaises(ValueError): doAssert foo() == 12 + +block: # issue #10440 + proc x(): int {.discardable.} = discard + try: + x() + finally: + echo "hi" + +import macros + +block: # issue #14665 + macro test(): untyped = + let b = @[1, 2, 3, 4] + + result = nnkStmtList.newTree() + var i = 0 + while i < b.len: + if false: + # this quote do is mandatory, removing it fixes the problem + result.add quote do: + let testtest = 5 + else: + result.add quote do: + let test = 6 + inc i + # removing this continue fixes the problem too + continue + inc i + test() + +block: # bug #23775 + proc retInt(): int {.discardable.} = + 42 + + proc retString(): string {.discardable.} = + "text" + + type + Enum = enum + A, B, C, D + + proc doStuff(msg: Enum) = + case msg: + of A: + retString() + of B: + retInt() + of C: + discard retString() + else: + let _ = retString() + + doStuff(C) + +block: + proc test(): (int, int) {.discardable.} = + discard + + if true: + test() + else: + quit() diff --git a/tests/discard/tfinallyerrmsg.nim b/tests/discard/tfinallyerrmsg.nim new file mode 100644 index 000000000..fbc8140aa --- /dev/null +++ b/tests/discard/tfinallyerrmsg.nim @@ -0,0 +1,19 @@ +discard """ + cmd: "nim check $file" +""" + +block: # issue #19672 + try: + 10 #[tt.Error + ^ expression '10' is of type 'int literal(10)' and has to be used (or discarded); start of expression here: tfinallyerrmsg.nim(5, 1)]# + finally: + echo "Finally block" + +block: # issue #13871 + template t(body: int) = + try: + body + finally: + echo "expression" + t: 2 #[tt.Error + ^ expression '2' is of type 'int literal(2)' and has to be used (or discarded)]# diff --git a/tests/distinct/tcomplexaddressableconv.nim b/tests/distinct/tcomplexaddressableconv.nim new file mode 100644 index 000000000..00e96bfeb --- /dev/null +++ b/tests/distinct/tcomplexaddressableconv.nim @@ -0,0 +1,21 @@ +# issue #22523 + +from std/typetraits import distinctBase + +type + V[p: static int] = distinct int + D[p: static int] = distinct int + T = V[1] + +proc f(y: var T) = discard + +var a: D[0] + +static: + doAssert distinctBase(T) is distinctBase(D[0]) + doAssert distinctBase(T) is int + doAssert distinctBase(D[0]) is int + doAssert T(a) is T + +f(cast[ptr T](addr a)[]) +f(T(a)) diff --git a/tests/effects/thooks.nim b/tests/effects/thooks.nim new file mode 100644 index 000000000..23cc005cd --- /dev/null +++ b/tests/effects/thooks.nim @@ -0,0 +1,16 @@ +discard """ + matrix: "--warningAsError:Effect" +""" + +import std/isolation + +# bug #23129 +type + Thing = object + x: string + +proc send(x: string) = + let wrapper = Thing(x: x) + discard isolate(wrapper) + +send("la") \ No newline at end of file diff --git a/tests/enum/tambiguousoverloads.nim b/tests/enum/tambiguousoverloads.nim index aa75eaa91..12c78c848 100644 --- a/tests/enum/tambiguousoverloads.nim +++ b/tests/enum/tambiguousoverloads.nim @@ -9,7 +9,7 @@ block: # bug #21887 EnumC = enum C doAssert typeof(EnumC(A)) is EnumC #[tt.Error - ^ ambiguous identifier 'A' -- use one of the following: + ^ ambiguous identifier: 'A' -- use one of the following: EnumA.A: EnumA EnumB.A: EnumB]# @@ -21,6 +21,6 @@ block: # issue #22598 red let a = red #[tt.Error - ^ ambiguous identifier 'red' -- use one of the following: + ^ ambiguous identifier: 'red' -- use one of the following: A.red: A B.red: B]# diff --git a/tests/enum/tenum.nim b/tests/enum/tenum.nim index 8046c6589..a03019c5d 100644 --- a/tests/enum/tenum.nim +++ b/tests/enum/tenum.nim @@ -184,3 +184,84 @@ block: # bug #12589 A = int64.high() doAssert ord(A) == int64.high() + +import std/enumutils +from std/sequtils import toSeq +import std/macros + +block: # unordered enum + block: + type + unordered_enum = enum + a = 1 + b = 0 + + doAssert (ord(a), ord(b)) == (1, 0) + doAssert unordered_enum.toSeq == @[a, b] + + block: + type + unordered_enum = enum + a = 1 + b = 0 + c + + doAssert (ord(a), ord(b), ord(c)) == (1, 0, 2) + + block: + type + unordered_enum = enum + a = 100 + b + c = 50 + d + + doAssert (ord(a), ord(b), ord(c), ord(d)) == (100, 101, 50, 51) + + block: + type + unordered_enum = enum + a = 7 + b = 6 + c = 5 + d + + doAssert (ord(a), ord(b), ord(c), ord(d)) == (7, 6, 5, 8) + doAssert unordered_enum.toSeq == @[a, b, c, d] + + block: + type + unordered_enum = enum + a = 100 + b + c = 500 + d + e + f = 50 + g + h + + doAssert (ord(a), ord(b), ord(c), ord(d), ord(e), ord(f), ord(g), ord(h)) == + (100, 101, 500, 501, 502, 50, 51, 52) + + block: + type + unordered_enum = enum + A + B + C = -1 + D + E + G = -999 + + doAssert (ord(A), ord(B), ord(C), ord(D), ord(E), ord(G)) == + (0, 1, -1, 2, 3, -999) + + block: + type + SomeEnum = enum + seA = 3 + seB = 2 + seC = "foo" + + doAssert (ord(seA), ord(seB), ord(seC)) == (3, 2, 4) diff --git a/tests/enum/tenum_duplicate.nim b/tests/enum/tenum_duplicate.nim new file mode 100644 index 000000000..4bcad7f6f --- /dev/null +++ b/tests/enum/tenum_duplicate.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "duplicate value in enum 'd'" +""" + +type + unordered_enum = enum + a = 1 + b = 0 + c + d = 2 diff --git a/tests/enum/toverloadedname.nim b/tests/enum/toverloadedname.nim new file mode 100644 index 000000000..d11b0fb83 --- /dev/null +++ b/tests/enum/toverloadedname.nim @@ -0,0 +1,7 @@ +block: # issue #23998 + type + Enum {.pure.} = enum + a + Obj = object + a: Enum + proc test(a: Enum) = discard Obj(a: a) diff --git a/tests/enum/tpure_enums_conflict.nim b/tests/enum/tpure_enums_conflict.nim index 3c7528a72..3cf335440 100644 --- a/tests/enum/tpure_enums_conflict.nim +++ b/tests/enum/tpure_enums_conflict.nim @@ -1,6 +1,5 @@ discard """ - errormsg: "ambiguous identifier: 'amb'" - line: 19 + matrix: "-d:testsConciseTypeMismatch" """ # bug #8066 @@ -16,4 +15,13 @@ when true: echo valueA # MyEnum.valueA echo MyEnum.amb # OK. - echo amb # Error: Unclear whether it's MyEnum.amb or OtherEnum.amb + echo amb #[tt.Error + ^ type mismatch +Expression: echo amb + [1] amb: MyEnum | OtherEnum + +Expected one of (first mismatch at [position]): +[1] proc echo(x: varargs[typed, `$$`]) + ambiguous identifier: 'amb' -- use one of the following: + MyEnum.amb: MyEnum + OtherEnum.amb: OtherEnum]# diff --git a/tests/enum/tpure_enums_conflict_legacy.nim b/tests/enum/tpure_enums_conflict_legacy.nim new file mode 100644 index 000000000..e592925bc --- /dev/null +++ b/tests/enum/tpure_enums_conflict_legacy.nim @@ -0,0 +1,25 @@ +# bug #8066 + +when true: + type + MyEnum {.pure.} = enum + valueA, valueB, valueC, valueD, amb + + OtherEnum {.pure.} = enum + valueX, valueY, valueZ, amb + + + echo valueA # MyEnum.valueA + echo MyEnum.amb # OK. + echo amb #[tt.Error + ^ type mismatch: got <MyEnum | OtherEnum> +but expected one of: +proc echo(x: varargs[typed, `$$`]) + first type mismatch at position: 1 + required type for x: varargs[typed] + but expression 'amb' is of type: None + ambiguous identifier: 'amb' -- use one of the following: + MyEnum.amb: MyEnum + OtherEnum.amb: OtherEnum + +expression: echo amb]# diff --git a/tests/enum/ttypenameconflict.nim b/tests/enum/ttypenameconflict.nim new file mode 100644 index 000000000..b13bf00ce --- /dev/null +++ b/tests/enum/ttypenameconflict.nim @@ -0,0 +1,13 @@ +# issue #23689 + +type + MyEnum {.pure.} = enum + A, B, C, D + + B = object + field: int + +let x: MyEnum = B +doAssert $x == "B" +doAssert typeof(x) is MyEnum +doAssert x in {A, B} diff --git a/tests/errmsgs/mambparam1.nim b/tests/errmsgs/mambparam1.nim new file mode 100644 index 000000000..1a5133c3c --- /dev/null +++ b/tests/errmsgs/mambparam1.nim @@ -0,0 +1 @@ +const test* = "foo" diff --git a/tests/errmsgs/mambparam2.nim b/tests/errmsgs/mambparam2.nim new file mode 100644 index 000000000..073e3f8c8 --- /dev/null +++ b/tests/errmsgs/mambparam2.nim @@ -0,0 +1,2 @@ +import mambparam1 +export test diff --git a/tests/errmsgs/mambparam3.nim b/tests/errmsgs/mambparam3.nim new file mode 100644 index 000000000..5469244e2 --- /dev/null +++ b/tests/errmsgs/mambparam3.nim @@ -0,0 +1 @@ +const test* = "bar" diff --git a/tests/errmsgs/t10735.nim b/tests/errmsgs/t10735.nim index f480d35ac..a39cd196e 100644 --- a/tests/errmsgs/t10735.nim +++ b/tests/errmsgs/t10735.nim @@ -2,40 +2,62 @@ discard """ cmd: "nim check $file" errormsg: "illformed AST: case buf[pos]" nimout: ''' -t10735.nim(43, 5) Error: 'let' symbol requires an initialization -t10735.nim(44, 10) Error: undeclared identifier: 'pos' -t10735.nim(44, 10) Error: expression 'pos' has no type (or is ambiguous) -t10735.nim(44, 10) Error: expression 'pos' has no type (or is ambiguous) -t10735.nim(44, 9) Error: type mismatch: got <cstring, > +t10735.nim(65, 5) Error: 'let' symbol requires an initialization +t10735.nim(66, 10) Error: undeclared identifier: 'pos' +t10735.nim(66, 10) Error: expression 'pos' has no type (or is ambiguous) +t10735.nim(66, 10) Error: expression 'pos' has no type (or is ambiguous) +t10735.nim(66, 9) Error: type mismatch: got <cstring, > but expected one of: proc `[]`(s: string; i: BackwardsIndex): char - first type mismatch at position: 0 + first type mismatch at position: 1 + required type for s: string + but expression 'buf' is of type: cstring proc `[]`(s: var string; i: BackwardsIndex): var char - first type mismatch at position: 0 + first type mismatch at position: 1 + required type for s: var string + but expression 'buf' is of type: cstring proc `[]`[I: Ordinal; T](a: T; i: I): T first type mismatch at position: 0 proc `[]`[Idx, T; U, V: Ordinal](a: array[Idx, T]; x: HSlice[U, V]): seq[T] - first type mismatch at position: 0 + first type mismatch at position: 1 + required type for a: array[Idx, T] + but expression 'buf' is of type: cstring proc `[]`[Idx, T](a: array[Idx, T]; i: BackwardsIndex): T - first type mismatch at position: 0 + first type mismatch at position: 1 + required type for a: array[Idx, T] + but expression 'buf' is of type: cstring proc `[]`[Idx, T](a: var array[Idx, T]; i: BackwardsIndex): var T - first type mismatch at position: 0 + first type mismatch at position: 1 + required type for a: var array[Idx, T] + but expression 'buf' is of type: cstring proc `[]`[T, U: Ordinal](s: string; x: HSlice[T, U]): string - first type mismatch at position: 0 + first type mismatch at position: 1 + required type for s: string + but expression 'buf' is of type: cstring proc `[]`[T; U, V: Ordinal](s: openArray[T]; x: HSlice[U, V]): seq[T] - first type mismatch at position: 0 + first type mismatch at position: 1 + required type for s: openArray[T] + but expression 'buf' is of type: cstring proc `[]`[T](s: openArray[T]; i: BackwardsIndex): T - first type mismatch at position: 0 + first type mismatch at position: 1 + required type for s: openArray[T] + but expression 'buf' is of type: cstring proc `[]`[T](s: var openArray[T]; i: BackwardsIndex): var T - first type mismatch at position: 0 + first type mismatch at position: 1 + required type for s: var openArray[T] + but expression 'buf' is of type: cstring template `[]`(a: WideCStringObj; idx: int): Utf16Char - first type mismatch at position: 0 + first type mismatch at position: 1 + required type for a: WideCStringObj + but expression 'buf' is of type: cstring template `[]`(s: string; i: int): char - first type mismatch at position: 0 + first type mismatch at position: 1 + required type for s: string + but expression 'buf' is of type: cstring -expression: `[]`(buf, pos) -t10735.nim(44, 9) Error: expression '' has no type (or is ambiguous) -t10735.nim(46, 3) Error: illformed AST: case buf[pos] +expression: buf[pos] +t10735.nim(66, 9) Error: expression '' has no type (or is ambiguous) +t10735.nim(68, 3) Error: illformed AST: case buf[pos] ''' joinable: false """ diff --git a/tests/errmsgs/t16654.nim b/tests/errmsgs/t16654.nim index 749707c06..b2b57619b 100644 --- a/tests/errmsgs/t16654.nim +++ b/tests/errmsgs/t16654.nim @@ -1,6 +1,6 @@ discard """ cmd: "nim check $options $file" - errormsg: "type mismatch: got <int> but expected 'float'" + errormsg: "type mismatch: got <int literal(1), proc (r: GenericParam): auto>" """ when true: # bug #16654 diff --git a/tests/errmsgs/t17460.nim b/tests/errmsgs/t17460.nim index e377bc48a..bb8e21198 100644 --- a/tests/errmsgs/t17460.nim +++ b/tests/errmsgs/t17460.nim @@ -1,6 +1,6 @@ discard """ cmd: "nim check $options $file" - errormsg: "wrong number of variables" + errormsg: "tuple expected for tuple unpacking, but got 'array[0..2, int]'" """ iterator xclusters*[T](a: openArray[T]; s: static[int]): array[s, T] {.inline.} = @@ -16,4 +16,4 @@ proc m = for (i, j, k) in xclusters([1, 2, 3, 4, 5], 3): echo i, j, k -m() \ No newline at end of file +m() diff --git a/tests/errmsgs/t22097.nim b/tests/errmsgs/t22097.nim index b50db08a3..bb24ee8d3 100644 --- a/tests/errmsgs/t22097.nim +++ b/tests/errmsgs/t22097.nim @@ -1,9 +1,9 @@ discard """ - errormsg: "for a 'var' type a variable needs to be passed; but 'uint16(x)' is immutable" + errormsg: "type mismatch: got <uint8>" """ proc toUInt16(x: var uint16) = discard var x = uint8(1) -toUInt16 x \ No newline at end of file +toUInt16 x diff --git a/tests/errmsgs/t22284.nim b/tests/errmsgs/t22284.nim new file mode 100644 index 000000000..827155e6b --- /dev/null +++ b/tests/errmsgs/t22284.nim @@ -0,0 +1,25 @@ +discard """ + errormsg: "j(uRef, proc (config: F; sources: auto) {.raises: [].} = discard ) can raise an unlisted exception: Exception" +""" + +import std/macros + +macro h(): untyped = + result = newTree(nnkStmtList) + result.add quote do: + new int + +type F = object + +proc j[SecondarySources]( + uRef: ref SecondarySources, + u: proc (config: F, sources: ref SecondarySources)): F = + u(result, uRef) + +template programMain(body: untyped) = + proc main {.raises: [].} = body # doesn't SIGSEGV without this {.raises: [].} + main() + +programMain: + var uRef = h() + discard j(uRef, u = proc(config: F, sources: auto) {.raises: [].} = discard) \ No newline at end of file diff --git a/tests/errmsgs/t22753.nim b/tests/errmsgs/t22753.nim index af6a871f1..8a504109a 100644 --- a/tests/errmsgs/t22753.nim +++ b/tests/errmsgs/t22753.nim @@ -3,33 +3,50 @@ cmd: "nim check --hints:off $file" errormsg: "type mismatch" nimoutFull: true nimout: ''' -t22753.nim(34, 13) Error: array expects two type parameters -t22753.nim(35, 1) Error: expression 'x' has no type (or is ambiguous) -t22753.nim(35, 1) Error: expression 'x' has no type (or is ambiguous) -t22753.nim(35, 2) Error: type mismatch: got <> +t22753.nim(51, 13) Error: array expects two type parameters +t22753.nim(52, 1) Error: expression 'x' has no type (or is ambiguous) +t22753.nim(52, 1) Error: expression 'x' has no type (or is ambiguous) +t22753.nim(52, 2) Error: type mismatch: got <> but expected one of: proc `[]=`(s: var string; i: BackwardsIndex; x: char) - first type mismatch at position: 0 + first type mismatch at position: 2 + required type for i: BackwardsIndex + but expression '0' is of type: int literal(0) proc `[]=`[I: Ordinal; T, S](a: T; i: I; x: sink S) first type mismatch at position: 0 proc `[]=`[Idx, T; U, V: Ordinal](a: var array[Idx, T]; x: HSlice[U, V]; b: openArray[T]) - first type mismatch at position: 0 + first type mismatch at position: 2 + required type for x: HSlice[[]=.U, []=.V] + but expression '0' is of type: int literal(0) proc `[]=`[Idx, T](a: var array[Idx, T]; i: BackwardsIndex; x: T) - first type mismatch at position: 0 + first type mismatch at position: 2 + required type for i: BackwardsIndex + but expression '0' is of type: int literal(0) proc `[]=`[T, U: Ordinal](s: var string; x: HSlice[T, U]; b: string) - first type mismatch at position: 0 + first type mismatch at position: 2 + required type for x: HSlice[[]=.T, []=.U] + but expression '0' is of type: int literal(0) proc `[]=`[T; U, V: Ordinal](s: var seq[T]; x: HSlice[U, V]; b: openArray[T]) - first type mismatch at position: 0 + first type mismatch at position: 2 + required type for x: HSlice[[]=.U, []=.V] + but expression '0' is of type: int literal(0) proc `[]=`[T](s: var openArray[T]; i: BackwardsIndex; x: T) - first type mismatch at position: 0 + first type mismatch at position: 2 + required type for i: BackwardsIndex + but expression '0' is of type: int literal(0) template `[]=`(a: WideCStringObj; idx: int; val: Utf16Char) - first type mismatch at position: 0 + first type mismatch at position: 3 + required type for val: Utf16Char + but expression '9' is of type: int literal(9) template `[]=`(s: string; i: int; val: char) - first type mismatch at position: 0 + first type mismatch at position: 3 + required type for val: char + but expression '9' is of type: int literal(9) -expression: `[]=`(x, 0, 9) +expression: x[0] = 9 ''' """ + var x: array[3] # bug #22753 -x[0] = 9 \ No newline at end of file +x[0] = 9 diff --git a/tests/errmsgs/t22852.nim b/tests/errmsgs/t22852.nim new file mode 100644 index 000000000..7c352a49c --- /dev/null +++ b/tests/errmsgs/t22852.nim @@ -0,0 +1,9 @@ +discard """ + exitcode: 1 + outputsub: ''' +Error: unhandled exception: value out of range: -2 notin 0 .. 9223372036854775807 [RangeDefect] +''' +""" + +# bug #22852 +echo [0][2..^2] diff --git a/tests/errmsgs/t23419.nim b/tests/errmsgs/t23419.nim new file mode 100644 index 000000000..59a72f081 --- /dev/null +++ b/tests/errmsgs/t23419.nim @@ -0,0 +1,5 @@ +discard """ + errormsg: "invalid type: 'void' in this context: '(array[0..-1, void],)' for var" +""" + +var a: (array[0, void], ) diff --git a/tests/errmsgs/t23435.nim b/tests/errmsgs/t23435.nim new file mode 100644 index 000000000..5e2e4c82a --- /dev/null +++ b/tests/errmsgs/t23435.nim @@ -0,0 +1,12 @@ +discard """ + outputsub: "Error: unhandled exception: value out of range: -15 notin 0 .. 9223372036854775807 [RangeDefect]" + exitcode: "1" +""" + +# bug #23435 +proc foo() = + for _ in @[1, 3, 5]: + discard "abcde"[25..<10] + break + +foo() diff --git a/tests/errmsgs/t23536.nim b/tests/errmsgs/t23536.nim new file mode 100644 index 000000000..610a85bab --- /dev/null +++ b/tests/errmsgs/t23536.nim @@ -0,0 +1,26 @@ +discard """ + matrix: "--stackTrace:on --excessiveStackTrace:off" +""" + +const expected = """ +wrong trace: +t23536.nim(22) t23536 +t23536.nim(17) foo +assertions.nim(41) failedAssertImpl +assertions.nim(36) raiseAssert +fatal.nim(53) sysFatal +""" + + +try: + proc foo = # bug #23536 + doAssert false + + for i in 0 .. 1: + + + foo() +except AssertionDefect: + let e = getCurrentException() + let trace = e.getStackTrace + doAssert "wrong trace:\n" & trace == expected diff --git a/tests/errmsgs/t5167_5.nim b/tests/errmsgs/t5167_5.nim index 6c1269bce..dea7e40b3 100644 --- a/tests/errmsgs/t5167_5.nim +++ b/tests/errmsgs/t5167_5.nim @@ -17,9 +17,9 @@ proc bar(x: proc (x: int)) = let x = t #[tt.Error ^ 't' has unspecified generic parameters]# bar t #[tt.Error - ^ 't' has unspecified generic parameters]# +^ type mismatch: got <template [*missing parameters*]()>]# let y = m #[tt.Error ^ 'm' has unspecified generic parameters]# bar m #[tt.Error - ^ 'm' has unspecified generic parameters]# +^ type mismatch: got <macro [*missing parameters*](): untyped{.noSideEffect, gcsafe.}>]# diff --git a/tests/errmsgs/t8064.nim b/tests/errmsgs/t8064.nim index 6be83fd1a..c35a3abcc 100644 --- a/tests/errmsgs/t8064.nim +++ b/tests/errmsgs/t8064.nim @@ -5,5 +5,5 @@ values discard """ # either this or "expression has no type": - errormsg: "ambiguous identifier 'values' -- use one of the following:" + errormsg: "ambiguous identifier: 'values' -- use one of the following:" """ diff --git a/tests/errmsgs/tambparam.nim b/tests/errmsgs/tambparam.nim new file mode 100644 index 000000000..5b56a3fce --- /dev/null +++ b/tests/errmsgs/tambparam.nim @@ -0,0 +1,16 @@ +discard """ + matrix: "-d:testsConciseTypeMismatch" +""" + +import mambparam2, mambparam3 + +echo test #[tt.Error +^ type mismatch +Expression: echo test + [1] test: string | string + +Expected one of (first mismatch at [position]): +[1] proc echo(x: varargs[typed, `$$`]) + ambiguous identifier: 'test' -- use one of the following: + mambparam1.test: string + mambparam3.test: string]# diff --git a/tests/errmsgs/tambparam_legacy.nim b/tests/errmsgs/tambparam_legacy.nim new file mode 100644 index 000000000..bd99a3aac --- /dev/null +++ b/tests/errmsgs/tambparam_legacy.nim @@ -0,0 +1,14 @@ +import mambparam2, mambparam3 + +echo test #[tt.Error +^ type mismatch: got <string | string> +but expected one of: +proc echo(x: varargs[typed, `$$`]) + first type mismatch at position: 1 + required type for x: varargs[typed] + but expression 'test' is of type: None + ambiguous identifier: 'test' -- use one of the following: + mambparam1.test: string + mambparam3.test: string + +expression: echo test]# diff --git a/tests/errmsgs/tconcisetypemismatch.nim b/tests/errmsgs/tconcisetypemismatch.nim index c2896604f..3093cc24e 100644 --- a/tests/errmsgs/tconcisetypemismatch.nim +++ b/tests/errmsgs/tconcisetypemismatch.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nim c --hints:off --skipParentCfg $file" + cmd: "nim c --hints:off -d:testsConciseTypeMismatch $file" errormsg: "type mismatch" nimout: ''' tconcisetypemismatch.nim(23, 47) Error: type mismatch diff --git a/tests/errmsgs/tconcisetypemismatch.nims b/tests/errmsgs/tconcisetypemismatch.nims deleted file mode 100644 index e9dce8147..000000000 --- a/tests/errmsgs/tconcisetypemismatch.nims +++ /dev/null @@ -1,21 +0,0 @@ -switch("path", "$lib/../testament/lib") - # so we can `import stdtest/foo` inside tests - # Using $lib/../ instead of $nim/ so you can use a different nim to run tests - # during local testing, e.g. nim --lib:lib. - -## prevent common user config settings to interfere with testament expectations -## Indifidual tests can override this if needed to test for these options. -switch("colors", "off") - -switch("excessiveStackTrace", "off") - -when (NimMajor, NimMinor, NimPatch) >= (1,5,1): - # to make it easier to test against older nim versions, (best effort only) - switch("filenames", "legacyRelProj") - switch("spellSuggest", "0") - -# for std/unittest -switch("define", "nimUnittestOutputLevel:PRINT_FAILURES") -switch("define", "nimUnittestColor:off") - -hint("Processing", off) diff --git a/tests/errmsgs/tgenericmismatchsegfault.nim b/tests/errmsgs/tgenericmismatchsegfault.nim new file mode 100644 index 000000000..dbb783cb3 --- /dev/null +++ b/tests/errmsgs/tgenericmismatchsegfault.nim @@ -0,0 +1,13 @@ +discard """ + matrix: "-d:testsConciseTypeMismatch" +""" + +template v[T](c: SomeOrdinal): T = T(c) +discard v[int, char]('A') #[tt.Error + ^ type mismatch +Expression: v[int, char]('A') + [1] 'A': char + +Expected one of (first mismatch at [position]): +[2] template v[T](c: SomeOrdinal): T + generic parameter mismatch, expected SomeOrdinal but got 'char' of type: char]# diff --git a/tests/errmsgs/tgenericmismatchsegfault_legacy.nim b/tests/errmsgs/tgenericmismatchsegfault_legacy.nim new file mode 100644 index 000000000..1532611b9 --- /dev/null +++ b/tests/errmsgs/tgenericmismatchsegfault_legacy.nim @@ -0,0 +1,10 @@ +template v[T](c: SomeOrdinal): T = T(c) +discard v[int, char]('A') #[tt.Error + ^ type mismatch: got <char> +but expected one of: +template v[T](c: SomeOrdinal): T + first type mismatch at position: 2 in generic parameters + required type for SomeOrdinal: SomeOrdinal + but expression 'char' is of type: char + +expression: v[int, char]('A')]# diff --git a/tests/errmsgs/tinconsistentgensym.nim b/tests/errmsgs/tinconsistentgensym.nim new file mode 100644 index 000000000..8e4c85106 --- /dev/null +++ b/tests/errmsgs/tinconsistentgensym.nim @@ -0,0 +1,25 @@ +discard """ + cmd: "nim check --hints:off $file" +""" + +block: + template foo = + when false: + let x = 123 + else: + template x: untyped {.inject.} = 456 + echo x #[tt.Error + ^ undeclared identifier: 'x`gensym0'; if declared in a template, this identifier may be inconsistently marked inject or gensym]# + foo() + +block: + template foo(y: static bool) = + block: + when y: + let x {.gensym.} = 123 + else: + let x {.inject.} = 456 + echo x #[tt.Error + ^ undeclared identifier: 'x']# + foo(false) + foo(true) diff --git a/tests/errmsgs/tmetaobjectfields.nim b/tests/errmsgs/tmetaobjectfields.nim new file mode 100644 index 000000000..47d3acf18 --- /dev/null +++ b/tests/errmsgs/tmetaobjectfields.nim @@ -0,0 +1,75 @@ +discard """ + cmd: "nim check --hints:off $file" + action: "reject" + nimout: ''' +tmetaobjectfields.nim(26, 5) Error: 'array' is not a concrete type +tmetaobjectfields.nim(30, 5) Error: 'seq' is not a concrete type +tmetaobjectfields.nim(34, 5) Error: 'set' is not a concrete type +tmetaobjectfields.nim(37, 3) Error: 'sink' is not a concrete type +tmetaobjectfields.nim(39, 3) Error: 'lent' is not a concrete type +tmetaobjectfields.nim(56, 16) Error: 'seq' is not a concrete type +tmetaobjectfields.nim(60, 5) Error: 'ptr' is not a concrete type +tmetaobjectfields.nim(61, 5) Error: 'ref' is not a concrete type +tmetaobjectfields.nim(62, 5) Error: 'auto' is not a concrete type +tmetaobjectfields.nim(63, 5) Error: 'UncheckedArray' is not a concrete type +tmetaobjectfields.nim(68, 5) Error: 'object' is not a concrete type +tmetaobjectfields.nim(72, 5) Error: 'Type3011:ObjectType' is not a concrete type +''' +""" + + +# bug #6982 +# bug #19546 +# bug #23531 +type + ExampleObj1 = object + arr: array + +type + ExampleObj2 = object + arr: seq + +type + ExampleObj3 = object + arr: set + +type A = object + b: sink + # a: openarray + c: lent + +type PropertyKind = enum + tInt, + tFloat, + tBool, + tString, + tArray + +type + Property = ref PropertyObj + PropertyObj = object + case kind: PropertyKind + of tInt: intValue: int + of tFloat: floatValue: float + of tBool: boolValue: bool + of tString: stringValue: string + of tArray: arrayValue: seq + +type + RegressionTest = object + a: ptr + b: ref + c: auto + d: UncheckedArray + +# bug #3011 +type + Type3011 = ref object + context: ref object + +type + Value3011 = ref object + typ: Type3011 + +proc x3011(): Value3011 = + nil diff --git a/tests/errmsgs/tsubscriptmismatch.nim b/tests/errmsgs/tsubscriptmismatch.nim new file mode 100644 index 000000000..a2b297b68 --- /dev/null +++ b/tests/errmsgs/tsubscriptmismatch.nim @@ -0,0 +1,11 @@ +discard """ + matrix: "-d:testsConciseTypeMismatch" + nimout: ''' +[1] proc `[]`[T; U, V: Ordinal](s: openArray[T]; x: HSlice[U, V]): seq[T] +''' +""" + +type Foo = object +let x = Foo() +discard x[1] #[tt.Error + ^ type mismatch]# diff --git a/tests/errmsgs/tsubscriptmismatch_legacy.nim b/tests/errmsgs/tsubscriptmismatch_legacy.nim new file mode 100644 index 000000000..3e1f1eb71 --- /dev/null +++ b/tests/errmsgs/tsubscriptmismatch_legacy.nim @@ -0,0 +1,10 @@ +discard """ + nimout: ''' + but expression 'x' is of type: Foo +''' +""" + +type Foo = object +let x = Foo() +discard x[1] #[tt.Error + ^ type mismatch: got <Foo, int literal(1)>]# diff --git a/tests/errmsgs/tundeclared_routine.nim b/tests/errmsgs/tundeclared_routine.nim index 2f1320fff..41b1d35f4 100644 --- a/tests/errmsgs/tundeclared_routine.nim +++ b/tests/errmsgs/tundeclared_routine.nim @@ -9,7 +9,7 @@ tundeclared_routine.nim(29, 28) Error: invalid pragma: myPragma tundeclared_routine.nim(36, 13) Error: undeclared field: 'bar3' for type tundeclared_routine.Foo [type declared in tundeclared_routine.nim(33, 8)] found tundeclared_routine.bar3() [iterator declared in tundeclared_routine.nim(35, 12)] tundeclared_routine.nim(41, 13) Error: undeclared field: 'bar4' for type tundeclared_routine.Foo [type declared in tundeclared_routine.nim(39, 8)] -tundeclared_routine.nim(44, 15) Error: attempting to call routine: 'bad5' +tundeclared_routine.nim(44, 11) Error: undeclared identifier: 'bad5' ''' """ diff --git a/tests/errmsgs/tuntypedoverload.nim b/tests/errmsgs/tuntypedoverload.nim new file mode 100644 index 000000000..1b1c2809c --- /dev/null +++ b/tests/errmsgs/tuntypedoverload.nim @@ -0,0 +1,37 @@ +discard """ + cmd: "nim check $file" +""" + +block: + template foo(x: var int, y: untyped) = discard + var a: float + foo(a, undeclared) #[tt.Error + ^ type mismatch: got <float, untyped>]# # `untyped` is arbitary + # previous error: undeclared identifier: 'undeclared' + +block: # issue #8697 + type + Fruit = enum + apple + banana + orange + macro hello(x, y: untyped) = discard + hello(apple, banana, orange) #[tt.Error + ^ type mismatch: got <Fruit, Fruit, Fruit>]# + +block: # issue #23265 + template declareFoo(fooName: untyped, value: uint16) = + const `fooName Value` {.inject.} = value + + declareFoo(FOO, 0xFFFF) + declareFoo(BAR, 0xFFFFF) #[tt.Error + ^ type mismatch: got <untyped, int literal(1048575)>]# + +block: # issue #9620 + template forLoop(index: untyped, length: int{lvalue}, body: untyped) = + for `index`{.inject.} in 0 ..< length: + body + var x = newSeq[int](10) + forLoop(i, x.len): #[tt.Error + ^ type mismatch: got <untyped, int, void>]# + x[i] = i diff --git a/tests/errmsgs/twrong_explicit_typeargs.nim b/tests/errmsgs/twrong_explicit_typeargs.nim new file mode 100644 index 000000000..5236e5f4f --- /dev/null +++ b/tests/errmsgs/twrong_explicit_typeargs.nim @@ -0,0 +1,26 @@ +discard """ + cmd: "nim c --hints:off -d:testsConciseTypeMismatch $file" + action: reject + nimout: ''' +twrong_explicit_typeargs.nim(26, 29) Error: type mismatch +Expression: newImage[string](320, 200) + [1] 320: int literal(320) + [2] 200: int literal(200) + +Expected one of (first mismatch at [position]): +[1] proc newImage[T: int32 | int64](w, h: int): ref Image[T] + generic parameter mismatch, expected int32 or int64 but got 'string' of type: string +''' +""" + +# bug #4084 +type + Image[T] = object + data: seq[T] + +proc newImage[T: int32|int64](w, h: int): ref Image[T] = + new(result) + result.data = newSeq[T](w * h) + +var correct = newImage[int32](320, 200) +var wrong = newImage[string](320, 200) diff --git a/tests/errmsgs/twrong_explicit_typeargs_legacy.nim b/tests/errmsgs/twrong_explicit_typeargs_legacy.nim new file mode 100644 index 000000000..cfa528c54 --- /dev/null +++ b/tests/errmsgs/twrong_explicit_typeargs_legacy.nim @@ -0,0 +1,25 @@ +discard """ + action: reject + nimout: ''' +twrong_explicit_typeargs_legacy.nim(25, 29) Error: type mismatch: got <int literal(320), int literal(200)> +but expected one of: +proc newImage[T: int32 | int64](w, h: int): ref Image[T] + first type mismatch at position: 1 in generic parameters + required type for T: int32 or int64 + but expression 'string' is of type: string + +expression: newImage[string](320, 200) +''' +""" + +# bug #4084 +type + Image[T] = object + data: seq[T] + +proc newImage[T: int32|int64](w, h: int): ref Image[T] = + new(result) + result.data = newSeq[T](w * h) + +var correct = newImage[int32](320, 200) +var wrong = newImage[string](320, 200) diff --git a/tests/generics/mopensymimport1.nim b/tests/generics/mopensymimport1.nim new file mode 100644 index 000000000..912db1302 --- /dev/null +++ b/tests/generics/mopensymimport1.nim @@ -0,0 +1,34 @@ +type + Result*[T, E] = object + when T is void: + when E is void: + oResultPrivate*: bool + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + discard + else: + when E is void: + case oResultPrivate*: bool + of false: + discard + of true: + vResultPrivate*: T + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + vResultPrivate*: T + +template valueOr*[T: not void, E](self: Result[T, E], def: untyped): untyped = + let s = (self) # TODO avoid copy + case s.oResultPrivate + of true: + s.vResultPrivate + of false: + when E isnot void: + template error: untyped {.used, inject.} = s.eResultPrivate + def diff --git a/tests/generics/mopensymimport2.nim b/tests/generics/mopensymimport2.nim new file mode 100644 index 000000000..c17aafd00 --- /dev/null +++ b/tests/generics/mopensymimport2.nim @@ -0,0 +1,16 @@ +{.experimental: "openSym".} + +import mopensymimport1 + +type Xxx = enum + error + value + +proc f(): Result[int, cstring] = + Result[int, cstring](oResultPrivate: false, eResultPrivate: "f") + +proc g*(T: type): string = + let x = f().valueOr: + return $error + + "ok" diff --git a/tests/generics/t19848.nim b/tests/generics/t19848.nim new file mode 100644 index 000000000..f80f0e298 --- /dev/null +++ b/tests/generics/t19848.nim @@ -0,0 +1,16 @@ +discard """ + output: ''' +todo +''' +""" + +type + Maybe[T] = object + List[T] = object + +proc dump[M: Maybe](a: List[M]) = + echo "todo" + +var a: List[Maybe[int]] + +dump(a) diff --git a/tests/generics/t23186.nim b/tests/generics/t23186.nim new file mode 100644 index 000000000..76f38da6b --- /dev/null +++ b/tests/generics/t23186.nim @@ -0,0 +1,155 @@ +# issue #23186 + +block: # simplified + template typedTempl(x: int, body): untyped = + body + proc generic1[T]() = + discard + proc generic2[T]() = + typedTempl(1): + let x = generic1[T] + generic2[int]() + +import std/macros + +when not compiles(len((1, 2))): + import std/typetraits + + func len(x: tuple): int = + arity(type(x)) + +block: # full issue example + type FieldDescription = object + name: NimNode + func isTuple(t: NimNode): bool = + t.kind == nnkBracketExpr and t[0].kind == nnkSym and eqIdent(t[0], "tuple") + proc collectFieldsFromRecList(result: var seq[FieldDescription], + n: NimNode, + parentCaseField: NimNode = nil, + parentCaseBranch: NimNode = nil, + isDiscriminator = false) = + case n.kind + of nnkRecList: + for entry in n: + collectFieldsFromRecList result, entry, + parentCaseField, parentCaseBranch + of nnkIdentDefs: + for i in 0 ..< n.len - 2: + var field: FieldDescription + field.name = n[i] + if field.name.kind == nnkPragmaExpr: + field.name = field.name[0] + if field.name.kind == nnkPostfix: + field.name = field.name[1] + result.add field + of nnkNilLit, nnkDiscardStmt, nnkCommentStmt, nnkEmpty: + discard + else: + doAssert false, "Unexpected nodes in recordFields:\n" & n.treeRepr + proc collectFieldsInHierarchy(result: var seq[FieldDescription], + objectType: NimNode) = + var objectType = objectType + if objectType.kind == nnkRefTy: + objectType = objectType[0] + let recList = objectType[2] + collectFieldsFromRecList result, recList + proc recordFields(typeImpl: NimNode): seq[FieldDescription] = + let objectType = case typeImpl.kind + of nnkObjectTy: typeImpl + of nnkTypeDef: typeImpl[2] + else: + macros.error("object type expected", typeImpl) + return + collectFieldsInHierarchy(result, objectType) + proc skipPragma(n: NimNode): NimNode = + if n.kind == nnkPragmaExpr: n[0] + else: n + func declval(T: type): T = + doAssert false, + "declval should be used only in `typeof` expressions and concepts" + default(ptr T)[] + macro enumAllSerializedFieldsImpl(T: type, body: untyped): untyped = + var typeAst = getType(T)[1] + var typeImpl: NimNode + let isSymbol = not typeAst.isTuple + if not isSymbol: + typeImpl = typeAst + else: + typeImpl = getImpl(typeAst) + result = newStmtList() + var i = 0 + for field in recordFields(typeImpl): + let + fieldIdent = field.name + realFieldName = newLit($fieldIdent.skipPragma) + fieldName = realFieldName + fieldIndex = newLit(i) + let fieldNameDefs = + if isSymbol: + quote: + const fieldName {.inject, used.} = `fieldName` + const realFieldName {.inject, used.} = `realFieldName` + else: + quote: + const fieldName {.inject, used.} = $`fieldIndex` + const realFieldName {.inject, used.} = $`fieldIndex` + # we can't access .Fieldn, so our helper knows + # to parseInt this + let field = + if isSymbol: + quote do: declval(`T`).`fieldIdent` + else: + quote do: declval(`T`)[`fieldIndex`] + result.add quote do: + block: + `fieldNameDefs` + type FieldType {.inject, used.} = type(`field`) + `body` + i += 1 + template enumAllSerializedFields(T: type, body): untyped = + when T is ref|ptr: + type TT = type(default(T)[]) + enumAllSerializedFieldsImpl(TT, body) + else: + enumAllSerializedFieldsImpl(T, body) + type + MemRange = object + startAddr: ptr byte + length: int + SszNavigator[T] = object + m: MemRange + func sszMount(data: openArray[byte], T: type): SszNavigator[T] = + let startAddr = unsafeAddr data[0] + SszNavigator[T](m: MemRange(startAddr: startAddr, length: data.len)) + func sszMount(data: openArray[char], T: type): SszNavigator[T] = + let startAddr = cast[ptr byte](unsafeAddr data[0]) + SszNavigator[T](m: MemRange(startAddr: startAddr, length: data.len)) + template sszMount(data: MemRange, T: type): SszNavigator[T] = + SszNavigator[T](m: data) + func navigateToField[T]( + n: SszNavigator[T], + FieldType: type): SszNavigator[FieldType] = + default(SszNavigator[FieldType]) + type + FieldInfo = ref object + navigator: proc (m: MemRange): MemRange {. + gcsafe, noSideEffect, raises: [IOError] .} + func fieldNavigatorImpl[RecordType; FieldType; fieldName: static string]( + m: MemRange): MemRange = + var typedNavigator = sszMount(m, RecordType) + discard navigateToField(typedNavigator, FieldType) + default(MemRange) + func genTypeInfo(T: type) = + when T is object: + enumAllSerializedFields(T): + discard FieldInfo(navigator: fieldNavigatorImpl[T, FieldType, fieldName]) + type + Foo = object + bar: Bar + BarList = seq[uint64] + Bar = object + b: BarList + baz: Baz + Baz = object + i: uint64 + genTypeInfo(Foo) diff --git a/tests/generics/t23790.nim b/tests/generics/t23790.nim new file mode 100644 index 000000000..9ac0df6a1 --- /dev/null +++ b/tests/generics/t23790.nim @@ -0,0 +1,14 @@ +# bug #23790 + +discard compiles($default(seq[seq[ref int]])) +discard compiles($default(seq[seq[ref uint]])) +discard compiles($default(seq[seq[ref int8]])) +discard compiles($default(seq[seq[ref uint8]])) +discard compiles($default(seq[seq[ref int16]])) +discard compiles($default(seq[seq[ref uint16]])) +discard compiles($default(seq[seq[ref int32]])) +discard compiles($default(seq[seq[ref uint32]])) +discard compiles($default(seq[seq[ref int64]])) +discard compiles($default(seq[seq[ref uint64]])) +proc s(_: int | string) = discard +s(0) diff --git a/tests/generics/t23853.nim b/tests/generics/t23853.nim new file mode 100644 index 000000000..bc9514a53 --- /dev/null +++ b/tests/generics/t23853.nim @@ -0,0 +1,91 @@ +# issue #23853 + +block simplified: + type QuadraticExt[F] = object + coords: array[2, F] + template Name(E: type QuadraticExt): int = 123 + template getBigInt(Name: static int): untyped = int + type Foo[GT] = object + a: getBigInt(GT.Name) + var x: Foo[QuadraticExt[int]] + +import std/macros + +type + Algebra* = enum + BN254_Snarks + BLS12_381 + + Fp*[Name: static Algebra] = object + limbs*: array[4, uint64] + + QuadraticExt*[F] = object + ## Quadratic Extension field + coords*: array[2, F] + + CubicExt*[F] = object + ## Cubic Extension field + coords*: array[3, F] + + ExtensionField*[F] = QuadraticExt[F] or CubicExt[F] + + Fp2*[Name: static Algebra] = + QuadraticExt[Fp[Name]] + + Fp4*[Name: static Algebra] = + QuadraticExt[Fp2[Name]] + + Fp6*[Name: static Algebra] = + CubicExt[Fp2[Name]] + + Fp12*[Name: static Algebra] = + CubicExt[Fp4[Name]] + # QuadraticExt[Fp6[Name]] + +template Name*(E: type ExtensionField): Algebra = + E.F.Name + +const BLS12_381_Order = [uint64 0x1, 0x2, 0x3, 0x4] +const BLS12_381_Modulus = [uint64 0x5, 0x6, 0x7, 0x8] + + +{.experimental: "dynamicBindSym".} + +macro baseFieldModulus*(Name: static Algebra): untyped = + result = bindSym($Name & "_Modulus") + +macro scalarFieldModulus*(Name: static Algebra): untyped = + result = bindSym($Name & "_Order") + +type FieldKind* = enum + kBaseField + kScalarField + +template getBigInt*(Name: static Algebra, kind: static FieldKind): untyped = + # Workaround: + # in `ptr UncheckedArray[BigInt[EC.getScalarField().bits()]] + # EC.getScalarField is not accepted by the compiler + # + # and `ptr UncheckedArray[BigInt[Fr[EC.F.Name].bits]]` gets undeclared field: 'Name' + # + # but `ptr UncheckedArray[getBigInt(EC.getName(), kScalarField)]` works fine + when kind == kBaseField: + Name.baseFieldModulus().typeof() + else: + Name.scalarFieldModulus().typeof() + +# ------------------------------------------------------------------------------ + +type BenchMultiexpContext*[GT] = object + elems: seq[GT] + exponents: seq[getBigInt(GT.Name, kScalarField)] + +proc createBenchMultiExpContext*(GT: typedesc, inputSizes: openArray[int]): BenchMultiexpContext[GT] = + discard + +# ------------------------------------------------------------------------------ + +proc main() = + let ctx = createBenchMultiExpContext(Fp12[BLS12_381], [2, 4, 8, 16]) + +main() diff --git a/tests/generics/t23854.nim b/tests/generics/t23854.nim new file mode 100644 index 000000000..f1175c8b2 --- /dev/null +++ b/tests/generics/t23854.nim @@ -0,0 +1,71 @@ +# issue #23854, not entirely fixed + +import std/bitops + +const WordBitWidth = sizeof(pointer) * 8 + +func wordsRequired*(bits: int): int {.inline.} = + const divShiftor = fastLog2(uint32(WordBitWidth)) + result = (bits + WordBitWidth - 1) shr divShiftor + +type + Algebra* = enum + BLS12_381 + + BigInt*[bits: static int] = object + limbs*: array[wordsRequired(bits), uint] + + Fr*[Name: static Algebra] = object + residue_form*: BigInt[255] + + Fp*[Name: static Algebra] = object + residue_form*: BigInt[381] + + FF*[Name: static Algebra] = Fp[Name] or Fr[Name] + +template getBigInt*[Name: static Algebra](T: type FF[Name]): untyped = + ## Get the underlying BigInt type. + typeof(default(T).residue_form) + +type + EC_ShortW_Aff*[F] = object + ## Elliptic curve point for a curve in Short Weierstrass form + ## y² = x³ + a x + b + ## + ## over a field F + x*, y*: F + +type FieldKind* = enum + kBaseField + kScalarField + +func bits*[Name: static Algebra](T: type FF[Name]): static int = + T.getBigInt().bits + +template getScalarField*(EC: type EC_ShortW_Aff): untyped = + Fr[EC.F.Name] + +# ------------------------------------------------------------------------------ + +type + ECFFT_Descriptor*[EC] = object + ## Metadata for FFT on Elliptic Curve + order*: int + rootsOfUnity1*: ptr UncheckedArray[BigInt[EC.getScalarField().bits()]] # Error: in expression 'EC.getScalarField()': identifier expected, but found 'EC.getScalarField' + rootsOfUnity2*: ptr UncheckedArray[BigInt[getScalarField(EC).bits()]] # Compiler SIGSEGV: Illegal Storage Access + +func new*(T: type ECFFT_Descriptor): T = + discard + +# ------------------------------------------------------------------------------ + +template getBits[bits: static int](x: ptr UncheckedArray[BigInt[bits]]): int = bits + +proc main() = + let ctx = ECFFT_Descriptor[EC_ShortW_Aff[Fp[BLS12_381]]].new() + doAssert getBits(ctx.rootsOfUnity1) == 255 + doAssert getBits(ctx.rootsOfUnity2) == 255 + doAssert ctx.rootsOfUnity1[0].limbs.len == wordsRequired(255) + doAssert ctx.rootsOfUnity2[0].limbs.len == wordsRequired(255) + +main() diff --git a/tests/generics/t23855.nim b/tests/generics/t23855.nim new file mode 100644 index 000000000..da8135a98 --- /dev/null +++ b/tests/generics/t23855.nim @@ -0,0 +1,61 @@ +# issue #23855, not entirely fixed + +import std/bitops + +const WordBitWidth = sizeof(pointer) * 8 + +func wordsRequired*(bits: int): int {.inline.} = + const divShiftor = fastLog2(uint32(WordBitWidth)) + result = (bits + WordBitWidth - 1) shr divShiftor + +type + Algebra* = enum + BLS12_381 + + BigInt*[bits: static int] = object + limbs*: array[wordsRequired(bits), uint] + + Fr*[Name: static Algebra] = object + residue_form*: BigInt[255] + + Fp*[Name: static Algebra] = object + residue_form*: BigInt[381] + + FF*[Name: static Algebra] = Fp[Name] or Fr[Name] + +template getBigInt*[Name: static Algebra](T: type FF[Name]): untyped = + ## Get the underlying BigInt type. + typeof(default(T).residue_form) + +type + EC_ShortW_Aff*[F] = object + ## Elliptic curve point for a curve in Short Weierstrass form + ## y² = x³ + a x + b + ## + ## over a field F + x*, y*: F + +func bits*[Name: static Algebra](T: type FF[Name]): static int = + T.getBigInt().bits + +# ------------------------------------------------------------------------------ + +type + ECFFT_Descriptor*[EC] = object + ## Metadata for FFT on Elliptic Curve + order*: int + rootsOfUnity*: ptr UncheckedArray[BigInt[Fr[EC.F.Name].bits()]] # Undeclared identifier `Name` + +func new*(T: type ECFFT_Descriptor): T = + discard + +# ------------------------------------------------------------------------------ + +template getBits[bits: static int](x: ptr UncheckedArray[BigInt[bits]]): int = bits + +proc main() = + let ctx = ECFFT_Descriptor[EC_ShortW_Aff[Fp[BLS12_381]]].new() + doAssert getBits(ctx.rootsOfUnity) == 255 + doAssert ctx.rootsOfUnity[0].limbs.len == wordsRequired(255) + +main() diff --git a/tests/generics/t6137.nim b/tests/generics/t6137.nim index 991f39dd1..fb7db22f8 100644 --- a/tests/generics/t6137.nim +++ b/tests/generics/t6137.nim @@ -1,6 +1,6 @@ discard """ - errormsg: "\'vectFunc\' doesn't have a concrete type, due to unspecified generic parameters." - line: 28 + errormsg: "cannot instantiate: 'T'" + line: 19 """ type diff --git a/tests/generics/taliashijack.nim b/tests/generics/taliashijack.nim new file mode 100644 index 000000000..fdebadded --- /dev/null +++ b/tests/generics/taliashijack.nim @@ -0,0 +1,8 @@ +# issue #23977 + +type Foo[T] = int + +proc foo(T: typedesc) = + var a: T + +foo(int) diff --git a/tests/generics/tbadcache.nim b/tests/generics/tbadcache.nim new file mode 100644 index 000000000..33e65be3a --- /dev/null +++ b/tests/generics/tbadcache.nim @@ -0,0 +1,26 @@ +# issue #16128 + +import std/[tables, hashes] + +type + NodeId*[L] = object + isSource: bool + index: Table[NodeId[L], seq[NodeId[L]]] + +func hash*[L](id: NodeId[L]): Hash = discard +func `==`[L](a, b: NodeId[L]): bool = discard + +proc makeIndex*[T, L](tree: T) = + var parent = NodeId[L]() + var tmp: Table[NodeId[L], seq[NodeId[L]]] + tmp[parent] = @[parent] + +proc simpleTreeDiff*[T, L](source, target: T) = + # Swapping these two lines makes error disappear + var m: Table[NodeId[L], NodeId[L]] + makeIndex[T, L](target) + +var tmp: Table[string, seq[string]] # removing this forward declaration also removes error + +proc diff(x1, x2: string): auto = + simpleTreeDiff[int, string](12, 12) diff --git a/tests/generics/tbracketinstantiation.nim b/tests/generics/tbracketinstantiation.nim new file mode 100644 index 000000000..22a86af4c --- /dev/null +++ b/tests/generics/tbracketinstantiation.nim @@ -0,0 +1,86 @@ +discard """ + nimout: ''' +type + Bob = object +type + Another = object +''' +""" + +block: # issue #22645 + type + Opt[T] = object + FutureBase = ref object of RootObj + Future[T] = ref object of FutureBase ## Typed future. + internalValue: T ## Stored value + template err[T](E: type Opt[T]): E = E() + proc works(): Future[Opt[int]] {.stackTrace: off, gcsafe, raises: [].} = + var chronosInternalRetFuture: FutureBase + template result(): untyped {.used.} = + Future[Opt[int]](chronosInternalRetFuture).internalValue + result = err(type(result)) + proc breaks(): Future[Opt[int]] {.stackTrace: off, gcsafe, raises: [].} = + var chronosInternalRetFuture: FutureBase + template result(): untyped {.used.} = + cast[Future[Opt[int]]](chronosInternalRetFuture).internalValue + result = err(type(result)) + +import macros + +block: # issue #16118 + macro thing(name: static[string]) = + result = newStmtList( + nnkTypeSection.newTree( + nnkTypeDef.newTree( + ident(name), + newEmptyNode(), + nnkObjectTy.newTree( + newEmptyNode(), + newEmptyNode(), + nnkRecList.newTree())))) + template foo(name: string): untyped = + thing(name) + expandMacros: + foo("Bob") + block: + expandMacros: + foo("Another") + +block: # issue #19670 + type + Past[Z] = object + OpenObject = object + + macro rewriter(prc: untyped): untyped = + prc.body.add(nnkCall.newTree( + prc.params[0] + )) + prc + + macro macroAsync(name, restype: untyped): untyped = + quote do: + proc `name`(): Past[seq[`restype`]] {.rewriter.} = discard + + macroAsync(testMacro, OpenObject) + +import asyncdispatch + +block: # issue #11838 long + type + R[P] = object + updates: seq[P] + D[T, P] = ref object + ps: seq[P] + t: T + proc newD[T, P](ps: seq[P], t: T): D[T, P] = + D[T, P](ps: ps, t: t) + proc loop[T, P](d: D[T, P]) = + var results = newSeq[Future[R[P]]](10) + let d = newD[string, int](@[1], "") + d.loop() + +block: # issue #11838 minimal + type R[T] = object + proc loop[T]() = + discard newSeq[R[R[T]]]() + loop[int]() diff --git a/tests/generics/tcalltype.nim b/tests/generics/tcalltype.nim new file mode 100644 index 000000000..cba691f77 --- /dev/null +++ b/tests/generics/tcalltype.nim @@ -0,0 +1,26 @@ +discard """ + joinable: false # breaks everything because of #23977 +""" + +# issue #23406 + +template helper(_: untyped): untyped = + int + +type # Each of them should always be `int`. + GenA[T] = helper int + GenB[T] = helper(int) + GenC[T] = helper helper(int) + +block: + template helper(_: untyped): untyped = + float + + type + A = GenA[int] + B = GenB[int] + C = GenC[int] + + assert A is int # OK. + assert B is int # Fails; it is `float`! + assert C is int # OK. diff --git a/tests/generics/tgeneric0.nim b/tests/generics/tgeneric0.nim index b5e1c4bb4..16a148f7b 100644 --- a/tests/generics/tgeneric0.nim +++ b/tests/generics/tgeneric0.nim @@ -9,7 +9,7 @@ float32 """ -import tables +import std/tables block tgeneric0: @@ -166,3 +166,31 @@ type # bug #8295 var x = AtomicContainer[int]() doAssert (ptr Block[int])(x.b) == nil + + +# bug #23233 +type + JsonObjectType*[T: string or uint64] = Table[string, JsonValueRef[T]] + + JsonValueRef*[T: string or uint64] = object + objVal*: JsonObjectType[T] + +proc scanValue[K](val: var K) = + var map: JsonObjectType[K.T] + var newVal: K + map["one"] = newVal + +block: + var a: JsonValueRef[uint64] + scanValue(a) + + var b: JsonValueRef[string] + scanValue(b) + +block: # bug #21347 + type K[T] = object + template s[T]() = discard + proc b1(n: bool | bool) = s[K[K[int]]]() + proc b2(n: bool) = s[K[K[int]]]() + b1(false) # Error: 's' has unspecified generic parameters + b2(false) # Builds, on its own diff --git a/tests/generics/tgenericwhen.nim b/tests/generics/tgenericwhen.nim new file mode 100644 index 000000000..87672a699 --- /dev/null +++ b/tests/generics/tgenericwhen.nim @@ -0,0 +1,58 @@ +discard """ + targets: "c js" +""" + +block: # issue #24041 + type ArrayBuf[N: static int, T = byte] = object + when sizeof(int) > sizeof(uint8): + when N <= int(uint8.high): + n: uint8 + else: + when sizeof(int) > sizeof(uint16): + when N <= int(uint16.high): + n: uint16 + else: + when sizeof(int) > sizeof(uint32): + when N <= int(uint32.high): + n: uint32 + else: + n: int + else: + n: int + else: + n: int + else: + n: int + + var x: ArrayBuf[8] + doAssert x.n is uint8 + when sizeof(int) > sizeof(uint32): + var y: ArrayBuf[int(uint32.high) * 8] + doAssert y.n is int + +block: # constant condition after dynamic one + type Foo[T] = object + when T is int: + a: int + elif true: + a: string + else: + a: bool + var x: Foo[string] + doAssert x.a is string + var y: Foo[int] + doAssert y.a is int + var z: Foo[float] + doAssert z.a is string + +block: # issue #4774, but not with threads + const hasThreadSupport = not defined(js) + when hasThreadSupport: + type Channel[T] = object + value: T + type + SomeObj[T] = object + when hasThreadSupport: + channel: ptr Channel[T] + var x: SomeObj[int] + doAssert compiles(x.channel) == hasThreadSupport diff --git a/tests/generics/tgensyminst.nim b/tests/generics/tgensyminst.nim new file mode 100644 index 000000000..3f30188d8 --- /dev/null +++ b/tests/generics/tgensyminst.nim @@ -0,0 +1,29 @@ +# issue #24048 + +import macros + +proc map(fn: proc(val: int): void) = fn(1) + +# This works fine, and is the exact same function call as what's +# generated by the macro `aBug`. +map proc(val: auto): void = + let variable = 123 + +macro aBug() = + # 1. let sym = ident("variable") + let sym = genSym(nskLet, "variable") + let letStmt = newLetStmt(sym, newLit(123)) + + let lambda = newProc( + params = @[ + ident("void"), + newIdentDefs(ident("val"), ident("auto")), + # 2. newIdentDefs(ident("val"), ident("int")), + ], + body = newStmtList(letStmt), + procType = nnkLambda + ) + + result = newCall(bindSym("map"), lambda) + +aBug() diff --git a/tests/generics/timplicit_and_explicit.nim b/tests/generics/timplicit_and_explicit.nim index fe61004e4..7220b7429 100644 --- a/tests/generics/timplicit_and_explicit.nim +++ b/tests/generics/timplicit_and_explicit.nim @@ -3,8 +3,8 @@ block: # basic test proc doStuff[T](a: SomeInteger): T = discard proc doStuff[T;Y](a: SomeInteger, b: Y): Y = discard assert typeof(doStuff[int](100)) is int - assert typeof(doStuff[int](100, 1.0)) is float - assert typeof(doStuff[int](100, "Hello")) is string + assert typeof(doStuff[int, float](100, 1.0)) is float + assert typeof(doStuff[int, string](100, "Hello")) is string proc t[T](x: T; z: int | float): seq[T] = result.add(x & $z) @@ -34,7 +34,8 @@ block: #15622 proc test1[T](a: T, b: static[string] = "") = discard test1[int64](123) proc test2[T](a: T, b: static[string] = "") = discard - test2[int64, static[string]](123) + doAssert not (compiles do: + test2[int64, static[string]](123)) block: #4688 proc convertTo[T](v: int or float): T = (T)(v) diff --git a/tests/generics/tmacroinjectedsym.nim b/tests/generics/tmacroinjectedsym.nim new file mode 100644 index 000000000..985e415f2 --- /dev/null +++ b/tests/generics/tmacroinjectedsym.nim @@ -0,0 +1,186 @@ +{.experimental: "openSym".} + +block: # issue #22605, normal call syntax + const error = "bad" + + template valueOr(self: int, def: untyped): untyped = + case false + of true: "" + of false: + template error: untyped {.used, inject.} = "good" + def + + proc g(T: type): string = + let x = valueOr 123: + return $error + + "ok" + + doAssert g(int) == "good" + + proc g2(T: type): string = + bind error # use the bad version on purpose + let x = valueOr 123: + return $error + + "ok" + + doAssert g2(int) == "bad" + +block: # issue #22605, method call syntax + const error = "bad" + + template valueOr(self: int, def: untyped): untyped = + case false + of true: "" + of false: + template error: untyped {.used, inject.} = "good" + def + + proc g(T: type): string = + let x = 123.valueOr: + return $error + + "ok" + + doAssert g(int) == "good" + + proc g2(T: type): string = + bind error # use the bad version on purpose + let x = 123.valueOr: + return $error + + "ok" + + doAssert g2(int) == "bad" + +block: # issue #22605, original complex example + type Xxx = enum + error + value + + type + Result[T, E] = object + when T is void: + when E is void: + oResultPrivate*: bool + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + discard + else: + when E is void: + case oResultPrivate*: bool + of false: + discard + of true: + vResultPrivate*: T + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + vResultPrivate*: T + + template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped = + let s = (self) # TODO avoid copy + case s.oResultPrivate + of true: + s.vResultPrivate + of false: + when E isnot void: + template error: untyped {.used, inject.} = s.eResultPrivate + def + + proc f(): Result[int, cstring] = + Result[int, cstring](oResultPrivate: false, eResultPrivate: "f") + + proc g(T: type): string = + let x = f().valueOr: + return $error + + "ok" + + doAssert g(int) == "f" + + proc g2(T: type): string = + bind error # use the bad version on purpose + let x = f().valueOr: + return $error + + "ok" + + doAssert g2(int) == "error" + +block: # issue #23865 + type Xxx = enum + error + value + + type + Result[T, E] = object + when T is void: + when E is void: + oResultPrivate: bool + else: + case oResultPrivate: bool + of false: + eResultPrivate: E + of true: + discard + else: + when E is void: + case oResultPrivate: bool + of false: + discard + of true: + vResultPrivate: T + else: + case oResultPrivate: bool + of false: + eResultPrivate: E + of true: + vResultPrivate: T + + func error[T, E](self: Result[T, E]): E = + ## Fetch error of result if set, or raise Defect + case self.oResultPrivate + of true: + when T isnot void: + raiseResultDefect("Trying to access error when value is set", self.vResultPrivate) + else: + raiseResultDefect("Trying to access error when value is set") + of false: + when E isnot void: + self.eResultPrivate + + template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped = + let s = (self) # TODO avoid copy + case s.oResultPrivate + of true: + s.vResultPrivate + of false: + when E isnot void: + template error: untyped {.used, inject.} = s.eResultPrivate + def + proc f(): Result[int, cstring] = + Result[int, cstring](oResultPrivate: false, eResultPrivate: "f") + proc g(T: type): string = + let x = f().valueOr: + return $error + "ok" + doAssert g(int) == "f" + +import sequtils + +block: # issue #12283 + var b = 5 + type Foo[T] = object + h, w: int + proc bar[T](foos: seq[Foo[T]]): T = + let w = foldl(foos, a + b.w, 0) + w + let foos = @[Foo[int](h: 3, w: 5), Foo[int](h: 4, w: 6)] + doAssert bar(foos) == 11 diff --git a/tests/generics/tmacroinjectedsymwarning.nim b/tests/generics/tmacroinjectedsymwarning.nim new file mode 100644 index 000000000..77119004b --- /dev/null +++ b/tests/generics/tmacroinjectedsymwarning.nim @@ -0,0 +1,59 @@ +discard """ + matrix: "--skipParentCfg --filenames:legacyRelProj" +""" + +type Xxx = enum + error + value + +type + Result[T, E] = object + when T is void: + when E is void: + oResultPrivate*: bool + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + discard + else: + when E is void: + case oResultPrivate*: bool + of false: + discard + of true: + vResultPrivate*: T + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + vResultPrivate*: T + +template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped = + let s = (self) # TODO avoid copy + case s.oResultPrivate + of true: + s.vResultPrivate + of false: + when E isnot void: + template error: untyped {.used, inject.} = s.eResultPrivate + def + +proc f(): Result[int, cstring] = + Result[int, cstring](oResultPrivate: false, eResultPrivate: "f") + +proc g(T: type): string = + let x = f().valueOr: + {.push warningAsError[IgnoredSymbolInjection]: on.} + # test spurious error + discard true + let _ = f + {.pop.} + return $error #[tt.Warning + ^ a new symbol 'error' has been injected during template or generic instantiation, however 'error' [enumField declared in tmacroinjectedsymwarning.nim(6, 3)] captured at the proc declaration will be used instead; either enable --experimental:openSym to use the injected symbol, or `bind` this captured symbol explicitly [IgnoredSymbolInjection]]# + + "ok" + +discard g(int) diff --git a/tests/generics/tnestedissues.nim b/tests/generics/tnestedissues.nim new file mode 100644 index 000000000..e96a1927e --- /dev/null +++ b/tests/generics/tnestedissues.nim @@ -0,0 +1,24 @@ +block: # issue #23568 + type G[T] = object + j: T + proc s[T](u: int) = discard + proc s[T]() = discard + proc c(e: int | int): G[G[G[int]]] = s[G[G[int]]]() + discard c(0) + +import std/options + +block: # issue #23310 + type + BID = string or uint64 + Future[T] = ref object of RootObj + internalValue: T + InternalRaisesFuture[T] = ref object of Future[T] + proc newInternalRaisesFutureImpl[T](): InternalRaisesFuture[T] = + let fut = InternalRaisesFuture[T]() + template newFuture[T](): auto = + newInternalRaisesFutureImpl[T]() + proc problematic(blockId: BID): Future[Option[seq[int]]] = + let resultFuture = newFuture[Option[seq[int]]]() + return resultFuture + let x = problematic("latest") diff --git a/tests/generics/tnestedtemplate.nim b/tests/generics/tnestedtemplate.nim new file mode 100644 index 000000000..22d0a2d3c --- /dev/null +++ b/tests/generics/tnestedtemplate.nim @@ -0,0 +1,9 @@ +block: # issue #13979 + var s: seq[int] + proc filterScanline[T](input: openArray[T]) = + template currPix: untyped = input[i] + for i in 0..<input.len: + s.add currPix + let pix = [1, 2, 3] + filterScanline(pix) + doAssert s == @[1, 2, 3] diff --git a/tests/generics/topensymimport.nim b/tests/generics/topensymimport.nim new file mode 100644 index 000000000..a47496827 --- /dev/null +++ b/tests/generics/topensymimport.nim @@ -0,0 +1,5 @@ +# issue #23386 + +import mopensymimport2 + +doAssert g(int) == "f" diff --git a/tests/generics/tstatic_constrained.nim b/tests/generics/tstatic_constrained.nim index 3c9201548..d356b9d1c 100644 --- a/tests/generics/tstatic_constrained.nim +++ b/tests/generics/tstatic_constrained.nim @@ -8,7 +8,7 @@ but expected: <T: float or string, Y> tstatic_constrained.nim(44, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)] got: <typedesc[int], int literal(10)> but expected: <T: float or string, Y> -tstatic_constrained.nim(44, 31) Error: object constructor needs an object type [proxy] +tstatic_constrained.nim(44, 31) Error: object constructor needs an object type [error] tstatic_constrained.nim(44, 31) Error: expression '' has no type (or is ambiguous) tstatic_constrained.nim(45, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)] got: <typedesc[byte], uint8> @@ -16,7 +16,7 @@ but expected: <T: float or string, Y> tstatic_constrained.nim(45, 22) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(30, 5)] got: <typedesc[byte], uint8> but expected: <T: float or string, Y> -tstatic_constrained.nim(45, 34) Error: object constructor needs an object type [proxy] +tstatic_constrained.nim(45, 34) Error: object constructor needs an object type [error] tstatic_constrained.nim(45, 34) Error: expression '' has no type (or is ambiguous) tstatic_constrained.nim(77, 14) Error: cannot instantiate MyType [type declared in tstatic_constrained.nim(71, 5)] got: <typedesc[float], float64> @@ -76,4 +76,4 @@ block: b: MyType[string, "hello"] c: MyType[float, 10d] d: MyOtherType[MyOtherConstraint[float],MyOtherConstraint[float]()] - e: MyOtherType[MyOtherConstraint[int], MyOtherConstraint[int]()] \ No newline at end of file + e: MyOtherType[MyOtherConstraint[int], MyOtherConstraint[int]()] diff --git a/tests/generics/tuninstantiatedgenericcalls.nim b/tests/generics/tuninstantiatedgenericcalls.nim index bac334e95..f33fc8967 100644 --- a/tests/generics/tuninstantiatedgenericcalls.nim +++ b/tests/generics/tuninstantiatedgenericcalls.nim @@ -140,3 +140,378 @@ block: # issue #1771 var a: Foo[range[0..2], float] doAssert test(a) == 0.0 + +block: # issue #23730 + proc test(M: static[int]): array[1 shl M, int] = discard + doAssert len(test(3)) == 8 + doAssert len(test(5)) == 32 + +block: # issue #19819 + type + Example[N: static int] = distinct int + What[E: Example] = Example[E.N + E.N] + +block: # issue #23339 + type + A = object + B = object + template aToB(t: typedesc[A]): typedesc = B + type + Inner[I] = object + innerField: I + Outer[O] = object + outerField: Inner[O.aToB] + var x: Outer[A] + doAssert typeof(x.outerField.innerField) is B + +block: # deref syntax + type + Enqueueable = concept x + x is ptr + Foo[T: Enqueueable] = object + x: typeof(default(T)[]) + + proc p[T](f: Foo[T]) = + var bar: Foo[T] + discard + var foo: Foo[ptr int] + p(foo) + doAssert foo.x is int + foo.x = 123 + doAssert foo.x == 123 + inc foo.x + doAssert foo.x == 124 + +block: + type Generic[T] = object + field: T + macro foo(x: typed): untyped = x + macro bar[T](x: typedesc[Generic[T]]): untyped = x + type + Foo[T] = object + field: Generic[int].foo() + Foo2[T] = object + field: Generic[T].foo() + Bar[T] = object + field: Generic[int].bar() + Bar2[T] = object + field: Generic[T].bar() + var x: Foo[int] + var x2: Foo2[int] + var y: Bar[int] + var y2: Bar2[int] + +block: + macro pick(x: static int): untyped = + if x < 100: + result = bindSym"int" + else: + result = bindSym"float" + + type Foo[T: static int] = object + fixed1: pick(25) + fixed2: pick(125) + unknown: pick(T) + + var a: Foo[123] + doAssert a.fixed1 is int + doAssert a.fixed2 is float + doAssert a.unknown is float + var b: Foo[23] + doAssert b.fixed1 is int + doAssert b.fixed2 is float + doAssert b.unknown is int + +import std/sequtils + +block: # version of #23432 with `typed`, don't delay instantiation + type + Future[T] = object + InternalRaisesFuture[T, E] = object + macro Raising[T](F: typedesc[Future[T]], E: varargs[typed]): untyped = + let raises = nnkTupleConstr.newTree(E.mapIt(it)) + nnkBracketExpr.newTree( + ident "InternalRaisesFuture", + nnkDotExpr.newTree(F, ident"T"), + raises + ) + type X[E] = Future[void].Raising(E) + proc f(x: X) = discard + var v: Future[void].Raising([ValueError]) + f(v) + +block: # issue #22647 + proc c0(n: static int): int = 8 + proc c1(n: static int): int = n div 2 + proc c2(n: static int): int = n * 2 + proc c3(n: static int, n2: int): int = n * n2 + proc `**`(n: static int, n2: int): int = n * n2 + proc c4(n: int, n2: int): int = n * n2 + + type + a[N: static int] = object + f0 : array[N, int] + + b[N: static int] = object + f0 : a[c0(N)] # does not work + f1 : a[c1(N)] # does not work + f2 : a[c2(N)] # does not work + f3 : a[N * 2] # does not work + f4 : a[N] # works + f5: a[c3(N, 2)] + f6: a[N ** 2] + f7: a[2 * N] + f8: a[c4(N, 2)] + + proc p[N: static int](x : a[N]) = discard x.f0[0] + template check(x, s: untyped) = + p(x) + doAssert x is a[s] + doAssert x.N == s + doAssert typeof(x).N == s + doAssert x.f0 == default(array[s, int]) + doAssert x.f0.len == s + proc p2[N: static int](y : a[N]) {.gensym.} = + doAssert y is a[s] + doAssert y.N == s + doAssert typeof(y).N == s + doAssert y.f0 == default(array[s, int]) + doAssert y.f0.len == s + p2(x) + proc p3(z: typeof(x)) {.gensym.} = discard + p3(default(a[s])) + proc p[N: static int](x : b[N]) = + x.f0.check(8) + x.f1.check(2) + x.f2.check(8) + x.f3.check(8) + x.f4.check(4) + x.f5.check(8) + x.f6.check(8) + x.f7.check(8) + x.f8.check(8) + + var x: b[4] + x.p() + +block: # issue #1969 + type ZeroGenerator = object + proc next(g: ZeroGenerator): int = 0 + # This compiles. + type TripleOfInts = tuple + a, b, c: typeof(new(ZeroGenerator)[].next) + # This raises a compiler error before it's even instantiated. + # The `new` proc can't be resolved because `Generator` is not defined. + type TripleLike[Generator] = tuple + a, b, c: typeof(new(Generator)[].next) + +import std/atomics + +block: # issue #12720 + const CacheLineSize = 128 + type + Enqueueable = concept x, type T + x is ptr + x.next is Atomic[pointer] + MyChannel[T: Enqueueable] = object + pad: array[CacheLineSize - sizeof(default(T)[]), byte] + dummy: typeof(default(T)[]) + +block: # issue #12714 + type + Enqueueable = concept x, type T + x is ptr + x.next is Atomic[pointer] + MyChannel[T: Enqueueable] = object + dummy: type(default(T)[]) + +block: # issue #24044 + type ArrayBuf[N: static int, T = byte] = object + buf: array[N, T] + template maxLen(T: type): int = + sizeof(T) * 2 + type MyBuf[I] = ArrayBuf[maxLen(I)] + var v: MyBuf[int] + +block: # issue #15959 + proc my[T](a: T): typeof(a[0]) = discard + proc my2[T](a: T): array[sizeof(a[0]), T] = discard + proc byLent2[T](a: T): lent type(a[0]) = a[0] # Error: type mismatch: got <T, int literal(0)> + proc byLent3[T](a: T): lent typeof(a[0]) = a[0] # ditto + proc byLent4[T](a: T): lent[type(a[0])] = a[0] # Error: no generic parameters allowed for lent + var x = @[1, 2, 3] + doAssert my(x) is int + doAssert my2(x) is array[sizeof(int), seq[int]] + doAssert byLent2(x) == 1 + doAssert byLent2(x) is lent int + doAssert byLent3(x) == 1 + doAssert byLent3(x) is lent int + doAssert byLent4(x) == 1 + doAssert byLent4(x) is lent int + proc fn[U](a: U): auto = a + proc my3[T](a: T, b: typeof(fn(a))) = discard + my3(x, x) + doAssert not compiles(my3(x, x[0])) + +block: # issue #22342, type section version of #22607 + type GenAlias[isInt: static bool] = ( + when isInt: + int + else: + float + ) + doAssert GenAlias[true] is int + doAssert GenAlias[false] is float + proc foo(T: static bool): GenAlias[T] = discard + doAssert foo(true) is int + doAssert foo(false) is float + proc foo[T: static bool](v: var GenAlias[T]) = + v += 1 + var x: int + foo[true](x) + doAssert not compiles(foo[false](x)) + foo[true](x) + doAssert x == 2 + var y: float + foo[false](y) + doAssert not compiles(foo[true](y)) + foo[false](y) + doAssert y == 2 + +block: # `when`, test no constant semchecks + type Foo[T] = ( + when false: + {.error: "bad".} + elif defined(neverDefined): + {.error: "bad 2".} + else: + T + ) + var x: Foo[int] + type Bar[T] = ( + when true: + T + elif defined(js): + {.error: "bad".} + else: + {.error: "bad 2".} + ) + var y: Bar[int] + +block: # weird regression + type + Foo[T] = distinct int + Bar[T, U] = distinct int + proc foo[T, U](x: static Foo[T], y: static Bar[T, U]): Foo[T] = + # signature gives: + # Error: cannot instantiate Bar + # got: <typedesc[T], U> + # but expected: <T, U> + x + doAssert foo(Foo[int](1), Bar[int, int](2)).int == 1 + +block: # issue #24090 + type M[V] = object + template y[V](N: type M, v: V): M[V] = default(M[V]) + proc d(x: int | int, f: M[int] = M.y(0)) = discard + d(0, M.y(0)) + type Foo[T] = object + x: typeof(M.y(default(T))) + var a: Foo[int] + doAssert a.x is M[int] + var b: Foo[float] + doAssert b.x is M[float] + doAssert not (compiles do: + type Bar[T] = object + x: typeof(M()) # actually fails here immediately + var bar: Bar[int]) + doAssert not (compiles do: + type Bar[T] = object + x: typeof(default(M)) + var bar: Bar[int] + # gives "undeclared identifier x" because of #24091, + # normally it should fail in the line above + echo bar.x) + proc foo[T: M](x: T = default(T)) = discard x + foo[M[int]]() + doAssert not compiles(foo()) + +block: # above but encountered by sigmatch using replaceTypeVarsN + type Opt[T] = object + x: T + proc none[T](x: type Opt, y: typedesc[T]): Opt[T] = discard + proc foo[T](x: T, a = Opt.none(int)) = discard + foo(1, a = Opt.none(int)) + foo(1) + +block: # real version of above + type Opt[T] = object + x: T + template none(x: type Opt, T: type): Opt[T] = Opt[T]() + proc foo[T](x: T, a = Opt.none(int)) = discard + foo(1, a = Opt.none(int)) + foo(1) + +block: # issue #20880 + type + Child[n: static int] = object + data: array[n, int] + Parent[n: static int] = object + child: Child[3*n] + const n = 3 + doAssert $(typeof Parent[n*3]()) == "Parent[9]" + doAssert $(typeof Parent[1]().child) == "Child[3]" + doAssert Parent[1]().child.data.len == 3 + +{.experimental: "dynamicBindSym".} +block: # issue #16774 + type SecretWord = distinct uint64 + const WordBitWidth = 8 * sizeof(uint64) + func wordsRequired(bits: int): int {.compileTime.} = + ## Compute the number of limbs required + # from the **announced** bit length + (bits + WordBitWidth - 1) div WordBitWidth + type + Curve = enum BLS12_381 + BigInt[bits: static int] = object + limbs: array[bits.wordsRequired, SecretWord] + const BLS12_381_Modulus = default(BigInt[381]) + macro Mod(C: static Curve): untyped = + ## Get the Modulus associated to a curve + result = bindSym($C & "_Modulus") + macro getCurveBitwidth(C: static Curve): untyped = + result = nnkDotExpr.newTree( + getAST(Mod(C)), + ident"bits" + ) + type Fp[C: static Curve] = object + ## Finite Fields / Modular arithmetic + ## modulo the curve modulus + mres: BigInt[getCurveBitwidth(C)] + var x: Fp[BLS12_381] + doAssert x.mres.limbs.len == wordsRequired(getCurveBitWidth(BLS12_381)) + # minimized, as if we haven't tested it already: + macro makeIntLit(c: static int): untyped = + result = newLit(c) + type Test[T: static int] = object + myArray: array[makeIntLit(T), int] + var y: Test[2] + doAssert y.myArray.len == 2 + var z: Test[4] + doAssert z.myArray.len == 4 + +block: # issue #16175 + type + Thing[D: static uint] = object + when D == 0: + kid: char + else: + kid: Thing[D-1] + var t2 = Thing[3]() + doAssert t2.kid is Thing[2.uint] + doAssert t2.kid.kid is Thing[1.uint] + doAssert t2.kid.kid.kid is Thing[0.uint] + doAssert t2.kid.kid.kid.kid is char + var s = Thing[1]() + doAssert s.kid is Thing[0.uint] + doAssert s.kid.kid is char diff --git a/tests/generics/twrong_explicit_typeargs.nim b/tests/generics/twrong_explicit_typeargs.nim deleted file mode 100644 index e47b38e99..000000000 --- a/tests/generics/twrong_explicit_typeargs.nim +++ /dev/null @@ -1,16 +0,0 @@ -discard """ - errormsg: "cannot instantiate: 'newImage[string]'" - line: 16 -""" - -# bug #4084 -type - Image[T] = object - data: seq[T] - -proc newImage[T: int32|int64](w, h: int): ref Image[T] = - new(result) - result.data = newSeq[T](w * h) - -var correct = newImage[int32](320, 200) -var wrong = newImage[string](320, 200) diff --git a/tests/generics/twrong_generic_object.nim b/tests/generics/twrong_generic_object.nim index 442b89ea1..4951f735f 100644 --- a/tests/generics/twrong_generic_object.nim +++ b/tests/generics/twrong_generic_object.nim @@ -1,6 +1,6 @@ discard """ - errormsg: "cannot instantiate: 'GenericNodeObj[T]'; Maybe generic arguments are missing?" - line: 21 + errormsg: "'Node' is not a concrete type" + line: 11 """ # bug #2509 type diff --git a/tests/import/t23167.nim b/tests/import/t23167.nim new file mode 100644 index 000000000..0891ee2af --- /dev/null +++ b/tests/import/t23167.nim @@ -0,0 +1,5 @@ +# bug #23167 +template sharedImport() = + import std / os + +sharedImport() diff --git a/tests/init/tcompiles.nim b/tests/init/tcompiles.nim index e86cad1e2..67e17b241 100644 --- a/tests/init/tcompiles.nim +++ b/tests/init/tcompiles.nim @@ -89,3 +89,13 @@ block: catchError: echo bar() + +block: + proc foo(x: ptr int) = + discard + + proc main = + var s: int + foo(addr s) + + main() diff --git a/tests/init/treturns.nim b/tests/init/treturns.nim index 77469472a..18cebe0b1 100644 --- a/tests/init/treturns.nim +++ b/tests/init/treturns.nim @@ -91,3 +91,16 @@ block: return discard hasImportStmt() + +block: + block: + proc foo(x: var int) = + discard + + proc main = + var s: int + foo(s)#[tt.Warning + ^ use explicit initialization of 's' for clarity [Uninit]]# + + main() + diff --git a/tests/int/t1.nim b/tests/int/t1.nim index 36402da07..6e5cdc8d4 100644 --- a/tests/int/t1.nim +++ b/tests/int/t1.nim @@ -1,3 +1,7 @@ +discard """ + targets: "c cpp" +""" + doAssert typeOf(1.int64 + 1.int) is int64 doAssert typeOf(1.uint64 + 1.uint) is uint64 doAssert int64 is SomeNumber @@ -12,3 +16,46 @@ doAssert typeOf(myInt16 + myInt) is int # of type `int` doAssert typeOf(myInt16 + 2i32) is int32 # of type `int32` doAssert int32 isnot int64 doAssert int32 isnot int + +block: # bug #23947 + template foo = + let test_u64 : uint64 = 0xFF07.uint64 + let test_u8 : uint8 = test_u64.uint8 + # Error: illegal conversion from '65287' to '[0..255]' + doAssert test_u8 == 7 + + static: foo() + foo() + +block: + # bug #22085 + const + x = uint32(uint64.high) # vm error + u = uint64.high + v = uint32(u) # vm error + + let + z = uint64.high + y = uint32(z) # runtime ok + + let + w = uint32(uint64.high) # semfold error + + doAssert x == w + doAssert v == y + + # bug #14522 + doAssert 0xFF000000_00000000.uint64 == 18374686479671623680'u64 + +block: # bug #23954 + let testRT_u8 : uint8 = 0x107.uint8 + doAssert testRT_u8 == 7 + const testCT_u8 : uint8 = 0x107.uint8 + doAssert testCT_u8 == 7 + +block: # issue #24104 + type P = distinct uint # uint, uint8, uint16, uint32, uint64 + let v = 0.P + case v + of 0.P: discard + else: discard diff --git a/tests/int/tints.nim b/tests/int/tints.nim index a7d27d736..773e8ccad 100644 --- a/tests/int/tints.nim +++ b/tests/int/tints.nim @@ -1,5 +1,5 @@ discard """ - matrix: "; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on" + matrix: "; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on" output: ''' 0 0 0 0 @@ -7,6 +7,7 @@ Success''' """ # Test the different integer operations + import std/private/jsutils var testNumber = 0 @@ -141,4 +142,9 @@ block: # shl when not defined(js) or (defined(js) and compileOption("jsbigint64")): doAssert u64 shl 1 == u64 - 1 +block: # bug #23378 + var neg = -1 # prevent compile-time evaluation + let n = abs BiggestInt neg + doAssert n == 1 + echo("Success") #OUT Success diff --git a/tests/int/tunsignedinc.nim b/tests/int/tunsignedinc.nim index 9d1a4bbb4..9392f1b74 100644 --- a/tests/int/tunsignedinc.nim +++ b/tests/int/tunsignedinc.nim @@ -32,3 +32,9 @@ block t4175: const j = 0u - 1u doAssert i == j doAssert j + 1u == 0u + +block: # https://forum.nim-lang.org/t/12465#76998 + var a: int = 1 + var x: uint8 = 1 + a.inc(x) # Error: type mismatch + doAssert a == 2 diff --git a/tests/int/twrongexplicitvarconv.nim b/tests/int/twrongexplicitvarconv.nim new file mode 100644 index 000000000..79f770e8e --- /dev/null +++ b/tests/int/twrongexplicitvarconv.nim @@ -0,0 +1,16 @@ +discard """ + action: reject + nimout: ''' + but expression 'int(a)' is immutable, not 'var' +''' +""" + +proc `++`(n: var int) = + n += 1 + +var a: int32 = 15 + +++int(a) #[tt.Error +^ type mismatch: got <int>]# + +echo a diff --git a/tests/int/twrongvarconv.nim b/tests/int/twrongvarconv.nim new file mode 100644 index 000000000..db6ac2c53 --- /dev/null +++ b/tests/int/twrongvarconv.nim @@ -0,0 +1,9 @@ +proc `++`(n: var int) = + n += 1 + +var a: int32 = 15 + +++a #[tt.Error +^ type mismatch: got <int32>]# + +echo a diff --git a/tests/iter/t1550.nim b/tests/iter/t1550.nim index 8ad96f0da..c971943ee 100644 --- a/tests/iter/t1550.nim +++ b/tests/iter/t1550.nim @@ -1,3 +1,7 @@ +discard """ + targets: "c js" +""" + type A[T] = iterator(x: T): T {.gcsafe, closure.} diff --git a/tests/iter/t21306.nim b/tests/iter/t21306.nim index 43fea9c80..4d0396294 100644 --- a/tests/iter/t21306.nim +++ b/tests/iter/t21306.nim @@ -1,3 +1,7 @@ +discard """ + targets: "c js" +""" + # bug #21306 type FutureState {.pure.} = enum diff --git a/tests/iter/t22619.nim b/tests/iter/t22619.nim index 04e707633..6a98391f3 100644 --- a/tests/iter/t22619.nim +++ b/tests/iter/t22619.nim @@ -52,8 +52,12 @@ block: var numDestroy = 0 - proc `=destroy`(x: Value) = - inc numDestroy + when defined(gcRefc): + proc `=destroy`(x: var Value) = + inc numDestroy + else: + proc `=destroy`(x: Value) = + inc numDestroy iterator iter(s: seq[Value]): int {.closure.} = # because it is used across yields, `s2` is lifted into the iterator's diff --git a/tests/iter/t2771.nim b/tests/iter/t2771.nim index 49befb0a9..71a8a9dcd 100644 --- a/tests/iter/t2771.nim +++ b/tests/iter/t2771.nim @@ -1,3 +1,7 @@ +discard """ + targets: "c js" +""" + template t1(i: int): int= i+1 template t2(i: int): int= diff --git a/tests/iter/tanoniter1.nim b/tests/iter/tanoniter1.nim index 9f0d0a74b..fee16497f 100644 --- a/tests/iter/tanoniter1.nim +++ b/tests/iter/tanoniter1.nim @@ -1,4 +1,5 @@ discard """ + targets: "c js" output: '''1 2 3 diff --git a/tests/iter/tclosureiters.nim b/tests/iter/tclosureiters.nim index 85611373c..4a2639852 100644 --- a/tests/iter/tclosureiters.nim +++ b/tests/iter/tclosureiters.nim @@ -1,4 +1,5 @@ discard """ + targets: "c js" output: '''0 1 2 @@ -152,15 +153,18 @@ iterator filesIt(path: string): auto {.closure.} = yield prefix / f # bug #13815 -var love = iterator: int {.closure.} = - yield cast[type( - block: - var a = 0 - yield a - a)](0) - -for i in love(): - echo i +when not defined(js): + var love = iterator: int {.closure.} = + yield cast[type( + block: + var a = 0 + yield a + a)](0) + + for i in love(): + echo i +else: + echo 0 # bug #18474 iterator pairs(): (int, int) {.closure.} = diff --git a/tests/iter/titer.nim b/tests/iter/titer.nim index f32bec2fb..b03d43f36 100644 --- a/tests/iter/titer.nim +++ b/tests/iter/titer.nim @@ -127,3 +127,21 @@ block: # bug #21110 e() static: foo() foo() + + +# bug #15924 +iterator walk(): (int, int) {.closure.} = + yield (10,11) + +for (i,j) in walk(): + doAssert i == 10 + +proc main123() = + let x = false + iterator it(): (bool, bool) {.closure.} = # normally {.closure.} here makes #21476 work + discard x + + for (_, _) in it(): + discard + +main123() diff --git a/tests/iter/titer11.nim b/tests/iter/titer11.nim index 2b39c74f7..153b3c29a 100644 --- a/tests/iter/titer11.nim +++ b/tests/iter/titer11.nim @@ -1,4 +1,5 @@ discard """ +targets: "c js" output: ''' [ 1 diff --git a/tests/iter/titer12.nim b/tests/iter/titer12.nim index f7fc64da4..f264a0e82 100644 --- a/tests/iter/titer12.nim +++ b/tests/iter/titer12.nim @@ -1,4 +1,5 @@ discard """ +targets: "c js" output: ''' Selecting 2 1.0 diff --git a/tests/iter/titer_issues.nim b/tests/iter/titer_issues.nim index adba8a8e3..c82b3902d 100644 --- a/tests/iter/titer_issues.nim +++ b/tests/iter/titer_issues.nim @@ -1,4 +1,5 @@ discard """ + target: "c js" output: ''' 0 1 @@ -392,3 +393,19 @@ iterator tryFinally() {.closure.} = var x = tryFinally x() + +block: # bug #24033 + type Query = ref object + + iterator pairs(query: Query): (int, (string, float32)) = + var output: (int, (string, float32)) = (0, ("foo", 3.14)) + for id in @[0, 1, 2]: + output[0] = id + yield output + + var collections: seq[(int, string, string)] + + for id, (str, num) in Query(): + collections.add (id, str, $num) + + doAssert collections[1] == (1, "foo", "3.14") diff --git a/tests/iter/titervaropenarray.nim b/tests/iter/titervaropenarray.nim index ad1192bd8..b2fe71ceb 100644 --- a/tests/iter/titervaropenarray.nim +++ b/tests/iter/titervaropenarray.nim @@ -1,6 +1,6 @@ discard """ output: "123" - targets: "c" + targets: "c cpp" """ # Try to break the transformation pass: iterator iterAndZero(a: var openArray[int]): int = diff --git a/tests/iter/tyieldintry.nim b/tests/iter/tyieldintry.nim index 47ba6efa6..e51ab7f0d 100644 --- a/tests/iter/tyieldintry.nim +++ b/tests/iter/tyieldintry.nim @@ -1,5 +1,5 @@ discard """ - matrix: "; --experimental:strictdefs" + matrix: "; --experimental:strictdefs; -d:nimOptIters" targets: "c cpp" """ @@ -504,3 +504,26 @@ block: # void iterator except: discard var a = it + +if defined(nimOptIters): # Locals present in only 1 state should be on the stack + proc checkOnStack(a: pointer, shouldBeOnStack: bool) = + # Quick and dirty way to check if a points to stack + var dummy = 0 + let dummyAddr = addr dummy + let distance = abs(cast[int](dummyAddr) - cast[int](a)) + const requiredDistance = 300 + if shouldBeOnStack: + doAssert(distance <= requiredDistance, "a is not on stack, but should") + else: + doAssert(distance > requiredDistance, "a is on stack, but should not") + + iterator it(): int {.closure.} = + var a = 1 + var b = 2 + var c {.liftLocals.} = 3 + checkOnStack(addr a, true) + checkOnStack(addr b, false) + checkOnStack(addr c, false) + yield a + yield b + test(it, 1, 2) diff --git a/tests/js/t21439.nim b/tests/js/t21439.nim index 972356cd0..3caeb090a 100644 --- a/tests/js/t21439.nim +++ b/tests/js/t21439.nim @@ -1,8 +1,5 @@ -discard """ - action: "compile" -""" - proc test(a: openArray[string]): proc = + let a = @a result = proc = for i in a: discard i diff --git a/tests/js/t7109.nim b/tests/js/t7109.nim index 0d071dbbf..a1a3b718e 100644 --- a/tests/js/t7109.nim +++ b/tests/js/t7109.nim @@ -1,8 +1,8 @@ -discard """ - errormsg: "Closure iterators are not supported by JS backend!" -""" - iterator iter*(): int {.closure.} = yield 3 var x = iter +doAssert x() == 3 + +let fIt = iterator(): int = yield 70 +doAssert fIt() == 70 diff --git a/tests/js/tcodegendeclproc.nim b/tests/js/tcodegendeclproc.nim index 3acf0bc13..33064bdf1 100644 --- a/tests/js/tcodegendeclproc.nim +++ b/tests/js/tcodegendeclproc.nim @@ -3,7 +3,7 @@ discard """ -1 8 ''' - ccodecheck: "'console.log(-1); function fac_' \\d+ '(n_' \\d+ ')'" + ccodecheck: "'console.log(-1); function fac__tcodegendeclproc_u1(n_p0)'" """ proc fac(n: int): int {.codegenDecl: "console.log(-1); function $2($3)".} = return n diff --git a/tests/js/tdanger.nim b/tests/js/tdanger.nim new file mode 100644 index 000000000..9088859a8 --- /dev/null +++ b/tests/js/tdanger.nim @@ -0,0 +1,17 @@ +discard """ + matrix: ";--d:danger" +""" + +block: + proc foo() = + var name = int64(12) + var x = uint32(name) + var m = x + 12 + + var y = int32(name) + var n = y + 1 + + doAssert m == uint32(n + 11) + + + foo() diff --git a/tests/js/tjsffi.nim b/tests/js/tjsffi.nim index b54d13e43..f27ea5546 100644 --- a/tests/js/tjsffi.nim +++ b/tests/js/tjsffi.nim @@ -1,4 +1,5 @@ discard """ +matrix: "--legacy:jsnolambdalifting;" output: ''' 3 2 @@ -180,7 +181,7 @@ block: # Test lit block: # Test bindMethod type TestObject = object a: int - onWhatever: proc(e: int): int + onWhatever: proc(e: int): int {.nimcall.} proc handleWhatever(this: TestObject, e: int): int = e + this.a block: @@ -269,5 +270,5 @@ block: # test ** block: # issue #21208 type MyEnum = enum baz var obj: JsObject - {.emit: "`obj` = {bar: {baz: 123}}".} + {.emit: "`obj` = {bar: {baz: 123}};".} discard obj.bar.baz diff --git a/tests/js/tjsffi_old.nim b/tests/js/tjsffi_old.nim index 19f30ee2c..378003f4e 100644 --- a/tests/js/tjsffi_old.nim +++ b/tests/js/tjsffi_old.nim @@ -279,8 +279,8 @@ block: block: type TestObject = object a: int - onWhatever: proc(e: int): int - proc handleWhatever(this: TestObject, e: int): int = + onWhatever: proc(e: int): int {.nimcall.} + proc handleWhatever(this: TestObject, e: int): int {.nimcall.} = e + this.a proc test(): bool = let obj = TestObject(a: 9, onWhatever: bindMethod(handleWhatever)) diff --git a/tests/js/tjsnimscombined.nim b/tests/js/tjsnimscombined.nim new file mode 100644 index 000000000..4d3e6c453 --- /dev/null +++ b/tests/js/tjsnimscombined.nim @@ -0,0 +1 @@ +import std/jsffi diff --git a/tests/js/tjsnimscombined.nims b/tests/js/tjsnimscombined.nims new file mode 100644 index 000000000..01b93d3fa --- /dev/null +++ b/tests/js/tjsnimscombined.nims @@ -0,0 +1 @@ +# test the condition where both `js` and `nimscript` are defined (nimscript receives priority) diff --git a/tests/js/tos.nim b/tests/js/tos.nim index bfe3cd9b4..40fb52bcf 100644 --- a/tests/js/tos.nim +++ b/tests/js/tos.nim @@ -13,11 +13,9 @@ block: doAssert not "foo".isAbsolute doAssert relativePath("", "bar") == "" doAssert normalizedPath(".///foo//./") == "foo" - let cwd = getCurrentDir() - let isWindows = '\\' in cwd - # defined(windows) doesn't work with -d:nodejs but should - # these actually break because of that (see https://github.com/nim-lang/Nim/issues/13469) - if not isWindows: + when nimvm: discard + else: + let cwd = getCurrentDir() doAssert cwd.isAbsolute - doAssert relativePath(getCurrentDir() / "foo", "bar") == "../foo" + doAssert relativePath(getCurrentDir() / "foo", "bar") == ".." / "foo" diff --git a/tests/js/ttypedarray.nim b/tests/js/ttypedarray.nim index 08b5fcdde..4807cb103 100644 --- a/tests/js/ttypedarray.nim +++ b/tests/js/ttypedarray.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--jsbigint64:off; --jsbigint64:on" + matrix: "--jsbigint64:off -d:nimStringHash2; --jsbigint64:on" """ import std/private/jsutils diff --git a/tests/lent/tlent_from_var.nim b/tests/lent/tlent_from_var.nim index d61ff6dc0..1fb3d0c17 100644 --- a/tests/lent/tlent_from_var.nim +++ b/tests/lent/tlent_from_var.nim @@ -50,3 +50,58 @@ template get*[T: not void](self: Opt[T]): T = self.value() method connect*( self: Opt[(int, int)]) = discard self.get()[0] + +block: # bug #23454 + type + Letter = enum + A + + LetterPairs = object + values: seq[(Letter, string)] + + iterator items(list: var LetterPairs): lent (Letter, string) = + for item in list.values: + yield item + + var instance = LetterPairs(values: @[(A, "foo")]) + + for (a, _) in instance: + case a + of A: discard + +block: # bug #23454 + type + Letter = enum + A + + LetterPairs = object + values: seq[(Letter, string)] + + iterator items(list: var LetterPairs): var (Letter, string) = + for item in list.values.mItems: + yield item + + var instance = LetterPairs(values: @[(A, "foo")]) + + for (a, _) in instance: + case a + of A: discard + +block: # bug #24034 + type T = object + v: array[100, byte] + + + iterator pairs(t: T): (int, lent array[100, byte]) = + yield (0, t.v) + + + block: + for a, b in default(T): + doAssert a == 0 + doAssert b.len == 100 + + block: + for (a, b) in pairs(default(T)): + doAssert a == 0 + doAssert b.len == 100 diff --git a/tests/lent/tvm.nim b/tests/lent/tvm.nim new file mode 100644 index 000000000..5df1d1270 --- /dev/null +++ b/tests/lent/tvm.nim @@ -0,0 +1,21 @@ +block: # issue #17527 + iterator items2[IX, T](a: array[IX, T]): lent T {.inline.} = + var i = low(IX) + if i <= high(IX): + while true: + yield a[i] + if i >= high(IX): break + inc(i) + + proc main() = + var s: seq[string] = @[] + for i in 0..<3: + for (key, val) in items2([("any", "bar")]): + s.add $(i, key, val) + doAssert s == @[ + "(0, \"any\", \"bar\")", + "(1, \"any\", \"bar\")", + "(2, \"any\", \"bar\")" + ] + + static: main() diff --git a/tests/lookups/issue_23172/m23172.nim b/tests/lookups/issue_23172/m23172.nim new file mode 100644 index 000000000..36af48761 --- /dev/null +++ b/tests/lookups/issue_23172/m23172.nim @@ -0,0 +1,6 @@ +type + Foo* = object + Bar* = object + +func `$`*(x: Foo | Bar): string = + "X" diff --git a/tests/lookups/mambsym3.nim b/tests/lookups/mambsym3.nim new file mode 100644 index 000000000..946a5ff29 --- /dev/null +++ b/tests/lookups/mambsym3.nim @@ -0,0 +1,4 @@ +# Module A +var x*: string +proc foo*(a: string) = + echo "A: ", a diff --git a/tests/lookups/mambsym4.nim b/tests/lookups/mambsym4.nim new file mode 100644 index 000000000..ed66cc16d --- /dev/null +++ b/tests/lookups/mambsym4.nim @@ -0,0 +1,4 @@ +# Module B +var x*: int +proc foo*(b: int) = + echo "B: ", b diff --git a/tests/lookups/mambtype1.nim b/tests/lookups/mambtype1.nim new file mode 100644 index 000000000..47046142e --- /dev/null +++ b/tests/lookups/mambtype1.nim @@ -0,0 +1 @@ +type K* = object diff --git a/tests/lookups/mambtype2.nim b/tests/lookups/mambtype2.nim new file mode 100644 index 000000000..cf622466b --- /dev/null +++ b/tests/lookups/mambtype2.nim @@ -0,0 +1,4 @@ +import ./mambtype1 +export mambtype1 +template K*(kind: static int): auto = typedesc[mambtype1.K] +template B*(kind: static int): auto = typedesc[mambtype1.K] diff --git a/tests/lookups/mdisambsym1.nim b/tests/lookups/mdisambsym1.nim new file mode 100644 index 000000000..b8beca035 --- /dev/null +++ b/tests/lookups/mdisambsym1.nim @@ -0,0 +1,2 @@ +proc count*(s: string): int = + s.len diff --git a/tests/lookups/mdisambsym2.nim b/tests/lookups/mdisambsym2.nim new file mode 100644 index 000000000..1e056311d --- /dev/null +++ b/tests/lookups/mdisambsym2.nim @@ -0,0 +1 @@ +var count*: int = 10 diff --git a/tests/lookups/mdisambsym3.nim b/tests/lookups/mdisambsym3.nim new file mode 100644 index 000000000..95bd19702 --- /dev/null +++ b/tests/lookups/mdisambsym3.nim @@ -0,0 +1 @@ +const count* = 3.142 diff --git a/tests/lookups/mmacroamb.nim b/tests/lookups/mmacroamb.nim new file mode 100644 index 000000000..107e51055 --- /dev/null +++ b/tests/lookups/mmacroamb.nim @@ -0,0 +1,10 @@ +# issue #12732 + +import std/macros +const getPrivate3_tmp* = 0 +const foobar1* = 0 # comment this or make private and it'll compile fine +macro foobar4*(): untyped = + newLit "abc" +template currentPkgDir2*: string = foobar4() +macro currentPkgDir2*(dir: string): untyped = + newLit "abc2" diff --git a/tests/lookups/t23172.nim b/tests/lookups/t23172.nim new file mode 100644 index 000000000..9edf9905a --- /dev/null +++ b/tests/lookups/t23172.nim @@ -0,0 +1,9 @@ +import issue_23172/m23172 + +type FooX = distinct Foo + +func `$`*(x: FooX): string = + $m23172.Foo(x) + +var a: FooX +doAssert $a == "X" diff --git a/tests/lookups/t23749.nim b/tests/lookups/t23749.nim new file mode 100644 index 000000000..650f04ea4 --- /dev/null +++ b/tests/lookups/t23749.nim @@ -0,0 +1,37 @@ +discard """ + action: compile +""" + +{.pragma: callback, gcsafe, raises: [].} + +type + DataProc* = proc(val: openArray[byte]) {.callback.} + GetProc = proc (db: RootRef, key: openArray[byte], onData: DataProc): bool {.nimcall, callback.} + KvStoreRef* = ref object + obj: RootRef + getProc: GetProc + +template get(dbParam: KvStoreRef, key: openArray[byte], onData: untyped): bool = + let db = dbParam + db.getProc(db.obj, key, onData) + +func decode(input: openArray[byte], maxSize = 128): seq[byte] = + @[] + +proc getSnappySSZ(db: KvStoreRef, key: openArray[byte]): string = + var status = "not found" + proc decode(data: openArray[byte]) = + status = + if true: "found" + else: "corrupted" + discard db.get(key, decode) + status + + +var ksr: KvStoreRef +var k = [byte(1), 2, 3, 4, 5] + +proc foo(): string = + getSnappySSZ(ksr, toOpenArray(k, 1, 3)) + +echo foo() diff --git a/tests/lookups/tambiguousemit.nim b/tests/lookups/tambiguousemit.nim index 0ebd0a255..4f4bacce4 100644 --- a/tests/lookups/tambiguousemit.nim +++ b/tests/lookups/tambiguousemit.nim @@ -7,6 +7,6 @@ proc foo(x: int) = discard proc foo(x: float) = discard {.emit: ["// ", foo].} #[tt.Error - ^ ambiguous identifier 'foo' -- use one of the following: + ^ ambiguous identifier: 'foo' -- use one of the following: tambiguousemit.foo: proc (x: int){.noSideEffect, gcsafe.} tambiguousemit.foo: proc (x: float){.noSideEffect, gcsafe.}]# diff --git a/tests/lookups/tambprocvar.nim b/tests/lookups/tambprocvar.nim index 33323fbb2..f5c3fde4f 100644 --- a/tests/lookups/tambprocvar.nim +++ b/tests/lookups/tambprocvar.nim @@ -2,7 +2,7 @@ discard """ action: reject cmd: "nim check $file" nimout: ''' -tambprocvar.nim(15, 11) Error: ambiguous identifier 'foo' -- use one of the following: +tambprocvar.nim(15, 11) Error: ambiguous identifier: 'foo' -- use one of the following: tambprocvar.foo: proc (x: int){.noSideEffect, gcsafe.} tambprocvar.foo: proc (x: float){.noSideEffect, gcsafe.} ''' @@ -16,4 +16,4 @@ block: block: let x = `+` #[tt.Error - ^ ambiguous identifier '+' -- use one of the following:]# + ^ ambiguous identifier: '+' -- use one of the following:]# diff --git a/tests/lookups/tambsym3.nim b/tests/lookups/tambsym3.nim index 6e7589cd8..6bbebca10 100644 --- a/tests/lookups/tambsym3.nim +++ b/tests/lookups/tambsym3.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "ambiguous identifier 'mDec' -- use one of the following:" + errormsg: "ambiguous identifier: 'mDec' -- use one of the following:" file: "tambsym3.nim" line: 11 """ diff --git a/tests/lookups/tambsymmanual.nim b/tests/lookups/tambsymmanual.nim new file mode 100644 index 000000000..3ad91b8cc --- /dev/null +++ b/tests/lookups/tambsymmanual.nim @@ -0,0 +1,25 @@ +discard """ + output: ''' +A: abc +B: 123 +A: def +4 +''' +""" +# Module C +import mambsym3, mambsym4 + +foo("abc") # A: abc +foo(123) # B: 123 +let inferred: proc (x: string) = foo +foo("def") # A: def + +doAssert not compiles(write(stdout, x)) # error: x is ambiguous +write(stdout, mambsym3.x) # no error: qualifier used + +proc bar(a: int): int = a + 1 +doAssert bar(x) == x + 1 # no error: only A.x of type int matches + +var x = 4 +write(stdout, x) # not ambiguous: uses the module C's x +echo() # for test output diff --git a/tests/lookups/tambtype.nim b/tests/lookups/tambtype.nim new file mode 100644 index 000000000..a292db83a --- /dev/null +++ b/tests/lookups/tambtype.nim @@ -0,0 +1,20 @@ +import ./mambtype2 + +block: # issue #23893 + discard default(K(0)) # works + discard default(mambtype2.B(0)) # works + discard default(mambtype2.K(0)) # doesn't work + +block: # issue #23898, in template + template r() = + discard default(B(0)) # compiles + discard default(mambtype2.B(0)) # compiles + discard default(K(0)) # does not compile + r() + +block: # in generics + proc foo[T]() = + discard default(B(0)) # compiles + discard default(mambtype2.B(0)) # compiles + discard default(K(0)) # does not compile + foo[int]() diff --git a/tests/lookups/tdisambsym.nim b/tests/lookups/tdisambsym.nim new file mode 100644 index 000000000..678528ad6 --- /dev/null +++ b/tests/lookups/tdisambsym.nim @@ -0,0 +1,8 @@ +# issue #15247 + +import mdisambsym1, mdisambsym2, mdisambsym3 + +proc twice(n: int): int = + n*2 + +doAssert twice(count) == 20 diff --git a/tests/lookups/tenumlocalsym.nim b/tests/lookups/tenumlocalsym.nim new file mode 100644 index 000000000..575227c07 --- /dev/null +++ b/tests/lookups/tenumlocalsym.nim @@ -0,0 +1,22 @@ +block: + type Enum = enum a, b + + block: + let a = b + let x: Enum = a + doAssert x == b + +block: + type + Enum = enum + a = 2 + b = 10 + + iterator items2(): Enum = + for a in [a, b]: + yield a + + var s = newSeq[Enum]() + for i in items2(): + s.add i + doAssert s == @[a, b] diff --git a/tests/lookups/tmacroamb.nim b/tests/lookups/tmacroamb.nim new file mode 100644 index 000000000..854017e72 --- /dev/null +++ b/tests/lookups/tmacroamb.nim @@ -0,0 +1,5 @@ +# issue #12732 + +import mmacroamb +const s0 = currentPkgDir2 #[tt.Error + ^ ambiguous identifier: 'currentPkgDir2' -- use one of the following:]# diff --git a/tests/lookups/tmoduleclash1.nim b/tests/lookups/tmoduleclash1.nim new file mode 100644 index 000000000..7058f691e --- /dev/null +++ b/tests/lookups/tmoduleclash1.nim @@ -0,0 +1,13 @@ +# issue #23596 + +import std/heapqueue +type Algo = enum heapqueue, quick +when false: + let x = heapqueue +let y: Algo = heapqueue +proc bar*(algo=quick) = + var x: HeapQueue[int] + case algo + of heapqueue: echo 1 # `Algo.heapqueue` works on devel + of quick: echo 2 + echo x.len diff --git a/tests/lookups/tmoduleclash2.nim b/tests/lookups/tmoduleclash2.nim new file mode 100644 index 000000000..958da2299 --- /dev/null +++ b/tests/lookups/tmoduleclash2.nim @@ -0,0 +1,6 @@ +import std/heapqueue +proc heapqueue(x: int) = discard +let x: proc (x: int) = heapqueue +let y: proc = heapqueue +when false: + let z = heapqueue diff --git a/tests/macros/t15751.nim b/tests/macros/t15751.nim new file mode 100644 index 000000000..fcabb2f9e --- /dev/null +++ b/tests/macros/t15751.nim @@ -0,0 +1,11 @@ +discard """ + cmd: "nim c --hints:off $file" + nimout: "out" +""" + +# bug #15751 +macro print(n: untyped): untyped = + echo n.repr + +print: + out diff --git a/tests/macros/t23032_2.nim b/tests/macros/t23032_2.nim index cb8e772e7..8dde29e10 100644 --- a/tests/macros/t23032_2.nim +++ b/tests/macros/t23032_2.nim @@ -1,6 +1,6 @@ discard """ action: "reject" - errormsg: "ambiguous identifier '%*'" + errormsg: "ambiguous identifier: '%*'" """ import std/macros diff --git a/tests/macros/t23547.nim b/tests/macros/t23547.nim new file mode 100644 index 000000000..9a2bff9ff --- /dev/null +++ b/tests/macros/t23547.nim @@ -0,0 +1,23 @@ +# https://github.com/nim-lang/Nim/issues/23547 + +type + A[T] = object + x: T + +proc mulCheckSparse[F](dummy: var A[F], xmulchecksparse: static A[F]) = + static: + echo "mulCheckSparse: ", typeof(dummy), ", ", typeof(xmulchecksparse) # when generic params not specified: A[system.int], A + +template sumImpl(xsumimpl: typed) = + static: + echo "sumImpl: ", typeof(xsumimpl) # A + var a = A[int](x: 55) + mulCheckSparse(a, xsumimpl) # fails here + +proc sum[T](xsum: static T) = + static: + echo "sum: ", typeof(xsum) # A[system.int] + sumImpl(xsum) + +const constA = A[int](x : 100) +sum[A[int]](constA) diff --git a/tests/macros/t23784.nim b/tests/macros/t23784.nim new file mode 100644 index 000000000..31b4544c6 --- /dev/null +++ b/tests/macros/t23784.nim @@ -0,0 +1,157 @@ +discard """ + joinable: false +""" + + +# debug ICE: genCheckedRecordField +# apparently after https://github.com/nim-lang/Nim/pull/23477 + +# bug #23784 + +import std/bitops, std/macros + +# -------------------------------------------------------------- + +type Algebra = enum + BN254_Snarks + +type SecretWord* = distinct uint64 +const WordBitWidth* = sizeof(SecretWord) * 8 + +func wordsRequired*(bits: int): int {.inline.} = + const divShiftor = fastLog2(WordBitWidth) + result = (bits + WordBitWidth - 1) shr divShiftor + +type + BigInt*[bits: static int] = object + limbs*: array[bits.wordsRequired, SecretWord] # <--- crash points to here + +# -------------------------------------------------------------- + +const CurveBitWidth = [ + BN254_Snarks: 254 +] + +const BN254_Snarks_Modulus = BigInt[254](limbs: [SecretWord 0x1, SecretWord 0x2, SecretWord 0x3, SecretWord 0x4]) +const BN254_Snarks_Order = BigInt[254](limbs: [SecretWord 0x1, SecretWord 0x1, SecretWord 0x2, SecretWord 0x2]) + +func montyOne*(M: BigInt[254]): BigInt[254] = + ## Returns "1 (mod M)" in the Montgomery domain. + ## This is equivalent to R (mod M) in the natural domain + BigInt[254](limbs: [SecretWord 0x1, SecretWord 0x1, SecretWord 0x1, SecretWord 0x1]) + + +{.experimental: "dynamicBindSym".} + +type + DerivedConstantMode* = enum + kModulus + kOrder + +macro genDerivedConstants*(mode: static DerivedConstantMode): untyped = + ## Generate constants derived from the main constants + ## + ## For example + ## - the Montgomery magic constant "R^2 mod N" in ROM + ## For each curve under the private symbol "MyCurve_R2modP" + ## - the Montgomery magic constant -1/P mod 2^Wordbitwidth + ## For each curve under the private symbol "MyCurve_NegInvModWord + ## - ... + + # Now typedesc are NimNode and there is no way to translate + # NimNode -> typedesc easily so we can't + # "for curve in low(Curve) .. high(Curve):" + # As an ugly workaround, we count + # The item at position 0 is a pragma + result = newStmtList() + + template used(name: string): NimNode = + nnkPragmaExpr.newTree( + ident(name), + nnkPragma.newTree(ident"used") + ) + + let ff = if mode == kModulus: "_Fp" else: "_Fr" + + for curveSym in low(Algebra) .. high(Algebra): + let curve = $curveSym + let M = if mode == kModulus: bindSym(curve & "_Modulus") + else: bindSym(curve & "_Order") + + # const MyCurve_montyOne = montyOne(MyCurve_Modulus) + result.add newConstStmt( + used(curve & ff & "_MontyOne"), newCall( + bindSym"montyOne", + M + ) + ) + +# -------------------------------------------------------------- + +{.experimental: "dynamicBindSym".} + +genDerivedConstants(kModulus) +genDerivedConstants(kOrder) + +proc bindConstant(ff: NimNode, property: string): NimNode = + # Need to workaround https://github.com/nim-lang/Nim/issues/14021 + # which prevents checking if a type FF[Name] = Fp[Name] or Fr[Name] + # was instantiated with Fp or Fr. + # getTypeInst only returns FF and sameType doesn't work. + # so quote do + when checks. + let T = getTypeInst(ff) + T.expectKind(nnkBracketExpr) + doAssert T[0].eqIdent("typedesc") + + let curve = + if T[1].kind == nnkBracketExpr: # typedesc[Fp[BLS12_381]] as used internally + # doAssert T[1][0].eqIdent"Fp" or T[1][0].eqIdent"Fr", "Found ident: '" & $T[1][0] & "' instead of 'Fp' or 'Fr'" + T[1][1].expectKind(nnkIntLit) # static enum are ints in the VM + $Algebra(T[1][1].intVal) + else: # typedesc[bls12381_fp] alias as used for C exports + let T1 = getTypeInst(T[1].getImpl()[2]) + if T1.kind != nnkBracketExpr or + T1[1].kind != nnkIntLit: + echo T.repr() + echo T1.repr() + echo getTypeInst(T1).treerepr() + error "getTypeInst didn't return the full instantiation." & + " Dealing with types in macros is hard, complain at https://github.com/nim-lang/RFCs/issues/44" + $Algebra(T1[1].intVal) + + let curve_fp = bindSym(curve & "_Fp_" & property) + let curve_fr = bindSym(curve & "_Fr_" & property) + result = quote do: + when `ff` is Fp: + `curve_fp` + elif `ff` is Fr: + `curve_fr` + else: + {.error: "Unreachable, received type: " & $`ff`.} + +# -------------------------------------------------------------- + +template matchingBigInt*(Name: static Algebra): untyped = + ## BigInt type necessary to store the prime field Fp + # Workaround: https://github.com/nim-lang/Nim/issues/16774 + # as we cannot do array accesses in type section. + # Due to generic sandwiches, it must be exported. + BigInt[CurveBitWidth[Name]] + +type + Fp*[Name: static Algebra] = object + mres*: matchingBigInt(Name) + +macro getMontyOne*(ff: type Fp): untyped = + ## Get one in Montgomery representation (i.e. R mod P) + result = bindConstant(ff, "MontyOne") + +func getOne*(T: type Fp): T {.noInit, inline.} = + result = cast[ptr T](unsafeAddr getMontyOne(T))[] + +# -------------------------------------------------------------- +proc foo(T: Fp) = + discard T + +let a = Fp[BN254_Snarks].getOne() +foo(a) # oops this was a leftover that broke the bisect. diff --git a/tests/macros/tastrepr.nim b/tests/macros/tastrepr.nim index c04498a25..96a37c7a2 100644 --- a/tests/macros/tastrepr.nim +++ b/tests/macros/tastrepr.nim @@ -11,6 +11,8 @@ for i, (x, y) in pairs(data): var a = 1 b = 2 +type + A* = object var data = @[(1, "one"), (2, "two")] for (i, d) in pairs(data): @@ -20,6 +22,11 @@ for i, d in pairs(data): for i, (x, y) in pairs(data): discard var (a, b) = (1, 2) +type + A* = object + +var t04 = 1.0'f128 +t04 = 2.0'f128 ''' """ @@ -44,3 +51,8 @@ echoTypedAndUntypedRepr: for i, (x,y) in pairs(data): discard var (a,b) = (1,2) + type A* = object # issue #22933 + +echoUntypedRepr: + var t04 = 1'f128 + t04 = 2'f128 diff --git a/tests/macros/tfail_parse.nim b/tests/macros/tfail_parse.nim new file mode 100644 index 000000000..1925f2b69 --- /dev/null +++ b/tests/macros/tfail_parse.nim @@ -0,0 +1,15 @@ +discard """ +action: "reject" +cmd: "nim check $file" +errormsg: "expected expression, but got multiple statements [ValueError]" +file: "macros.nim" +""" + +import macros +static: + discard parseStmt("'") + discard parseExpr("'") + discard parseExpr(""" +proc foo() +proc foo() = discard +""") diff --git a/tests/macros/tgetimpl.nim b/tests/macros/tgetimpl.nim index 398957672..ab33131b0 100644 --- a/tests/macros/tgetimpl.nim +++ b/tests/macros/tgetimpl.nim @@ -50,8 +50,6 @@ static: doAssert isSameOwner(poo, dummyproc) == false wrappedScope() -#--------------------------------------------------------------- - macro check_gen_proc(ex: typed): (bool, bool) = let lenChoice = bindsym"len" var is_equal = false @@ -75,7 +73,9 @@ assert: check_gen_proc(len(a)) == (false, true) macro check(x: type): untyped = let z = getType(x) let y = getImpl(z[1]) - let sym = if y[0].kind == nnkSym: y[0] else: y[0][0] + var sym = y[0] + if sym.kind == nnkPragmaExpr: sym = sym[0] + if sym.kind == nnkPostfix: sym = sym[1] expectKind(z[1], nnkSym) expectKind(sym, nnkSym) expectKind(y[2], nnkObjectTy) diff --git a/tests/macros/tgettypeinst7737.nim b/tests/macros/tgettypeinst7737.nim new file mode 100644 index 000000000..e49f82562 --- /dev/null +++ b/tests/macros/tgettypeinst7737.nim @@ -0,0 +1,61 @@ +discard """ + nimout: ''' +seq[int] +CustomSeq[int] +''' +""" + +import macros, typetraits, sequtils + +block: # issue #7737 original + type + CustomSeq[T] = object + data: seq[T] + + proc getSubType(T: NimNode): NimNode = + echo getTypeInst(T).repr + result = getTypeInst(T)[1] + + macro typed_helper(x: varargs[typed]): untyped = + let foo = getSubType(x[0]) + result = quote do: discard + + macro untyped_heavylifting(x: varargs[untyped]): untyped = + var containers = nnkArgList.newTree() + for arg in x: + case arg.kind: + of nnkInfix: + if eqIdent(arg[0], "in"): + containers.add arg[2] + else: + discard + result = quote do: + typed_helper(`containers`) + var a, b, c: seq[int] + untyped_heavylifting z in c, x in a, y in b: + discard + ## The following gives me CustomSeq instead + ## of CustomSeq[int] in getTypeInst + var u, v, w: CustomSeq[int] + untyped_heavylifting z in u, x in v, y in w: + discard + +block: # issue #7737 comment + type + CustomSeq[T] = object + data: seq[T] + # when using just one argument, `foo` and `bar` should be exactly + # identical. + macro foo(arg: typed): string = + result = newLit(arg.getTypeInst.repr) + macro bar(args: varargs[typed]): untyped = + result = newTree(nnkBracket) + for arg in args: + result.add newLit(arg.getTypeInst.repr) + var + a: seq[int] + b: CustomSeq[int] + doAssert foo(a) == "seq[int]" + doAssert bar(a) == ["seq[int]"] + doAssert foo(b) == "CustomSeq[int]" + doAssert bar(b) == ["CustomSeq[int]"] diff --git a/tests/macros/tmacrostmt.nim b/tests/macros/tmacrostmt.nim index 79be5f764..817bc8352 100644 --- a/tests/macros/tmacrostmt.nim +++ b/tests/macros/tmacrostmt.nim @@ -124,7 +124,7 @@ static: let fn4s = "proc fn4(x: int): int =\n if x mod 2 == 0:\n return x + 2\n else:\n return 0\n" let fn5s = "proc fn5(a, b: float): float =\n result = -a * a / (b * b)\n" let fn6s = "proc fn6() =\n var a = @[1.0, 2.0]\n let z = a{0, 1}\n a{2} = 5.0\n" - let fnAddr = "proc fn_unsafeaddr(x: int): int =\n result = cast[int](unsafeAddr(x))\n" + let fnAddr = "proc fn_unsafeaddr(x: int): int =\n result = cast[int](addr(x))\n" doAssert fn1.repr_to_string == fn1s doAssert fn2.repr_to_string == fn2s diff --git a/tests/macros/tmacrotypes.nim b/tests/macros/tmacrotypes.nim index 43819c81d..13b421303 100644 --- a/tests/macros/tmacrotypes.nim +++ b/tests/macros/tmacrotypes.nim @@ -1,9 +1,9 @@ discard """ - nimout: '''intProc; ntyProc; proc[int, int, float]; proc (a: int; b: float): int + nimout: '''intProc; ntyProc; proc[int, int, float]; proc (a: int; b: float): int {.nimcall.} void; ntyVoid; void; void int; ntyInt; int; int -proc (); ntyProc; proc[void]; proc () -voidProc; ntyProc; proc[void]; proc () +proc () {.nimcall.}; ntyProc; proc[void]; proc () {.nimcall.} +voidProc; ntyProc; proc[void]; proc () {.nimcall.} listing fields for ObjType a: string b: int diff --git a/tests/macros/tprocgettype.nim b/tests/macros/tprocgettype.nim new file mode 100644 index 000000000..0c1cc4270 --- /dev/null +++ b/tests/macros/tprocgettype.nim @@ -0,0 +1,28 @@ +discard """ + nimout: ''' +var x: proc () {.cdecl.} = foo +var x: iterator (): int {.closure.} = bar +''' +""" + +# issue #19010 + +import macros + +macro createVar(x: typed): untyped = + result = nnkVarSection.newTree: + newIdentDefs(ident"x", getTypeInst(x), copy(x)) + + echo repr result + +block: + proc foo() {.cdecl.} = discard + + createVar(foo) + x() + +block: + iterator bar(): int {.closure.} = discard + + createVar(bar) + for a in x(): discard diff --git a/tests/metatype/tmetatype_issues.nim b/tests/metatype/tmetatype_issues.nim index 21c5c02f1..d33d8dd31 100644 --- a/tests/metatype/tmetatype_issues.nim +++ b/tests/metatype/tmetatype_issues.nim @@ -157,3 +157,12 @@ block t3338: var t2 = Bar[int32]() t2.add() doAssert t2.x == 5 + +block: # issue #24203 + proc b(G: typedesc) = + type U = G + template s(h: untyped) = h + s(b(typeof (0, 0))) + b(seq[int]) + b((int, int)) + b(typeof (0, 0)) diff --git a/tests/metatype/tmetatype_various.nim b/tests/metatype/tmetatype_various.nim index be70f37a7..45c74432d 100644 --- a/tests/metatype/tmetatype_various.nim +++ b/tests/metatype/tmetatype_various.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--mm:refc; --mm:refc" + matrix: "--mm:refc; --mm:orc" output: '''[1, 0, 0, 0, 0, 0, 0, 0] CTBool[Ct[system.uint32]]''' """ @@ -66,3 +66,8 @@ var x: array[8, CTBool[Ct[uint32]]] x[0] = (CTBool[Ct[uint32]])(1) echo x.repr, " ", typeof(x[0]) +block: # bug #23139 + type Foo = enum a, b + + var x: range[a..b] + doAssert (repr x) == "a" diff --git a/tests/metatype/ttypedescnotnimnode.nim b/tests/metatype/ttypedescnotnimnode.nim new file mode 100644 index 000000000..52a04815b --- /dev/null +++ b/tests/metatype/ttypedescnotnimnode.nim @@ -0,0 +1,21 @@ +discard """ + errormsg: "type mismatch: got <NimNode> but expected 'typedesc'" + line: 14 +""" + +import macros + +# This is the same example as ttypeselectors but using a proc instead of a macro +# Instead of type mismatch for macro, proc just failed with internal error: getTypeDescAux(tyNone) +# https://github.com/nim-lang/Nim/issues/7231 + +proc getBase2*(bits: static[int]): typedesc = + if bits == 128: + result = newTree(nnkBracketExpr, ident("MpUintBase"), ident("uint64")) + else: + result = newTree(nnkBracketExpr, ident("MpUintBase"), ident("uint32")) + +type + MpUint2*[bits: static[int]] = getbase2(bits) +# technically shouldn't error until instantiation, so instantiate it +var x: MpUint2[123] diff --git a/tests/metatype/ttypeselectors.nim b/tests/metatype/ttypeselectors.nim index 5385a1be9..d0843511d 100644 --- a/tests/metatype/ttypeselectors.nim +++ b/tests/metatype/ttypeselectors.nim @@ -98,16 +98,3 @@ var c: Bar[32] echo sizeof(a) echo sizeof(b) echo sizeof(c) - -# This is the same example but using a proc instead of a macro -# Instead of type mismatch for macro, proc just failed with internal error: getTypeDescAux(tyNone) -# https://github.com/nim-lang/Nim/issues/7231 - -proc getBase2*(bits: static[int]): typedesc = - if bits == 128: - result = newTree(nnkBracketExpr, ident("MpUintBase"), ident("uint64")) - else: - result = newTree(nnkBracketExpr, ident("MpUintBase"), ident("uint32")) - -type - MpUint2*[bits: static[int]] = getbase2(bits) diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim index bfaa23057..0523390a7 100644 --- a/tests/metatype/ttypetraits.nim +++ b/tests/metatype/ttypetraits.nim @@ -144,6 +144,32 @@ block distinctBase: doAssert($distinctBase(typeof(b2)) == "string") doAssert($distinctBase(typeof(c2)) == "int") +block: # rangeBase + {.push warningAsError[EnumConv]: on.} + proc foo[T: not range](x: T): string = + $T & "(" & $x & ")" + proc foo[T: range](x: T): string = + "ranged(" & $low(T) & ".." & $high(T) & " of " & $rangeBase(T) & ") " & foo(rangeBase(x)) + doAssert foo(123) == "int(123)" + type IntRange = range[0..3] + let x: IntRange = 2 + doAssert foo(x) == "ranged(0..3 of int) int(2)" + type E = enum a, b, c, d, e, f + type EnumRange = range[c..e] + let y: EnumRange = d + doAssert foo(y) == "ranged(c..e of E) E(d)" + let z: range['a'..'z'] = 'g' + doAssert foo(z) == "ranged(a..z of char) char(g)" + {.pop.} + + # works only with #24037: + var toChange: range[0..3] = 1 + proc bar[T: int and not range](y: var T) = + inc y + doAssert not compiles(bar(toChange)) + bar(rangeBase(toChange)) + doAssert toChange == 2 + block: # tupleLen doAssert not compiles(tupleLen(int)) @@ -365,3 +391,14 @@ block: # enum.len doAssert MyEnum.enumLen == 4 doAssert OtherEnum.enumLen == 3 doAssert MyFlag.enumLen == 4 + +when true: # Odd bug where alias can seep inside of `distinctBase` + import std/unittest + + type + AdtChild* = concept t + distinctBase(t) + + proc `$`*[T: AdtChild](adtChild: T): string = "" + + check 10 is int diff --git a/tests/metatype/twrong_same_type.nim b/tests/metatype/twrong_same_type.nim new file mode 100644 index 000000000..ea903b7a3 --- /dev/null +++ b/tests/metatype/twrong_same_type.nim @@ -0,0 +1,28 @@ +# bug #23418 + +template mapIt*(x: untyped): untyped = + type OutType {.gensym.} = typeof(x) #typeof(x, typeOfProc) + newSeq[OutType](5) + +type F[E] = object + +proc start(v: int): F[(ValueError,)] = discard +proc stop(v: int): F[tuple[]] = discard + +assert $typeof(mapIt(start(9))) == "seq[F[(ValueError,)]]" +assert $typeof(mapIt(stop(9))) == "seq[F[tuple[]]]" + +# bug #23445 + +type F2[T; I: static int] = distinct int + +proc start2(v: int): F2[void, 22] = discard +proc stop2(v: int): F2[void, 33] = discard + +var a = mapIt(start2(5)) + +assert $type(a) == "seq[F2[system.void, 22]]", $type(a) + +var b = mapIt(stop2(5)) + +assert $type(b) == "seq[F2[system.void, 33]]", $type(b) diff --git a/tests/misc/mjsondoc.nim b/tests/misc/mjsondoc.nim index e4642f0b4..016c8522d 100644 --- a/tests/misc/mjsondoc.nim +++ b/tests/misc/mjsondoc.nim @@ -9,3 +9,6 @@ const type MyEnum* = enum foo, bar + +proc foo2*[T: int, M: string, U](x: T, y: U, z: M) = + echo 1 diff --git a/tests/misc/t12869.nim b/tests/misc/t12869.nim index 731a4e95e..054e28a03 100644 --- a/tests/misc/t12869.nim +++ b/tests/misc/t12869.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "type mismatch: got <bool> but expected 'int'" + errormsg: "type mismatch: got <openArray[int], proc (x: GenericParam, y: GenericParam): auto, SortOrder>" line: 12 """ diff --git a/tests/misc/t20883.nim b/tests/misc/t20883.nim index d98feaa14..92e7929f4 100644 --- a/tests/misc/t20883.nim +++ b/tests/misc/t20883.nim @@ -1,8 +1,9 @@ discard """ action: reject - errormsg: "type mismatch: got <float64> but expected 'typeof(U(0.000001))'" - line: 8 - column: 22 +nimout: ''' +t20883.nim(13, 4) template/generic instantiation of `foo` from here +t20883.nim(9, 11) Error: cannot instantiate: 'U' +''' """ proc foo*[U](x: U = U(1e-6)) = diff --git a/tests/misc/t23240.nim b/tests/misc/t23240.nim new file mode 100644 index 000000000..d5edcefe8 --- /dev/null +++ b/tests/misc/t23240.nim @@ -0,0 +1,6 @@ +discard """ + cmd: "nim c foo/bar.nim" + action: "reject" + errormsg: "cannot open 'foo/'" + file: "" +""" diff --git a/tests/misc/t8545.nim b/tests/misc/t8545.nim index 89957e1d3..48b886cb8 100644 --- a/tests/misc/t8545.nim +++ b/tests/misc/t8545.nim @@ -1,5 +1,6 @@ discard """ - targets: "c cpp js" + # just tests that this doesn't crash the compiler + errormsg: "cannot instantiate: 'a:type'" """ # bug #8545 diff --git a/tests/misc/taddr.nim b/tests/misc/taddr.nim index 48d4928ac..64f95c7e3 100644 --- a/tests/misc/taddr.nim +++ b/tests/misc/taddr.nim @@ -273,6 +273,16 @@ proc test15939() = # bug #15939 (v2) else: # can't take address of cstring element in js when not defined(js): cstringTest() +block: # bug #23499 + template volatileStore[T](dest: ptr T, val: T) = + dest[] = val + + proc foo = + var ctr = 0 + volatileStore(addr ctr, 0) + + foo() + template main = # xxx wrap all other tests here like that so they're also tested in VM test14420() diff --git a/tests/misc/tcast.nim b/tests/misc/tcast.nim index 6d67b1c52..73196e76c 100644 --- a/tests/misc/tcast.nim +++ b/tests/misc/tcast.nim @@ -1,6 +1,7 @@ discard """ output: ''' Hello World +Hello World Hello World''' joinable: false """ @@ -8,7 +9,7 @@ type MyProc = proc() {.cdecl.} type MyProc2 = proc() {.nimcall.} type MyProc3 = proc() #{.closure.} is implicit -proc testProc() = echo "Hello World" +proc testProc() {.exportc:"foo".} = echo "Hello World" template reject(x) = doAssert(not compiles(x)) @@ -23,6 +24,10 @@ proc callPointer(p: pointer) = ffunc0() ffunc1() + # bug #5901 + proc foo() {.importc.} + (cast[proc(a: int) {.cdecl.}](foo))(5) + callPointer(cast[pointer](testProc)) reject: discard cast[enum](0) diff --git a/tests/misc/tconv.nim b/tests/misc/tconv.nim index e4a99344a..90fae868b 100644 --- a/tests/misc/tconv.nim +++ b/tests/misc/tconv.nim @@ -88,6 +88,13 @@ block: # https://github.com/nim-lang/RFCs/issues/294 reject: Goo(k2) reject: k2.Goo + type KooRange = range[k2..k2] + accept: KooRange(k2) + accept: k2.KooRange + let k2ranged: KooRange = k2 + accept: Koo(k2ranged) + accept: k2ranged.Koo + reject: # bug #18550 proc f(c: char): cstring = diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index f0262f528..6e5487d1b 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -224,13 +224,15 @@ sub/mmain.idx""", context doAssert exitCode == 0, msg let data = parseJson(readFile(output))["entries"] - doAssert data.len == 4 + doAssert data.len == 5 let doSomething = data[0] doAssert doSomething["name"].getStr == "doSomething" doAssert doSomething["type"].getStr == "skProc" doAssert doSomething["line"].getInt == 1 doAssert doSomething["col"].getInt == 0 doAssert doSomething["code"].getStr == "proc doSomething(x, y: int): int {.raises: [], tags: [], forbids: [].}" + let foo2 = data[4] + doAssert $foo2["signature"] == """{"arguments":[{"name":"x","type":"T"},{"name":"y","type":"U"},{"name":"z","type":"M"}],"genericParams":[{"name":"T","types":"int"},{"name":"M","types":"string"},{"name":"U"}]}""" block: # nim jsondoc # bug #11953 let file = testsDir / "misc/mjsondoc.nim" @@ -241,7 +243,7 @@ sub/mmain.idx""", context doAssert exitCode == 0, msg let data = parseJson(readFile(destDir / "mjsondoc.json"))["entries"] - doAssert data.len == 4 + doAssert data.len == 5 let doSomething = data[0] doAssert doSomething["name"].getStr == "doSomething" doAssert doSomething["type"].getStr == "skProc" diff --git a/tests/misc/trunner_special.nim b/tests/misc/trunner_special.nim index e13810722..e08b419b0 100644 --- a/tests/misc/trunner_special.nim +++ b/tests/misc/trunner_special.nim @@ -14,6 +14,10 @@ xxx test all tests/untestable/* here, possibly with adjustments to make running import std/[strformat,os,unittest,compilesettings] import stdtest/specialpaths + +from stdtest/testutils import disableSSLTesting + + const nim = getCurrentCompilerExe() mode = querySetting(backend) @@ -29,4 +33,5 @@ proc main = block: # SSL certificate check integration tests runCmd fmt"{nim} r {options} -d:ssl --threads:on --mm:refc {testsDir}/untestable/thttpclient_ssl_remotenetwork.nim" -main() +when not disableSSLTesting(): + main() diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim index 0d96a5e04..ce5334664 100644 --- a/tests/misc/tsizeof.nim +++ b/tests/misc/tsizeof.nim @@ -732,3 +732,11 @@ type doAssert sizeof(PackedUnion) == 11 doAssert alignof(PackedUnion) == 1 + +# bug #22553 +type + ChunkObj = object + data: UncheckedArray[byte] + +doAssert sizeof(ChunkObj) == 1 +doAssert offsetOf(ChunkObj, data) == 1 diff --git a/tests/modules/mincludeprefix.nim b/tests/modules/mincludeprefix.nim new file mode 100644 index 000000000..6d557a430 --- /dev/null +++ b/tests/modules/mincludeprefix.nim @@ -0,0 +1 @@ +const bar = 456 diff --git a/tests/modules/mincludetemplate.nim b/tests/modules/mincludetemplate.nim new file mode 100644 index 000000000..febe9bfcf --- /dev/null +++ b/tests/modules/mincludetemplate.nim @@ -0,0 +1 @@ +const foo = 123 diff --git a/tests/modules/tincludeprefix.nim b/tests/modules/tincludeprefix.nim new file mode 100644 index 000000000..d45a6eff3 --- /dev/null +++ b/tests/modules/tincludeprefix.nim @@ -0,0 +1,3 @@ +include ./[mincludeprefix, mincludetemplate] +doAssert foo == 123 +doAssert bar == 456 diff --git a/tests/modules/tincludetemplate.nim b/tests/modules/tincludetemplate.nim new file mode 100644 index 000000000..77e409ee5 --- /dev/null +++ b/tests/modules/tincludetemplate.nim @@ -0,0 +1,5 @@ +# issue #12539 + +template includePath(n: untyped) = include ../modules/n # But `include n` works +includePath(mincludetemplate) +doAssert foo == 123 diff --git a/tests/modules/tmodulesymtype.nim b/tests/modules/tmodulesymtype.nim index b1378ab69..d17c4cca4 100644 --- a/tests/modules/tmodulesymtype.nim +++ b/tests/modules/tmodulesymtype.nim @@ -13,3 +13,10 @@ proc foo() = sequtils foo() + +# issue #23399 +when isMainModule: + sequtils #[tt.Error + ^ expression has no type: sequtils]# + +discard diff --git a/tests/modules/treorder.nim b/tests/modules/treorder.nim index 286b50e22..ff0b2e071 100644 --- a/tests/modules/treorder.nim +++ b/tests/modules/treorder.nim @@ -8,6 +8,8 @@ defined {.experimental: "codeReordering".} +{.push callconv: stdcall.} + proc bar(x: T) proc foo() = @@ -41,3 +43,5 @@ using my, omy: int goo(3, 4) + +{.pop.} diff --git a/tests/msgs/tused2.nim b/tests/msgs/tused2.nim index f80c198d8..5ccda7737 100644 --- a/tests/msgs/tused2.nim +++ b/tests/msgs/tused2.nim @@ -7,12 +7,12 @@ mused2a.nim(12, 6) Hint: 'fn1' is declared but not used [XDeclaredButNotUsed] mused2a.nim(16, 5) Hint: 'fn4' is declared but not used [XDeclaredButNotUsed] mused2a.nim(20, 7) Hint: 'fn7' is declared but not used [XDeclaredButNotUsed] mused2a.nim(23, 6) Hint: 'T1' is declared but not used [XDeclaredButNotUsed] -mused2a.nim(1, 11) Warning: imported and not used: 'strutils' [UnusedImport] -mused2a.nim(3, 9) Warning: imported and not used: 'os' [UnusedImport] +mused2a.nim(1, 12) Warning: imported and not used: 'strutils' [UnusedImport] +mused2a.nim(3, 10) Warning: imported and not used: 'os' [UnusedImport] mused2a.nim(5, 23) Warning: imported and not used: 'typetraits2' [UnusedImport] -mused2a.nim(6, 9) Warning: imported and not used: 'setutils' [UnusedImport] +mused2a.nim(6, 10) Warning: imported and not used: 'setutils' [UnusedImport] tused2.nim(42, 8) Warning: imported and not used: 'mused2a' [UnusedImport] -tused2.nim(45, 11) Warning: imported and not used: 'strutils' [UnusedImport] +tused2.nim(45, 12) Warning: imported and not used: 'strutils' [UnusedImport] ''' """ diff --git a/tests/niminaction/Chapter8/sdl/sdl_test.nim b/tests/niminaction/Chapter8/sdl/sdl_test.nim index 1c4d258fb..db1700e0d 100644 --- a/tests/niminaction/Chapter8/sdl/sdl_test.nim +++ b/tests/niminaction/Chapter8/sdl/sdl_test.nim @@ -18,7 +18,7 @@ renderer.setDrawColor 29, 64, 153, 255 renderer.clear renderer.setDrawColor 255, 255, 255, 255 -when defined(c): +when false: # no long work with gcc 14! # just to ensure code from NimInAction still works, but # the `else` branch would work as well in C mode var points = [ diff --git a/tests/objects/tobject_default_value.nim b/tests/objects/tobject_default_value.nim index 152b355f4..0cd05e4f3 100644 --- a/tests/objects/tobject_default_value.nim +++ b/tests/objects/tobject_default_value.nim @@ -121,7 +121,7 @@ template main {.dirty.} = rVal: R = default(R) # Works fine objVal = default(Obj) - doAssert rVal == 0 # it should be 1 + doAssert rVal == 1 doAssert objVal.r == 1 block: # bug #16744 @@ -134,7 +134,7 @@ template main {.dirty.} = rVal: R = default(R) # Works fine objVal = Obj() - doAssert rVal == 0 # it should be 1 + doAssert rVal == 1 # it should be 1 doAssert objVal.r == 1 block: # bug #3608 @@ -744,6 +744,37 @@ template main {.dirty.} = var b = default ArrayObj2 doAssert b.list[North] == 1 + block: + type limited_float = range[1.2..20.0] + doAssert default(limited_float) == 1.2 + + + block: + type + range1 = range[1..10] + range2 = range[-1..10] + + proc foo = + doAssert default(range1) == 1 + doAssert default(range2) == -1 + + let s = default(array[5, range1]) + doAssert s == [range1 1, 1, 1, 1, 1] + + foo() + + block: + type + Object = object + id: range[1.2..29.3] + + var s = default(Object) + doAssert s.id == 1.2 + + block: # bug #23943 + type limited_int = range[1..20] + var d: limited_int; + doAssert d == 1 static: main() main() diff --git a/tests/objects/trequireinit.nim b/tests/objects/trequireinit.nim new file mode 100644 index 000000000..202667b02 --- /dev/null +++ b/tests/objects/trequireinit.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "The MPlayerObj type doesn't have a default value. The following fields must be initialized: foo." +""" + +type + MPlayerObj* {.requiresInit.} = object + foo: range[5..10] = 5 + +var a: MPlayerObj +echo a.foo \ No newline at end of file diff --git a/tests/objvariant/tconstobjvariant.nim b/tests/objvariant/tconstobjvariant.nim new file mode 100644 index 000000000..45a647707 --- /dev/null +++ b/tests/objvariant/tconstobjvariant.nim @@ -0,0 +1,18 @@ +# This is a sample code, the first echo statement prints out the error +type + A = object + case w: uint8 + of 1: + n: int + else: + other: string + +const + a = A(w: 1, n: 5) + +proc foo = + + let c = [a] + doAssert c[0].n == 5 + +foo() \ No newline at end of file diff --git a/tests/openarray/topenarray.nim b/tests/openarray/topenarray.nim index c752becf2..25b983651 100644 --- a/tests/openarray/topenarray.nim +++ b/tests/openarray/topenarray.nim @@ -48,6 +48,41 @@ proc main = doAssert testing(mySeq) == mySeq doAssert testing(mySeq[2..^2]) == mySeq[2..^2] + block: # bug #23321 + block: + proc foo(x: openArray[int]) = + doAssert x[0] == 0 + + var d = new array[1, int] + foo d[].toOpenArray(0, 0) + + block: + proc foo(x: openArray[int]) = + doAssert x[0] == 0 + + proc task(x: var array[1, int]): var array[1, int] = + result = x + var d: array[1, int] + foo task(d).toOpenArray(0, 0) + + block: + proc foo(x: openArray[int]) = + doAssert x[0] == 0 + + proc task(x: var array[1, int]): lent array[1, int] = + result = x + var d: array[1, int] + foo task(d).toOpenArray(0, 0) + + block: + proc foo(x: openArray[int]) = + doAssert x[0] == 0 + + proc task(x: var array[1, int]): ptr array[1, int] = + result = addr x + var d: array[1, int] + foo task(d)[].toOpenArray(0, 0) + main() static: main() diff --git a/tests/openarray/tuncheckedarray.nim b/tests/openarray/tuncheckedarray.nim new file mode 100644 index 000000000..c8ca9d2d4 --- /dev/null +++ b/tests/openarray/tuncheckedarray.nim @@ -0,0 +1,19 @@ +discard """ + exitcode: 0 + targets: "c cpp" +""" + +proc main = + block: # issue 19171 + var a = ['A'] + proc mutB(x: var openArray[char]) = + x[0] = 'B' + mutB(toOpenArray(cast[ptr UncheckedArray[char]](addr a), 0, 0)) + doAssert a[0] == 'B' + proc mutC(x: var openArray[char]; c: char) = + x[0] = c + let p = cast[ptr UncheckedArray[char]](addr a) + mutC(toOpenArray(p, 0, 0), 'C') + doAssert p[0] == 'C' + +main() diff --git a/tests/osproc/tnoexe.nim b/tests/osproc/tnoexe.nim new file mode 100644 index 000000000..19a3cca67 --- /dev/null +++ b/tests/osproc/tnoexe.nim @@ -0,0 +1,27 @@ +discard """ + output: '''true +true''' +""" + +import std/osproc + +const command = "lsaaa -lah" + +try: + let process = startProcess(command, options = {poUsePath}) + discard process.waitForExit() +except OSError as e: + echo e.errorCode != 0 + +# `poEvalCommand`, invokes the system shell to run the specified command +try: + let process = startProcess(command, options = {poUsePath, poEvalCommand}) + # linux + let exitCode = process.waitForExit() + echo exitCode != 0 +except OSError as e: + # Because the implementation of `poEvalCommand` on different platforms is inconsistent, + # Linux will not throw an exception, but Windows will throw an exception + + # windows + echo e.errorCode != 0 diff --git a/tests/osproc/twaitforexit.nim b/tests/osproc/twaitforexit.nim new file mode 100644 index 000000000..535faca63 --- /dev/null +++ b/tests/osproc/twaitforexit.nim @@ -0,0 +1,38 @@ +import std/[osproc, os, times] + +block: # bug #5091 + when defined(linux): + const filename = "false" + var p = startProcess(filename, options = {poStdErrToStdOut, poUsePath}) + os.sleep(1000) # make sure process has exited already + + let atStart = getTime() + const msWait = 2000 + + try: + discard waitForExit(p, msWait) + except OSError: + discard + + # check that we don't have to wait msWait milliseconds + doAssert(getTime() < atStart + milliseconds(msWait)) + +block: # bug #23825 + + # the sleep command might not be available in all Windows installations + + when defined(linux): + + var thr: array[0..99, Thread[int]] + + proc threadFunc(i: int) {.thread.} = + let sleepTime = float(i) / float(thr.len + 1) + doAssert sleepTime < 1.0 + let p = startProcess("sleep", workingDir = "", args = @[$sleepTime], options = {poUsePath, poParentStreams}) + # timeout = 1_000_000 seconds ~= 278 hours ~= 11.5 days + doAssert p.waitForExit(timeout=1_000_000_000) == 0 + + for i in low(thr)..high(thr): + createThread(thr[i], threadFunc, i) + + joinThreads(thr) diff --git a/tests/overflow/twronginference.nim b/tests/overflow/twronginference.nim new file mode 100644 index 000000000..34a982976 --- /dev/null +++ b/tests/overflow/twronginference.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "cannot convert 256 to int8" + line: 9 +""" + +# issue #23177 + +var x: int8 +x = 256 +echo x # 0 diff --git a/tests/overload/issue22142/tfail_implicit_ambiguous.nim b/tests/overload/issue22142/tfail_implicit_ambiguous.nim new file mode 100644 index 000000000..2586e0877 --- /dev/null +++ b/tests/overload/issue22142/tfail_implicit_ambiguous.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "ambiguous call" +""" +type + A[T] = object + C = object + +proc test[T: A](param: T): bool = false +proc test(param: A): bool = true +doAssert test(A[C]()) == true # previously would pass diff --git a/tests/overload/issue22142/tfail_nested_pointers.nim b/tests/overload/issue22142/tfail_nested_pointers.nim new file mode 100644 index 000000000..1603d98cb --- /dev/null +++ b/tests/overload/issue22142/tfail_nested_pointers.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "ambiguous call" +""" + +type + A[T] = object + C = object + x:int +proc p[T: A[ptr]](x:ptr[T]):bool = false +proc p(x: ptr[A[ptr]]):bool = true +var a: A[ptr[C]] +doAssert p(a.addr) == true diff --git a/tests/overload/issue22142/tfail_object_is_generic.nim b/tests/overload/issue22142/tfail_object_is_generic.nim new file mode 100644 index 000000000..b46795bd5 --- /dev/null +++ b/tests/overload/issue22142/tfail_object_is_generic.nim @@ -0,0 +1,16 @@ +discard """ + errormsg: "ambiguous call" +""" + +#[ +As of the time of writing `object` needs some special +treament in order to be considered "generic" in the right +context when used implicitly +]# + +type + C = object + +proc test[T: object](param: T): bool = false +proc test(param: object): bool = true +doAssert test(C()) == true # previously would pass diff --git a/tests/overload/issue22142/tfail_typeclass_var_invar.nim b/tests/overload/issue22142/tfail_typeclass_var_invar.nim new file mode 100644 index 000000000..07db65fef --- /dev/null +++ b/tests/overload/issue22142/tfail_typeclass_var_invar.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "ambiguous call" +""" + +type C = object +proc test[T: ptr](param: var T): bool = false +proc test(param: var ptr): bool = true +var d: ptr[C] +doAssert test(d) == true # previously would pass diff --git a/tests/overload/issue22142/tissue22142_shouldpass.nim b/tests/overload/issue22142/tissue22142_shouldpass.nim new file mode 100644 index 000000000..90d4efe51 --- /dev/null +++ b/tests/overload/issue22142/tissue22142_shouldpass.nim @@ -0,0 +1,68 @@ +type + A[T] = object of RootObj + B[T] = object + C = object + x:int + +# change (previously true) +block: + proc test[J;H: A[J];T: B[H]](param: T): bool = false + proc test[T](param: B[T]): bool = true + doAssert test(B[A[int]]()) == false +block: # object is more specific then `T` + proc p[H:object;T:ptr[H]](param:T):bool = false + proc p[T](param:ptr[T]):bool= true + var l: ptr[C] + doAssert p(l) == false +block: + proc p[T:A[object]](param:T):bool = false + proc p[T](param: A[T]):bool= true + doAssert p(A[C]()) == false +block: + proc test[H;T: A[H]](param: T): bool = false + proc test(param: A): bool = true + doAssert test(A[C]()) == false + +# change (previously ambiguous) +block: + proc p[T](a: A[T]): bool = false + proc p[T: object](a: T): bool = true + doAssert p(A[int]()) == false +block: # A is more specific than `object` + proc test[T: A](param: T): bool = false + proc test[T: object](param: T): bool = true + doAssert test(A[int]()) == false +block: + proc test[T: A](param: T): bool = false + proc test(param: object): bool = true + doAssert test(A[int]()) == false +block: + proc test[H;T: A[H]](param: T): bool = false + proc test(param: object): bool = true + doAssert test(A[C]()) == false +block: + proc test[H;T: A[B[H]]](param: T): bool = false + proc test[T: object](param: T): bool = true + doAssert test(A[B[int]]()) == false +block: + #[ + This was referenced in the nim compiler source (`sumGeneric`) as a case + that was supposed to not be ambiguous, yet it was + ]# + proc test[J;H:A[J]; T: A[H]](param: T): bool = false + proc test[H;T: A[H]](param: T): bool = true + doAssert test(A[A[C]]()) == false +block: + proc test[J;T:A[J]](param: A[T]): bool = false + proc test[T](param: A[T]): bool = true + doAssert test(A[A[C]]()) == false +block: + proc test[T](param: A[T]): bool = false + proc test[T: object](param: A[T]): bool = true + doAssert test(A[C]()) == true + + +block: #anti-regression (object is more specific then `T`) + proc test[J;T:A[J]](param: A[T]): bool = false + proc test(param: A[A[object]]): bool = true + doAssert test(A[A[C]]()) == true \ No newline at end of file diff --git a/tests/overload/m19737.nim b/tests/overload/m19737.nim new file mode 100644 index 000000000..7f7ac98e2 --- /dev/null +++ b/tests/overload/m19737.nim @@ -0,0 +1,10 @@ +type + UInt128* = object + lo, hi: uint64 + +func `<`*(x, y: UInt128): bool = + (x.hi < y.hi) or ((x.hi == y.hi) and (x.lo < y.lo)) + +when not defined(works): + func `>`*(x, y: UInt128): bool = + (x.hi > y.hi) or ((x.hi == y.hi) and (x.lo > y.lo)) diff --git a/tests/overload/mvaruintconv.nim b/tests/overload/mvaruintconv.nim new file mode 100644 index 000000000..b889c90cf --- /dev/null +++ b/tests/overload/mvaruintconv.nim @@ -0,0 +1,145 @@ +import + std/[macros, tables, hashes] + +export + macros + +type + FieldDescription* = object + name*: NimNode + isPublic*: bool + isDiscriminator*: bool + typ*: NimNode + pragmas*: NimNode + caseField*: NimNode + caseBranch*: NimNode + +{.push raises: [].} + +func isTuple*(t: NimNode): bool = + t.kind == nnkBracketExpr and t[0].kind == nnkSym and eqIdent(t[0], "tuple") + +macro isTuple*(T: type): untyped = + newLit(isTuple(getType(T)[1])) + +proc collectFieldsFromRecList(result: var seq[FieldDescription], + n: NimNode, + parentCaseField: NimNode = nil, + parentCaseBranch: NimNode = nil, + isDiscriminator = false) = + case n.kind + of nnkRecList: + for entry in n: + collectFieldsFromRecList result, entry, + parentCaseField, parentCaseBranch + of nnkRecWhen: + for branch in n: + case branch.kind: + of nnkElifBranch: + collectFieldsFromRecList result, branch[1], + parentCaseField, parentCaseBranch + of nnkElse: + collectFieldsFromRecList result, branch[0], + parentCaseField, parentCaseBranch + else: + doAssert false + + of nnkRecCase: + collectFieldsFromRecList result, n[0], + parentCaseField, + parentCaseBranch, + isDiscriminator = true + + for i in 1 ..< n.len: + let branch = n[i] + case branch.kind + of nnkOfBranch: + collectFieldsFromRecList result, branch[^1], n[0], branch + of nnkElse: + collectFieldsFromRecList result, branch[0], n[0], branch + else: + doAssert false + + of nnkIdentDefs: + let fieldType = n[^2] + for i in 0 ..< n.len - 2: + var field: FieldDescription + field.name = n[i] + field.typ = fieldType + field.caseField = parentCaseField + field.caseBranch = parentCaseBranch + field.isDiscriminator = isDiscriminator + + if field.name.kind == nnkPragmaExpr: + field.pragmas = field.name[1] + field.name = field.name[0] + + if field.name.kind == nnkPostfix: + field.isPublic = true + field.name = field.name[1] + + result.add field + + of nnkSym: + result.add FieldDescription( + name: n, + typ: getType(n), + caseField: parentCaseField, + caseBranch: parentCaseBranch, + isDiscriminator: isDiscriminator) + + of nnkNilLit, nnkDiscardStmt, nnkCommentStmt, nnkEmpty: + discard + + else: + doAssert false, "Unexpected nodes in recordFields:\n" & n.treeRepr + +proc collectFieldsInHierarchy(result: var seq[FieldDescription], + objectType: NimNode) = + var objectType = objectType + + objectType.expectKind {nnkObjectTy, nnkRefTy} + + if objectType.kind == nnkRefTy: + objectType = objectType[0] + + objectType.expectKind nnkObjectTy + + var baseType = objectType[1] + if baseType.kind != nnkEmpty: + baseType.expectKind nnkOfInherit + baseType = baseType[0] + baseType.expectKind nnkSym + baseType = getImpl(baseType) + baseType.expectKind nnkTypeDef + baseType = baseType[2] + baseType.expectKind {nnkObjectTy, nnkRefTy} + collectFieldsInHierarchy result, baseType + + let recList = objectType[2] + collectFieldsFromRecList result, recList + +proc recordFields*(typeImpl: NimNode): seq[FieldDescription] = + if typeImpl.isTuple: + for i in 1 ..< typeImpl.len: + result.add FieldDescription(typ: typeImpl[i], name: ident("Field" & $(i - 1))) + return + + let objectType = case typeImpl.kind + of nnkObjectTy: typeImpl + of nnkTypeDef: typeImpl[2] + else: + macros.error("object type expected", typeImpl) + return + + collectFieldsInHierarchy(result, objectType) + +macro field*(obj: typed, fieldName: static string): untyped = + newDotExpr(obj, ident fieldName) + +proc skipPragma*(n: NimNode): NimNode = + if n.kind == nnkPragmaExpr: n[0] + else: n + + +{.pop.} diff --git a/tests/overload/t19737.nim b/tests/overload/t19737.nim new file mode 100644 index 000000000..b33ba9d8b --- /dev/null +++ b/tests/overload/t19737.nim @@ -0,0 +1,15 @@ +# issue #19737 + +import ./m19737 + +var m: seq[uint64] + +proc foo(x: bool) = discard + +proc test[T: uint64|uint32](s: var seq[T]) = + var tmp = newSeq[T](1) + s = newSeq[T](1) + + foo s[0] > tmp[0] + +test(m) diff --git a/tests/overload/t23249.nim b/tests/overload/t23249.nim new file mode 100644 index 000000000..f4657833b --- /dev/null +++ b/tests/overload/t23249.nim @@ -0,0 +1,17 @@ +# issue #23249 + +type Control* = object +proc onAction*(c: Control, handler: proc(e: int) {.gcsafe.}) = discard +proc onAction*(c: Control, handler: proc() {.gcsafe.}) = discard + +template setControlHandlerBlock(c: Control, p: untyped, a: untyped) = + when compiles(c.p(nil)): + c.p() do() {.gcsafe.}: a + else: + c.p = proc() {.gcsafe.} = + a + +proc mkLayout() = + var b: Control + setControlHandlerBlock(b, onAction): + echo "hi" diff --git a/tests/overload/t23755.nim b/tests/overload/t23755.nim new file mode 100644 index 000000000..de338a2ce --- /dev/null +++ b/tests/overload/t23755.nim @@ -0,0 +1,62 @@ +type + BigInt[bits: static int] = object + limbs: array[8, uint64] + +block: + proc view[N](a: array[N, uint64]) = + discard + + proc view[N](a: var array[N, uint64]) = + discard + + var r: BigInt[64] + r.limbs.view() + + +type Limbs[N: static int] = array[N, uint64] + +block: + proc view(a: Limbs) = + discard + + proc view(a: var Limbs) = + discard + + var r: BigInt[64] + r.limbs.view() + + +block: + type IntArray[N: static[int]] = array[N, int] + + proc p[T](a: IntArray[T]): bool= true + proc p(a: IntArray[5]): bool= false + + var s: IntArray[5] + doAssert s.p == false + +block: + type IntArray[N: static[int]] = array[N, int] + + proc `$`(a: IntArray): string = + return "test" + + var s: IntArray[5] = [1,1,1,1,1] + doAssert `$`(s) == "test" + +block: + proc p[n:static[int]](a: array[n, char]):bool=true + proc p[T, IDX](a: array[IDX, T]):bool=false + + var g: array[32, char] + doAssert p(g) + +block: # issue #23823 + func p[N,T](a, b: array[N,T]) = + discard + + func p[N: static int; T](x, y: array[N, T]) = + discard + + var a: array[5, int] + p(a,a) diff --git a/tests/overload/t8829.nim b/tests/overload/t8829.nim index fe0dbf2bf..85d87f136 100644 --- a/tests/overload/t8829.nim +++ b/tests/overload/t8829.nim @@ -2,7 +2,7 @@ block: let txt = "Hello World" template `[]`[T](p: ptr T, span: Slice[int]): untyped = - toOpenArray(cast[ptr array[0, T]](p)[], span.a, span.b) + toOpenArray(cast[ptr UncheckedArray[T]](p), span.a, span.b) doAssert $cast[ptr uint8](txt[0].addr)[0 ..< txt.len] == "[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]" @@ -12,7 +12,7 @@ block: let txt = "Hello World" template `[]`[T](p: ptr T, span: Slice[int]): untyped = - toOpenArray(cast[ptr array[0, T]](p)[], span.a, span.b) + toOpenArray(cast[ptr UncheckedArray[T]](p), span.a, span.b) doAssert $cast[ptr uint8](txt[0].addr)[0 ..< txt.len] == "[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]" diff --git a/tests/overload/tgenericalias.nim b/tests/overload/tgenericalias.nim new file mode 100644 index 000000000..50a44bd32 --- /dev/null +++ b/tests/overload/tgenericalias.nim @@ -0,0 +1,13 @@ +block: # issue #13799 + type + X[A, B] = object + a: A + b: B + + Y[A] = X[A, int] + template s(T: type X): X = T() + template t[A, B](T: type X[A, B]): X[A, B] = T() + proc works1(): Y[int] = s(X[int, int]) + proc works2(): Y[int] = t(X[int, int]) + proc works3(): Y[int] = t(Y[int]) + proc broken(): Y[int] = s(Y[int]) diff --git a/tests/overload/tor_isnt_better.nim b/tests/overload/tor_isnt_better.nim index ce92009d0..bee125386 100644 --- a/tests/overload/tor_isnt_better.nim +++ b/tests/overload/tor_isnt_better.nim @@ -7,7 +7,6 @@ block: # PR #22261 proc d(x: int | D[SomeInteger]):bool= true doAssert d(D[5]()) == false - block: # bug #8568 #[ Since PR #22261 and amendment has been made. Since D is a subset of D | E but @@ -17,3 +16,26 @@ block: # bug #8568 proc g(a: D|E): string = "foo D|E" proc g(a: D): string = "foo D" doAssert g(D[int]()) == "foo D" + +type Obj1[T] = object + v: T +converter toObj1[T](t: T): Obj1[T] = return Obj1[T](v: t) +block: # issue #10019 + proc fun1[T](elements: seq[T]): string = "fun1 seq" + proc fun1(o: object|tuple): string = "fun1 object|tuple" + proc fun2[T](elements: openArray[T]): string = "fun2 openarray" + proc fun2(o: object): string = "fun2 object" + proc fun_bug[T](elements: openArray[T]): string = "fun_bug openarray" + proc fun_bug(o: object|tuple):string = "fun_bug object|tuple" + proc main() = + var x = @["hello", "world"] + block: + # no ambiguity error shown here even though this would compile if we remove either 1st or 2nd overload of fun1 + doAssert fun1(x) == "fun1 seq" + block: + # ditto + doAssert fun2(x) == "fun2 openarray" + block: + # Error: ambiguous call; both t0065.fun_bug(elements: openarray[T])[declared in t0065.nim(17, 5)] and t0065.fun_bug(o: object or tuple)[declared in t0065.nim(20, 5)] match for: (array[0..1, string]) + doAssert fun_bug(x) == "fun_bug openarray" + main() diff --git a/tests/overload/toverload_issues.nim b/tests/overload/toverload_issues.nim index 5db7b54fa..26bf89091 100644 --- a/tests/overload/toverload_issues.nim +++ b/tests/overload/toverload_issues.nim @@ -77,27 +77,30 @@ testPred(1) -# bug #6526 -type - BaseObj = ref object of RootObj - DerivedObj = ref object of BaseObj - OtherDerivate = ref object of BaseObj - -proc `==`*[T1, T2: BaseObj](a: T1, b: T2): bool = - echo "baseobj ==" - return true - -let a = DerivedObj() -let b = DerivedObj() -echo a == b - -proc `==`*[T1, T2: OtherDerivate](a: T1, b: T2): bool = - echo "even better! ==" - return true - -let a2 = OtherDerivate() -let b2 = OtherDerivate() -echo a2 == b2 +block: # bug #6526 + type + BaseObj = ref object of RootObj + DerivedObj = ref object of BaseObj + OtherDerivate = ref object of BaseObj + + proc p[T](a: T, b: T): bool = + assert false + + proc p[T1, T2: BaseObj](a: T1, b: T2): bool = + echo "baseobj ==" + return true + + let a = DerivedObj() + let b = DerivedObj() + echo p(a,b) + + proc p[T1, T2: OtherDerivate](a: T1, b: T2): bool = + echo "even better! ==" + return true + + let a2 = OtherDerivate() + let b2 = OtherDerivate() + echo p(a2, b2) diff --git a/tests/overload/toverload_various.nim b/tests/overload/toverload_various.nim index 0741fce60..d195a069d 100644 --- a/tests/overload/toverload_various.nim +++ b/tests/overload/toverload_various.nim @@ -506,3 +506,63 @@ block: doAssert(p2(F(float,1.0),F(float,2)) == 3.0) doAssert(p2(F(float,1.0),F(float,2.0)) == 3.0) #doAssert(p2(F(float,1),F(int,2.0)) == 3.0) + +block: # PR #23870 + type + A {.inheritable.} = object + B = object of A + C = object of B + + proc p[T: A](x: T): int = 0 + proc p[T: B](x: T): int = 1 + + proc d(x: A): int = 0 + proc d(x: B): int = 1 + + proc g[T:A](x: typedesc[T]): int = 0 + proc g[T: B](x: typedesc[T]): int = 1 + + proc f[T](x: typedesc[T]): int = 0 + proc f[T:B](x: typedesc[T]): int = 1 + + assert p(C()) == 1 + assert d(C()) == 1 + assert g(C) == 1 + assert f(C) == 1 + +block: # PR #23870 + type + A = object of RootObj + PT = proc(ev: A) {.closure.} + sdt = seq[(PT, PT)] + + proc encap() = + proc p(a: A) {.closure.} = + discard + + var s: sdt + s.add (p, nil) + + encap() + +block: # PR #23870 + type + A = object of RootObj + B = object of A + C = object of B + + proc p(a: B | RootObj): int = + 0 + + proc p(a: A | A): int = + 1 + + assert p(C()) == 0 + + proc d(a: RootObj | B): int = + 0 + + proc d(a: A | A): int = + 1 + + assert d(C()) == 0 diff --git a/tests/overload/tuntypedarg.nim b/tests/overload/tuntypedarg.nim new file mode 100644 index 000000000..9aa4fad3b --- /dev/null +++ b/tests/overload/tuntypedarg.nim @@ -0,0 +1,19 @@ +import macros + +block: # issue #7385 + type CustomSeq[T] = object + data: seq[T] + macro `[]`[T](s: CustomSeq[T], args: varargs[untyped]): untyped = + ## The end goal is to replace the joker "_" by something else + result = newIntLitNode(10) + proc foo1(): CustomSeq[int] = + result.data.newSeq(10) + # works since no overload matches first argument with type `CustomSeq` + # except magic `[]`, which always matches without checking arguments + doAssert result[_] == 10 + doAssert foo1() == CustomSeq[int](data: newSeq[int](10)) + proc foo2[T](): CustomSeq[T] = + result.data.newSeq(10) + # works fine with generic return type + doAssert result[_] == 10 + doAssert foo2[int]() == CustomSeq[int](data: newSeq[int](10)) diff --git a/tests/overload/tvaruintconv.nim b/tests/overload/tvaruintconv.nim new file mode 100644 index 000000000..87ebd285d --- /dev/null +++ b/tests/overload/tvaruintconv.nim @@ -0,0 +1,207 @@ +discard """ + action: compile +""" + +# https://github.com/status-im/nimbus-eth2/pull/6554#issuecomment-2354977102 +# failed with "for a 'var' type a variable needs to be passed; but 'uint64(result)' is immutable" + +import + std/[typetraits, macros] + +type + DefaultFlavor = object + +template serializationFormatImpl(Name: untyped) {.dirty.} = + type Name = object + +template serializationFormat(Name: untyped) = + serializationFormatImpl(Name) + +template setReader(Format, FormatReader: distinct type) = + when arity(FormatReader) > 1: + template Reader(T: type Format, F: distinct type = DefaultFlavor): type = FormatReader[F] + else: + template ReaderType(T: type Format): type = FormatReader + template Reader(T: type Format): type = FormatReader + +template useDefaultReaderIn(T: untyped, Flavor: type) = + mixin Reader + + template readValue(r: var Reader(Flavor), value: var T) = + mixin readRecordValue + readRecordValue(r, value) + +import mvaruintconv + +type + FieldTag[RecordType: object; fieldName: static string] = distinct void + +func declval*(T: type): T {.compileTime.} = + default(ptr T)[] + +macro enumAllSerializedFieldsImpl(T: type, body: untyped): untyped = + var typeAst = getType(T)[1] + var typeImpl: NimNode + let isSymbol = not typeAst.isTuple + + if not isSymbol: + typeImpl = typeAst + else: + typeImpl = getImpl(typeAst) + result = newStmtList() + + var i = 0 + for field in recordFields(typeImpl): + let + fieldIdent = field.name + realFieldName = newLit($fieldIdent.skipPragma) + fieldName = realFieldName + fieldIndex = newLit(i) + + let fieldNameDefs = + if isSymbol: + quote: + const fieldName {.inject, used.} = `fieldName` + const realFieldName {.inject, used.} = `realFieldName` + else: + quote: + const fieldName {.inject, used.} = $`fieldIndex` + const realFieldName {.inject, used.} = $`fieldIndex` + + let field = + if isSymbol: + quote do: declval(`T`).`fieldIdent` + else: + quote do: declval(`T`)[`fieldIndex`] + + result.add quote do: + block: + `fieldNameDefs` + + template FieldType: untyped {.inject, used.} = typeof(`field`) + + `body` + + # echo repr(result) + +template enumAllSerializedFields(T: type, body): untyped = + enumAllSerializedFieldsImpl(T, body) + +type + FieldReader[RecordType, Reader] = tuple[ + fieldName: string, + reader: proc (rec: var RecordType, reader: var Reader) + {.gcsafe, nimcall.} + ] + +proc totalSerializedFieldsImpl(T: type): int = + mixin enumAllSerializedFields + enumAllSerializedFields(T): inc result + +template totalSerializedFields(T: type): int = + (static(totalSerializedFieldsImpl(T))) + +template GetFieldType(FT: type FieldTag): type = + typeof field(declval(FT.RecordType), FT.fieldName) + +proc makeFieldReadersTable(RecordType, ReaderType: distinct type, + numFields: static[int]): + array[numFields, FieldReader[RecordType, ReaderType]] = + mixin enumAllSerializedFields, handleReadException + var idx = 0 + + enumAllSerializedFields(RecordType): + proc readField(obj: var RecordType, reader: var ReaderType) + {.gcsafe, nimcall.} = + + mixin readValue + + type F = FieldTag[RecordType, realFieldName] + field(obj, realFieldName) = reader.readValue(GetFieldType(F)) + + result[idx] = (fieldName, readField) + inc idx + +proc fieldReadersTable(RecordType, ReaderType: distinct type): auto = + mixin readValue + type T = RecordType + const numFields = totalSerializedFields(T) + var tbl {.threadvar.}: ref array[numFields, FieldReader[RecordType, ReaderType]] + if tbl == nil: + tbl = new typeof(tbl) + tbl[] = makeFieldReadersTable(RecordType, ReaderType, numFields) + return addr(tbl[]) + +proc readValue(reader: var auto, T: type): T = + mixin readValue + reader.readValue(result) + +template decode(Format: distinct type, + input: string, + RecordType: distinct type): auto = + mixin Reader + block: # https://github.com/nim-lang/Nim/issues/22874 + var reader: Reader(Format) + reader.readValue(RecordType) + +template readValue(Format: type, + ValueType: type): untyped = + mixin Reader, init, readValue + var reader: Reader(Format) + readValue reader, ValueType + +template parseArrayImpl(numElem: untyped, + actionValue: untyped) = + actionValue + +serializationFormat Json +template createJsonFlavor(FlavorName: untyped, + skipNullFields = false) {.dirty.} = + type FlavorName = object + + template Reader(T: type FlavorName): type = Reader(Json, FlavorName) +type + JsonReader[Flavor = DefaultFlavor] = object + +Json.setReader JsonReader + +template parseArray(r: var JsonReader; body: untyped) = + parseArrayImpl(idx): body + +template parseArray(r: var JsonReader; idx: untyped; body: untyped) = + parseArrayImpl(idx): body + +proc readRecordValue[T](r: var JsonReader, value: var T) = + type + ReaderType {.used.} = type r + T = type value + + discard T.fieldReadersTable(ReaderType) + +proc readValue[T](r: var JsonReader, value: var T) = + mixin readValue + + when value is seq: + r.parseArray: + readValue(r, value[0]) + + elif value is object: + readRecordValue(r, value) + +type + RemoteSignerInfo = object + id: uint32 + RemoteKeystore = object + +proc readValue(reader: var JsonReader, value: var RemoteKeystore) = + discard reader.readValue(seq[RemoteSignerInfo]) + +createJsonFlavor RestJson +useDefaultReaderIn(RemoteSignerInfo, RestJson) +proc readValue(reader: var JsonReader[RestJson], value: var uint64) = + discard reader.readValue(string) + +discard Json.decode("", RemoteKeystore) +block: # https://github.com/nim-lang/Nim/issues/22874 + var reader: Reader(RestJson) + discard reader.readValue(RemoteSignerInfo) diff --git a/tests/parallel/tsendtwice.nim b/tests/parallel/tsendtwice.nim index 6bf5e5ebb..9f4a2e06e 100644 --- a/tests/parallel/tsendtwice.nim +++ b/tests/parallel/tsendtwice.nim @@ -1,18 +1,10 @@ discard """ - output: '''ob2 @[] -ob @[] -ob3 @[] -3 -ob2 @[] -ob @[] -ob3 @[] -''' matrix: "--mm:refc" """ # bug #4776 -import tables +import tables, algorithm type Base* = ref object of RootObj @@ -35,20 +27,21 @@ globalTable.add("ob", d) globalTable.add("ob2", d) globalTable.add("ob3", d) +proc `<`(x, y: seq[int]): bool = x.len < y.len +proc kvs(t: TableRef[string, Base]): seq[(string, seq[int])] = + for k, v in t.pairs: result.add (k, v.someSeq) + result.sort + proc testThread(channel: ptr TableChannel) {.thread.} = globalTable = channel[].recv() - for k, v in pairs globaltable: - echo k, " ", v.someSeq var myObj: Base deepCopy(myObj, globalTable["ob"]) myObj.someSeq = newSeq[int](100) let table = channel[].recv() # same table - echo table.len - for k, v in mpairs table: - echo k, " ", v.someSeq assert(table.contains("ob")) # fails! assert(table.contains("ob2")) # fails! assert(table.contains("ob3")) # fails! + assert table.kvs == globalTable.kvs # Last to see above spot checks first var channel: TableChannel diff --git a/tests/parser/tbinarynotindented.nim b/tests/parser/tbinarynotindented.nim new file mode 100644 index 000000000..8d124aade --- /dev/null +++ b/tests/parser/tbinarynotindented.nim @@ -0,0 +1,3 @@ +type Foo = ref int + not nil #[tt.Error + ^ invalid indentation]# diff --git a/tests/parser/tbinarynotsameline.nim b/tests/parser/tbinarynotsameline.nim new file mode 100644 index 000000000..ca417e023 --- /dev/null +++ b/tests/parser/tbinarynotsameline.nim @@ -0,0 +1,10 @@ +# issue #23565 + +func foo: bool = + true + +const bar = block: + type T = int + not foo() + +doAssert not bar diff --git a/tests/pragmas/monoff1.nim b/tests/pragmas/monoff1.nim new file mode 100644 index 000000000..85d6c57b3 --- /dev/null +++ b/tests/pragmas/monoff1.nim @@ -0,0 +1 @@ +proc on*() = discard diff --git a/tests/pragmas/mqualifiedmacro.nim b/tests/pragmas/mqualifiedmacro.nim new file mode 100644 index 000000000..908973206 --- /dev/null +++ b/tests/pragmas/mqualifiedmacro.nim @@ -0,0 +1,10 @@ +template t*(x:untyped): untyped = + echo "template t" + +import macros +macro m*(name: static string, x: untyped): untyped = + let newName = ident(name) + result = quote do: + type `newName` = object + if result.kind == nnkStmtList: + result = result[^1] diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim index 9ffa9a33d..11a6df813 100644 --- a/tests/pragmas/tcustom_pragma.nim +++ b/tests/pragmas/tcustom_pragma.nim @@ -531,3 +531,10 @@ block: check(a) check(b) + +block: # https://forum.nim-lang.org/t/12522, backticks + template `mypragma`() {.pragma.} + # Error: invalid pragma: `mypragma` + type Test = object + field {.`mypragma`.}: int + doAssert Test().field.hasCustomPragma(mypragma) diff --git a/tests/pragmas/tonoff1.nim b/tests/pragmas/tonoff1.nim new file mode 100644 index 000000000..20ba7def2 --- /dev/null +++ b/tests/pragmas/tonoff1.nim @@ -0,0 +1,8 @@ +# issue #23002 + +import monoff1 + +proc test() = + {.warning[ProveInit]: on.} + +test() diff --git a/tests/pragmas/tonoff2.nim b/tests/pragmas/tonoff2.nim new file mode 100644 index 000000000..9dff5ef11 --- /dev/null +++ b/tests/pragmas/tonoff2.nim @@ -0,0 +1,14 @@ +discard """ + action: compile +""" + +# issue #22841 + +import unittest + +proc on() = + discard + +suite "some suite": + test "some test": + discard diff --git a/tests/pragmas/tpush.nim b/tests/pragmas/tpush.nim index 8ebbfe3d3..9c6b85c4e 100644 --- a/tests/pragmas/tpush.nim +++ b/tests/pragmas/tpush.nim @@ -99,3 +99,46 @@ block: # bug #23019 k(w) {.pop.} {.pop.} + +{.push exportC.} + +block: + proc foo11() = + const factor = [1, 2, 3, 4] + doAssert factor[0] == 1 + proc foo21() = + const factor = [1, 2, 3, 4] + doAssert factor[0] == 1 + + foo11() + foo21() + +template foo31() = + let factor = [1, 2, 3, 4] + doAssert factor[0] == 1 +template foo41() = + let factor = [1, 2, 3, 4] + doAssert factor[0] == 1 + +foo31() +foo41() + +{.pop.} + +import macros + +block: + {.push deprecated.} + template test() = discard + test() + {.pop.} + macro foo(): bool = + let ast = getImpl(bindSym"test") + var found = false + if ast[4].kind == nnkPragma: + for x in ast[4]: + if x.eqIdent"deprecated": + found = true + break + result = newLit(found) + doAssert foo() diff --git a/tests/pragmas/tpushnotes.nim b/tests/pragmas/tpushnotes.nim new file mode 100644 index 000000000..27ba0bec4 --- /dev/null +++ b/tests/pragmas/tpushnotes.nim @@ -0,0 +1,13 @@ +discard """ + matrix: "--warningAsError:HoleEnumConv" +""" + +type + e = enum + a = 0 + b = 2 + +var i: int +{.push warning[HoleEnumConv]:off.} +discard i.e +{.pop.} diff --git a/tests/pragmas/tqualifiedmacro.nim b/tests/pragmas/tqualifiedmacro.nim new file mode 100644 index 000000000..bc95ec1ea --- /dev/null +++ b/tests/pragmas/tqualifiedmacro.nim @@ -0,0 +1,14 @@ +discard """ + output: ''' +template t +''' +""" + +# issue #12696 + +import mqualifiedmacro +proc p() {. mqualifiedmacro.t .} = # errors with identifier expected but a.t found + echo "proc p" + +type Foo {. mqualifiedmacro.m("Bar") .} = object +doAssert Bar is object diff --git a/tests/proc/t23874.nim b/tests/proc/t23874.nim new file mode 100644 index 000000000..940bc4ac8 --- /dev/null +++ b/tests/proc/t23874.nim @@ -0,0 +1,26 @@ +block: + type Head[T] = object + wasc: bool + + proc `=destroy`[T](x: var Head[T]) = + discard + + proc `=copy`[T](x: var Head[T], y: Head[T]) = + x.wasc = true + + proc `=dup`[T](x: Head[T]): Head[T] = + result.wasc = true + + proc update(h: var Head) = + discard + + proc digest(h: sink Head) = + assert h.wasc + + var h = Head[int](wasc: false) + h.digest() # sink h + h.update() # use after sink + +block: + proc two(a: sink auto) =discard + assert typeof(two[int]) is proc(a: sink int) {.nimcall.} diff --git a/tests/proc/texplicitgenericcount.nim b/tests/proc/texplicitgenericcount.nim new file mode 100644 index 000000000..8654a1d13 --- /dev/null +++ b/tests/proc/texplicitgenericcount.nim @@ -0,0 +1,24 @@ +discard """ + cmd: "nim check -d:testsConciseTypeMismatch $file" +""" + +proc foo[T, U](x: T, y: U): (T, U) = (x, y) + +let x = foo[int](1, 2) #[tt.Error + ^ type mismatch +Expression: foo[int](1, 2) + [1] 1: int literal(1) + [2] 2: int literal(2) + +Expected one of (first mismatch at [position]): +[2] proc foo[T, U](x: T; y: U): (T, U) + missing generic parameter: U]# +let y = foo[int, float, string](1, 2) #[tt.Error + ^ type mismatch +Expression: foo[int, float, string](1, 2) + [1] 1: int literal(1) + [2] 2: int literal(2) + +Expected one of (first mismatch at [position]): +[3] proc foo[T, U](x: T; y: U): (T, U) + extra generic param given]# diff --git a/tests/proc/texplicitgenericcountverbose.nim b/tests/proc/texplicitgenericcountverbose.nim new file mode 100644 index 000000000..76228eeaf --- /dev/null +++ b/tests/proc/texplicitgenericcountverbose.nim @@ -0,0 +1,22 @@ +discard """ + cmd: "nim check $file" +""" + +proc foo[T, U](x: T, y: U): (T, U) = (x, y) + +let x = foo[int](1, 2) #[tt.Error + ^ type mismatch: got <int literal(1), int literal(2)> +but expected one of: +proc foo[T, U](x: T; y: U): (T, U) + first type mismatch at position: 2 in generic parameters + missing generic parameter: U + +expression: foo[int](1, 2)]# +let y = foo[int, float, string](1, 2) #[tt.Error + ^ type mismatch: got <int literal(1), int literal(2)> +but expected one of: +proc foo[T, U](x: T; y: U): (T, U) + first type mismatch at position: 3 in generic parameters + extra generic param given + +expression: foo[int, float, string](1, 2)]# diff --git a/tests/proc/texplicitgenerics.nim b/tests/proc/texplicitgenerics.nim new file mode 100644 index 000000000..833d77b3b --- /dev/null +++ b/tests/proc/texplicitgenerics.nim @@ -0,0 +1,55 @@ +block: # issue #16376 + type + Matrix[T] = object + data: T + proc randMatrix[T](m, n: int, max: T): Matrix[T] = discard + proc randMatrix[T](m, n: int, x: Slice[T]): Matrix[T] = discard + template randMatrix[T](m, n: int): Matrix[T] = randMatrix[T](m, n, T(1.0)) + let B = randMatrix[float32](20, 10) + +block: # different generic param counts + type + Matrix[T] = object + data: T + proc randMatrix[T](m: T, n: T): Matrix[T] = Matrix[T](data: T(1.0)) + proc randMatrix[T; U: not T](m: T, n: U): (Matrix[T], U) = (Matrix[T](data: T(1.0)), default(U)) + let b = randMatrix[float32](20, 10) + doAssert b == Matrix[float32](data: 1.0) + +block: # above for templates + type + Matrix[T] = object + data: T + template randMatrix[T](m: T, n: T): Matrix[T] = Matrix[T](data: T(1.0)) + template randMatrix[T; U: not T](m: T, n: U): (Matrix[T], U) = (Matrix[T](data: T(1.0)), default(U)) + let b = randMatrix[float32](20, 10) + doAssert b == Matrix[float32](data: 1.0) + +block: # sigmatch can't handle this without pre-instantiating the type: + # minimized from numericalnim + type Foo[T] = proc (x: T) + proc foo[T](x: T) = discard + proc bar[T](f: Foo[T]) = discard + bar[int](foo) + +block: # ditto but may be wrong minimization + # minimized from measuremancer + type Foo[T] = object + proc foo[T](): Foo[T] = Foo[T]() + # this is the actual issue but there are other instantiation problems + proc bar[T](x = foo[T]()) = discard + bar[int](Foo[int]()) + bar[int]() + # alternative version, also causes instantiation issue + proc baz[T](x: typeof(foo[T]())) = discard + baz[int](Foo[int]()) + +block: # issue #21346 + type K[T] = object + template s[T](x: int) = doAssert T is K[K[int]] + proc b1(n: bool | bool) = s[K[K[int]]](3) + proc b2(n: bool) = s[K[K[int]]](3) + template b3(n: bool) = s[K[K[int]]](3) + b1(false) # Error: cannot instantiate K; got: <T> but expected: <T> + b2(false) # Builds, on its own + b3(false) diff --git a/tests/proc/tgenericdefaultparam.nim b/tests/proc/tgenericdefaultparam.nim new file mode 100644 index 000000000..7bce591ce --- /dev/null +++ b/tests/proc/tgenericdefaultparam.nim @@ -0,0 +1,98 @@ +block: # issue #16700 + type MyObject[T] = object + x: T + proc initMyObject[T](value = T.default): MyObject[T] = + MyObject[T](x: value) + var obj = initMyObject[int]() + +block: # issue #20916 + type + SomeX = object + v: int + var val = 0 + proc f(_: type int, x: SomeX, v = x.v) = + doAssert v == 42 + val = v + proc a(): proc() = + let v = SomeX(v: 42) + var tmp = proc() = + int.f(v) + tmp + a()() + doAssert val == 42 + +import std/typetraits + +block: # issue #24099, original example + type + ColorRGBU = distinct array[3, uint8] ## RGB range 0..255 + ColorRGBAU = distinct array[4, uint8] ## RGB range 0..255 + ColorRGBUAny = ColorRGBU | ColorRGBAU + template componentType(t: typedesc[ColorRGBUAny]): typedesc = + ## Returns component type of a given color type. + arrayType distinctBase t + func `~=`[T: ColorRGBUAny](a, b: T, e = componentType(T)(1.0e-11)): bool = + ## Compares colors with given accuracy. + abs(a[0] - b[0]) < e and abs(a[1] - b[1]) < e and abs(a[2] - b[2]) < e + +block: # issue #24099, modified to actually work + type + ColorRGBU = distinct array[3, uint8] ## RGB range 0..255 + ColorRGBAU = distinct array[4, uint8] ## RGB range 0..255 + ColorRGBUAny = ColorRGBU | ColorRGBAU + template arrayType[I, T](t: typedesc[array[I, T]]): typedesc = + T + template `[]`(a: ColorRGBUAny, i: untyped): untyped = distinctBase(a)[i] + proc abs(a: uint8): uint8 = a + template componentType(t: typedesc[ColorRGBUAny]): typedesc = + ## Returns component type of a given color type. + arrayType distinctBase t + func `~=`[T: ColorRGBUAny](a, b: T, e = componentType(T)(1.0e-11)): bool = + ## Compares colors with given accuracy. + abs(a[0] - b[0]) <= e and abs(a[1] - b[1]) <= e and abs(a[2] - b[2]) <= e + doAssert ColorRGBU([1.uint8, 1, 1]) ~= ColorRGBU([1.uint8, 1, 1]) + +block: # issue #24099, modified to work but using float32 + type + ColorRGBU = distinct array[3, float32] ## RGB range 0..255 + ColorRGBAU = distinct array[4, float32] ## RGB range 0..255 + ColorRGBUAny = ColorRGBU | ColorRGBAU + template arrayType[I, T](t: typedesc[array[I, T]]): typedesc = + T + template `[]`(a: ColorRGBUAny, i: untyped): untyped = distinctBase(a)[i] + template componentType(t: typedesc[ColorRGBUAny]): typedesc = + ## Returns component type of a given color type. + arrayType distinctBase t + func `~=`[T: ColorRGBUAny](a, b: T, e = componentType(T)(1.0e-11)): bool = + ## Compares colors with given accuracy. + abs(a[0] - b[0]) < e and abs(a[1] - b[1]) < e and abs(a[2] - b[2]) < e + doAssert ColorRGBU([1.float32, 1, 1]) ~= ColorRGBU([1.float32, 1, 1]) + +block: # issue #13270 + type + A = object + B = object + proc f(a: A) = discard + proc g[T](value: T, cb: (proc(a: T)) = f) = + cb value + g A() + # This should fail because there is no f(a: B) overload available + doAssert not compiles(g B()) + +block: # issue #24121 + type + Foo = distinct int + Bar = distinct int + FooBar = Foo | Bar + + proc foo[T: distinct](x: T): string = "a" + proc foo(x: Foo): string = "b" + proc foo(x: Bar): string = "c" + + proc bar(x: FooBar, y = foo(x)): string = y + doAssert bar(Foo(123)) == "b" + doAssert bar(Bar(123)) == "c" + + proc baz[T: FooBar](x: T, y = foo(x)): string = y + doAssert baz(Foo(123)) == "b" + doAssert baz(Bar(123)) == "c" diff --git a/tests/proc/tinferlambdareturn.nim b/tests/proc/tinferlambdareturn.nim new file mode 100644 index 000000000..e9e592871 --- /dev/null +++ b/tests/proc/tinferlambdareturn.nim @@ -0,0 +1,36 @@ +import std/[sugar, sequtils] + +block: # issue #23200 + proc dosomething(iter: int -> (iterator: int)) = + discard + proc dosomething(iter: int -> seq[int]) = + discard + proc makeSeq(x: int): seq[int] = + @[x] + # Works fine with 1.6.12 and 1.6.14 + dosomething(makeSeq) + # Works with 1.6.12, fails with 1.6.14 + dosomething((y) => makeSeq(y)) + dosomething(proc (y: auto): auto = makeSeq(y)) + proc foo(y: auto): auto = makeSeq(y) + dosomething(foo) + +block: # issue #18866 + proc somefn[T](list: openarray[T], op: proc (v: T): float) = + discard op(list[0]) + + type TimeD = object + year: Natural + month: 1..12 + day: 1..31 + + doAssert not compiles(@[TimeD()].somefn(proc (v: auto): auto = + v + )) + @[TimeD()].somefn(proc (v: auto): auto = + v.year.float + ) + proc foo(v: auto): auto = v + doAssert not compiles(@[TimeD()].somefn(foo)) + proc bar(v: auto): auto = v.year.float + @[TimeD()].somefn(bar) diff --git a/tests/proc/tstaticsignature.nim b/tests/proc/tstaticsignature.nim new file mode 100644 index 000000000..25aa09c5d --- /dev/null +++ b/tests/proc/tstaticsignature.nim @@ -0,0 +1,268 @@ +block: # issue #4228 + template seqType(t: typedesc): typedesc = + when t is int: + seq[int] + else: + seq[string] + + proc mkSeq[T: int|string](v: T): seqType(T) = + result = newSeq[T](1) + result[0] = v + + doAssert mkSeq("a") == @["a"] + doAssert mkSeq(1) == @[1] + +block: # expanded version of t8545 + template bar(a: static[bool]): untyped = + when a: + int + else: + float + + proc main() = + proc foo1(a: static[bool]): auto = 1 + doAssert foo1(true) == 1 + + proc foo2(a: static[bool]): bar(a) = 1 + doAssert foo2(true) == 1 + doAssert foo2(true) is int + doAssert foo2(false) == 1.0 + doAssert foo2(false) is float + + proc foo3(a: static[bool]): bar(cast[bool](a)) = 1 + doAssert foo3(true) == 1 + doAssert foo3(true) is int + doAssert foo3(false) == 1.0 + doAssert foo3(false) is float + + proc foo4(a: static[bool]): bar(static(a)) = 1 + doAssert foo4(true) == 1 + doAssert foo4(true) is int + doAssert foo4(false) == 1.0 + doAssert foo4(false) is float + + static: main() + main() + +block: # issue #8406 + macro f(x: static[int]): untyped = discard + proc g[X: static[int]](v: f(X)) = discard + +import macros + +block: # issue #8551 + macro distinctBase2(T: typedesc): untyped = + let typeNode = getTypeImpl(T) + expectKind(typeNode, nnkBracketExpr) + if typeNode[0].typeKind != ntyTypeDesc: + error "expected typeDesc, got " & $typeNode[0] + var typeSym = typeNode[1] + + typeSym = getTypeImpl(typeSym) + + if typeSym.typeKind != ntyDistinct: + error "type is not distinct: " & $typeSym.typeKind + + typeSym = typeSym[0] + typeSym + + func distinctBase[T](a: T): distinctBase2(T) = distinctBase2(T)(a) + + type T = distinct int + doAssert distinctBase(T(0)) is int + +block: + type Foo[T] = object + x: T + + proc foo(x: Foo): Foo[x.T] = + doAssert typeof(result) is typeof(x) + + var a: Foo[int] + let b: Foo[int] = foo(a) + doAssert b.x is int + +block: + type Foo[T: static int] = object + x: array[T, int] + + proc double(x: int): int = x * 2 + + proc foo[T: static int](x: Foo[T]): Foo[T.double] = + doAssert typeof(result).T == double(typeof(x).T) + + var a: Foo[3] + let b: Foo[6] = foo(a) + doAssert $typeof(foo(a)) == "Foo[6]" + +block: + type Foo[T: static int] = object + x: array[T, int] + + proc foo(x: Foo): Foo[x.T] = + doAssert typeof(result).T == typeof(x).T + doAssert typeof(result) is typeof(x) + + var a: Foo[3] + let b: Foo[3] = foo(a) + doAssert $typeof(foo(a)) == "Foo[3]" + +block: # issue #7006 + type + Node[T] = object + val: T + next: ref Node[T] + HHSet[T, Key] = object + data: seq[Node[T]] + proc rawGet(hhs:HHSet; key: hhs.Key): ptr Node[hhs.T] = + return nil # body doesn't matter + var hhs: HHSet[string, cstring] + discard hhs.rawGet("hello".cstring) + +block: # issue #7008 + type Node[T] = object + val: T + # Compiles fine + proc concreteProc(s: Node[cstring]; key: s.T) = discard + # Also fine + proc implicitGenericProc1(s: Node; key: s.T) = discard + # still fine + proc explicitGenericProc1[T](s: Node[T]; key: T) = discard + # Internal Compiler Error! + proc explicitGenericProc2[T](s: Node[T]; key: s.T) = discard + let n = Node[int](val: 5) + implicitGenericProc1(n, 5) # works + explicitGenericProc1(n, 5) # works + explicitGenericProc2(n, 5) # doesn't + +block: # issue #20027 + block: + type Test[T] = object + proc run(self: Test): self.T = discard + discard run(Test[int]()) + block: + type Test[T] = object + proc run[T](self: Test[T]): self.T = discard + discard run(Test[int]()) + block: + type Test[T] = object + proc run(self: Test[auto]): self.T = discard + discard run(Test[int]()) + +block: # issue #11112 + proc foo[A, B]: type(A.default + B.default) = + discard + doAssert foo[int, int]() is int + +block: # tyStatic and tyFromExpr instantiation mid-match + proc bar(x: int): int = x * 3 + proc bar2(x: static int): int = x * 4 + type Foo[T: static int] = distinct array[T, int] + proc foo[T: static int](x: Foo[T], y: Foo[bar(T)]) = discard + proc foo2[T: static int](x: Foo[T], y: Foo[bar2(T)]) = discard + foo(Foo[1]([1]), Foo[3]([1, 2, 3])) + foo2(Foo[1]([1]), Foo[4]([1, 2, 3, 4])) + +block: # issue #4990 + type Foo[I: static[int], A: static[array[I, int]]] = object + curIndex: int + + proc next[I: static[int], A: static[array[I, int]]](f: Foo[I, A]): string = + discard + const arr = [1, 2, 3] + var f: Foo[arr.len, arr] + discard next(f) + +block: # issue #4990 comment + type + Foo[A: static[int], B: static[int], TokenType: enum, EofToken: static[TokenType]] = object + curIndex: int + MyEnum = enum + meA, meB + Bar = Foo[2, 3, MyEnum, meA] + proc next[A: static[int], B: static[int], TokenType: enum, + EofToken: static[TokenType]](f: Foo[A, B, TokenType, EofToken], + a: static[(array[A, int], array[B, int])]): TokenType = + TokenType(a[0][f.curIndex]) + const + a = [1, 2] + b = [3, 4, 5] + template next(bar: Bar): MyEnum = + next(Foo[2, 3, MyEnum, meA](bar), (a, b)) + let bar = Bar(curIndex: 0) + doAssert bar.next() == meB + +block: # issue #14053 + template returnType(value: static[int]): typedesc = + when value == 1: + int + else: + float + proc fun(value: static[int]): returnType(value) = discard + doAssert fun(1) is int + template returnType2(value: static[int]): typedesc = + int + proc fun2(value: static[int]): returnType2(value) = discard + doAssert fun2(1) is int + +block: # issue #7547 + macro foo(N: static[int]): untyped = + result = getType(int) + type + Foo[N: static[int]] = foo(N) + ContainsFoo[N: static[int]] = object + Ffoo: Foo[N] + proc initFoo(N: static[int]): Foo[N] = discard + proc initContainsFoo(size: static[int]): ContainsFoo[size] = discard + var a: Foo[10] # Works + doAssert a is int + let b = initFoo(10) # Works + doAssert b is int + let c = ContainsFoo[5]() # Works + doAssert c.Ffoo is int + let z = initContainsFoo(5) # Error: undeclared identifier: 'N' + doAssert z.Ffoo is int + +block: # issue #22607, needs nkWhenStmt to be handled like nkRecWhen + proc test[x: static bool]( + t: ( + when x: + int + else: + float + ) + ) = discard + test[true](1.int) + test[false](1.0) + doAssert not compiles(test[]) + +block: # `when` in static signature + template ctAnd(a, b): bool = + when a: + when b: true + else: false + else: false + template test(): untyped = + when ctAnd(declared(SharedTable), typeof(result) is SharedTable): + result = SharedTable() + else: + result = 123 + proc foo[T](): T = test() + proc bar[T](x = foo[T]()): T = x + doAssert bar[int]() == 123 + +block: # issue #22276 + type Foo = enum A, B + macro test(y: static[Foo]): untyped = + if y == A: + result = parseExpr("proc (x: int)") + else: + result = parseExpr("proc (x: float)") + proc foo(y: static[Foo], x: test(y)) = # We want to make the type of `x` depend on what `y` is + x(9) + foo(A, proc (x: int) = doAssert x == 9) + var a: int + foo(A, proc (x: int) = + a = x * 2) + doAssert a == 18 + foo(B, proc (x: float) = doAssert x == 9) diff --git a/tests/proc/twrongdefaultvalue.nim b/tests/proc/twrongdefaultvalue.nim new file mode 100644 index 000000000..2c36c2247 --- /dev/null +++ b/tests/proc/twrongdefaultvalue.nim @@ -0,0 +1,25 @@ +discard """ + cmd: "nim check $file" + action: reject + nimout: ''' +twrongdefaultvalue.nim(20, 12) template/generic instantiation of `doit` from here +twrongdefaultvalue.nim(17, 37) Error: type mismatch: got <proc (p: int): Item[initItem.T]> but expected 'Item[system.string]' +twrongdefaultvalue.nim(25, 3) template/generic instantiation of `foo` from here +twrongdefaultvalue.nim(23, 33) Error: type mismatch: got <string> but expected 'int' +''' +""" + +block: # issue #21258 + type Item[T] = object + pos: int + proc initItem[T](p:int=10000) : Item[T] = + result = Item[T](p) + proc doit[T](x:Item[T], s:Item[T]=initItem) : string = + return $x.pos + let x = Item[string](pos:100) + echo doit(x) + +block: # issue #21258, reduced case + proc foo[T](x: seq[T], y: T = "foo") = + discard + foo @[1, 2, 3] diff --git a/tests/range/tcompiletime_range_checks.nim b/tests/range/tcompiletime_range_checks.nim index 29e2c48a8..2d3f292ec 100644 --- a/tests/range/tcompiletime_range_checks.nim +++ b/tests/range/tcompiletime_range_checks.nim @@ -1,8 +1,8 @@ discard """ cmd: "nim check --hint:Processing:off --hint:Conf:off $file" errormsg: "18446744073709551615 can't be converted to int8" - nimout: '''tcompiletime_range_checks.nim(36, 21) Error: 2147483648 can't be converted to int32 -tcompiletime_range_checks.nim(37, 23) Error: -1 can't be converted to uint64 + nimout: ''' +tcompiletime_range_checks.nim(36, 21) Error: 2147483648 can't be converted to int32 tcompiletime_range_checks.nim(38, 34) Error: 255 can't be converted to FullNegativeRange tcompiletime_range_checks.nim(39, 34) Error: 18446744073709551615 can't be converted to HalfNegativeRange tcompiletime_range_checks.nim(40, 34) Error: 300 can't be converted to FullPositiveRange diff --git a/tests/range/texplicitvarconv.nim b/tests/range/texplicitvarconv.nim new file mode 100644 index 000000000..8da8a8878 --- /dev/null +++ b/tests/range/texplicitvarconv.nim @@ -0,0 +1,13 @@ +# related to issue #24032 + +proc `++`(n: var int) = + n += 1 + +type + r = range[ 0..15 ] + +var a: r = 14 + +++int(a) # this should be mutable + +doAssert a == 15 diff --git a/tests/range/toutofrangevarconv.nim b/tests/range/toutofrangevarconv.nim new file mode 100644 index 000000000..1ee4d340e --- /dev/null +++ b/tests/range/toutofrangevarconv.nim @@ -0,0 +1,14 @@ +discard """ + outputsub: "value out of range: 5 notin 0 .. 3 [RangeDefect]" + exitcode: "1" +""" + +# make sure out of bounds range conversion is detected for `var` conversions + +type R = range[0..3] + +proc foo(x: var R) = + doAssert x in 0..3 + +var x = 5 +foo(R(x)) diff --git a/tests/refc/tsinkbug.nim b/tests/refc/tsinkbug.nim new file mode 100644 index 000000000..de2ec98a5 --- /dev/null +++ b/tests/refc/tsinkbug.nim @@ -0,0 +1,26 @@ +discard """ + matrix: "--gc:refc; --gc:arc" + output: ''' +Value is: 42 +Value is: 42''' +""" + +type AnObject* = object of RootObj + value*: int + +proc mutate(a: sink AnObject) = + a.value = 1 + +var obj = AnObject(value: 42) +echo "Value is: ", obj.value +mutate(obj) +echo "Value is: ", obj.value + +proc p(x: sink string) = + var y = move(x) + doAssert x.len == 0 + doAssert y.len == 4 + +p("1234") +var s = "oooo" +p(s) diff --git a/tests/sets/trangeincompatible.nim b/tests/sets/trangeincompatible.nim new file mode 100644 index 000000000..554a50235 --- /dev/null +++ b/tests/sets/trangeincompatible.nim @@ -0,0 +1,32 @@ +block: # issue #20142 + let + s1: set['a' .. 'g'] = {'a', 'e'} + s2: set['a' .. 'g'] = {'b', 'c', 'd', 'f'} # this works fine + s3 = {'b', 'c', 'd', 'f'} + + doAssert s1 != s2 + doAssert s1 == {range['a'..'g'] 'a', 'e'} + doAssert s2 == {range['a'..'g'] 'b', 'c', 'd', 'f'} + # literal conversion: + doAssert s1 == {'a', 'e'} + doAssert s2 == {'b', 'c', 'd', 'f'} + doAssert s3 == {'b', 'c', 'd', 'f'} + doAssert not compiles(s1 == s3) + doAssert not compiles(s2 == s3) + # can't convert literal 'z', overload match fails + doAssert not compiles(s1 == {'a', 'z'}) + +block: # issue #18396 + var s1: set[char] = {'a', 'b'} + var s2: set['a'..'z'] = {'a', 'b'} + doAssert s1 == {'a', 'b'} + doAssert s2 == {range['a'..'z'] 'a', 'b'} + doAssert s2 == {'a', 'b'} + doAssert not compiles(s1 == s2) + +block: # issue #16270 + var s1: set[char] = {'a', 'b'} + var s2: set['a'..'z'] = {'a', 'c'} + doAssert not (compiles do: s2 = s2 + s1) + s2 = s2 + {'a', 'b'} + doAssert s2 == {'a', 'b', 'c'} diff --git a/tests/sets/tsets.nim b/tests/sets/tsets.nim index 3c20a3907..6125a3715 100644 --- a/tests/sets/tsets.nim +++ b/tests/sets/tsets.nim @@ -1,3 +1,7 @@ +discard """ + targets: "c cpp" +""" + # Test builtin sets # xxx these tests are not very good, this should be revisited. @@ -93,3 +97,37 @@ block: doAssert k99 notin s1 doAssert k99 notin s2 + +block: # bug #23422 + block: + var a: set[uint8] = {1'u8} + + proc printLen(x: set[uint8]): int = + doAssert x.len == card(x) + result = card(x) + + proc printLenVar(x: var set[uint8]): int = + doAssert x.len == card(x) + result = card(x) + + doAssert a.len == 1 + doAssert printLen(a) == 1 + doAssert printLenVar(a) == card(a) + + block: + type Fruit = enum + Apple, Banana, Melon + + var a: set[Fruit] = {Apple} + + proc printLen(x: set[Fruit]): int = + doAssert x.len == card(x) + result = card(x) + + proc printLenVar(x: var set[Fruit]): int = + doAssert x.len == card(x) + result = card(x) + + doAssert a.len == 1 + doAssert printLen(a) == 1 + doAssert printLenVar(a) == card(a) diff --git a/tests/sets/twrongenumrange.nim b/tests/sets/twrongenumrange.nim new file mode 100644 index 000000000..a8d64ac44 --- /dev/null +++ b/tests/sets/twrongenumrange.nim @@ -0,0 +1,50 @@ +discard """ + cmd: "nim check --hints:off $file" +""" + +# issue #17848 + +block: + # generate with: + # var a = "" + # for i in 0..<80: a.add "k" & $i & ", " + # echo a + type + TMsgKind = enum + k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k40, k41, k42, k43, k44, k45, k46, k47, k48, k49, k50, k51, k52, k53, k54, k55, k56, k57, k58, k59, k60, k61, k62, k63, k64, k65, k66, k67, k68, k69, k70, k71, k72, k73, k74, k75, k76, k77, k78, k79 + type + TNoteKind = range[k10..k79] + Conf = ref object + notes: set[TNoteKind] + proc bad(conf: Conf, noteSet: set[TMsgKind]) = + conf.notes = noteSet #[tt.Error + ^ type mismatch: got <set[TMsgKind]> but expected 'set[TNoteKind]']# + var conf = Conf() + bad(conf, {k10..k60}) + +block: + type + TMsgKind = enum k0, k1, k2, k3 + TNoteKind = range[k1..k2] + TNoteKinds = set[TNoteKind] + type Conf = ref object + notes: TNoteKinds + proc fn(conf: Conf, b: set[TMsgKind]) = + conf.notes = b #[tt.Error + ^ type mismatch: got <set[TMsgKind]> but expected 'TNoteKinds = set[TNoteKind]']# + var conf = Conf() + conf.fn({k0..k3}) # BUG: this should give error + echo conf.notes # {k1, k2} + +block: + #[ + compiler/bitsets.nim(43, 9) `elem >= 0` [AssertionDefect] + ]# + type + TMsgKind = enum k0, k1, k2, k3 + TNoteKind = range[k1..k2] + var notes: set[TNoteKind] + notes = {k0} #[tt.Error + ^ type mismatch: got <set[TMsgKind]> but expected 'set[TNoteKind]']# + notes = {k0..k3} #[tt.Error + ^ type mismatch: got <set[TMsgKind]> but expected 'set[TNoteKind]']# diff --git a/tests/stdlib/concurrency/tatomics.nim b/tests/stdlib/concurrency/tatomics.nim index 3fb5197da..08f2e7d3e 100644 --- a/tests/stdlib/concurrency/tatomics.nim +++ b/tests/stdlib/concurrency/tatomics.nim @@ -1,5 +1,7 @@ discard """ - matrix: "--mm:refc; --mm:orc" + # test C with -d:nimUseCppAtomics as well to check nothing breaks + matrix: "--mm:refc; --mm:orc; --mm:refc -d:nimUseCppAtomics; --mm:orc -d:nimUseCppAtomics" + targets: "c cpp" """ # test atomic operations diff --git a/tests/stdlib/concurrency/tatomics_size.nim b/tests/stdlib/concurrency/tatomics_size.nim index cfe568623..f64adb308 100644 --- a/tests/stdlib/concurrency/tatomics_size.nim +++ b/tests/stdlib/concurrency/tatomics_size.nim @@ -1,5 +1,6 @@ discard """ - matrix: "--mm:refc; --mm:orc" + # test C with -d:nimUseCppAtomics as well to check nothing breaks + matrix: "--mm:refc; --mm:orc; --mm:refc -d:nimUseCppAtomics; --mm:orc -d:nimUseCppAtomics" targets: "c cpp" """ import std/atomics @@ -17,4 +18,4 @@ block testSize: # issue 12726 f: AtomicFlag static: doAssert sizeof(Node) == sizeof(pointer) - doAssert sizeof(MyChannel) == sizeof(pointer) * 2 \ No newline at end of file + doAssert sizeof(MyChannel) == sizeof(pointer) * 2 diff --git a/tests/stdlib/tbase64.nim b/tests/stdlib/tbase64.nim index 98388bb6c..c3bfb818e 100644 --- a/tests/stdlib/tbase64.nim +++ b/tests/stdlib/tbase64.nim @@ -18,6 +18,8 @@ template main() = doAssert encode("") == "" doAssert decode("") == "" + doAssert decode(" ") == "" + const testInputExpandsTo76 = "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++" const testInputExpands = "++++++++++++++++++++++++++++++" const longText = """Man is distinguished, not only by his reason, but by this diff --git a/tests/stdlib/tclosures.nim b/tests/stdlib/tclosures.nim new file mode 100644 index 000000000..84b033fa8 --- /dev/null +++ b/tests/stdlib/tclosures.nim @@ -0,0 +1,47 @@ +discard """ + targets: "c js" +""" + +import std/assertions + +block: # bug #4299 + proc scopeProc() = + proc normalProc() = + discard + + proc genericProc[T]() = + normalProc() + + genericProc[string]() + + scopeProc() + +block: # bug #12492 + proc foo() = + var i = 0 + proc bar() = + inc i + + bar() + doAssert i == 1 + + foo() + static: + foo() + +block: # bug #10849 + type + Generic[T] = ref object + getState: proc(): T + + proc newGeneric[T](): Generic[T] = + var state: T + + proc getState[T](): T = + state + + Generic[T](getState: getState) + + let g = newGeneric[int]() + let state = g.getState() + doAssert state == 0 diff --git a/tests/stdlib/tcomplex.nim b/tests/stdlib/tcomplex.nim index 812bcdc77..ca83314b9 100644 --- a/tests/stdlib/tcomplex.nim +++ b/tests/stdlib/tcomplex.nim @@ -84,6 +84,9 @@ let t = polar(a) doAssert(rect(t.r, t.phi) =~ a) doAssert(rect(1.0, 2.0) =~ complex(-0.4161468365471424, 0.9092974268256817)) +doAssert(almostEqual(a, a + complex(1e-16, 1e-16))) +doAssert(almostEqual(a, a + complex(2e-15, 2e-15), unitsInLastPlace = 5)) + let i64: Complex32 = complex(0.0f, 1.0f) diff --git a/tests/stdlib/tdeques.nim b/tests/stdlib/tdeques.nim index 49072b150..39ff996d1 100644 --- a/tests/stdlib/tdeques.nim +++ b/tests/stdlib/tdeques.nim @@ -189,6 +189,55 @@ proc main() = a.shrink(fromFirst = 0, fromLast = 1) doAssert $a == "[10, 20, 30]" + block: + var a, b: Deque[int] + for i in 1 .. 256: + a.addLast(i) + for i in 1 .. 255: + a.popLast + b.addLast(1) + doAssert a == b + + block: + # Issue 23275 + # Test `==`. + block: + var a, b = initDeque[int]() + doAssert a == b + doAssert a.hash == b.hash + a.addFirst(1) + doAssert a != b + doAssert a.hash != b.hash + b.addLast(1) + doAssert a == b + doAssert a.hash == b.hash + a.popFirst + b.popLast + doAssert a == b + doAssert a.hash == b.hash + a.addLast 2 + doAssert a != b + doAssert a.hash != b.hash + b.addFirst 2 + doAssert a == b + doAssert a.hash == b.hash + + block: + var a, b = initDeque[int]() + for i in countDown(100, 1): + a.addFirst(i) + for i in 1..100: + b.addLast(i) + doAssert a == b + for i in 1..99: + a.popLast + let a1 = [1].toDeque + doAssert a == a1 + doAssert a.hash == a1.hash + var c = initDeque[int]() + c.addLast(1) + doAssert a == c + doAssert a.hash == c.hash static: main() main() diff --git a/tests/stdlib/tencodings.nim b/tests/stdlib/tencodings.nim index e5e89ef37..2f4daaba3 100644 --- a/tests/stdlib/tencodings.nim +++ b/tests/stdlib/tencodings.nim @@ -101,3 +101,7 @@ block: doAssert orig == "\195\182\195\164\195\188\195\159" doAssert ibm850 == "\148\132\129\225" doAssert convert(ibm850, current, "ibm850") == orig + +block: # fixes about #23481 + doAssertRaises EncodingError: + discard open(destEncoding="this is a invalid enc") diff --git a/tests/stdlib/tenumutils.nim b/tests/stdlib/tenumutils.nim index 67b98efe1..2662a660d 100644 --- a/tests/stdlib/tenumutils.nim +++ b/tests/stdlib/tenumutils.nim @@ -35,5 +35,15 @@ template main = doAssert $b == "kb0" static: doAssert B.high.symbolName == "b2" + block: + type + Color = enum + Red = "red", Yellow = "yellow", Blue = "blue" + + var s = Red + doAssert symbolName(s) == "Red" + var x: range[Red..Blue] = Yellow + doAssert symbolName(x) == "Yellow" + static: main() main() diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim index b6fbbbdb7..4555fbcb3 100644 --- a/tests/stdlib/thashes.nim +++ b/tests/stdlib/thashes.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:on; --backend:js --jsbigint64:off" + matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:on; --backend:c -d:nimStringHash2; --backend:cpp -d:nimStringHash2; --backend:js -d:nimStringHash2" """ import std/hashes @@ -31,7 +31,8 @@ block hashes: doAssert hashWangYi1(123) == wy123 const wyNeg123 = hashWangYi1(-123) doAssert wyNeg123 != 0 - doAssert hashWangYi1(-123) == wyNeg123 + when not defined(js): # TODO: fixme it doesn't work for JS + doAssert hashWangYi1(-123) == wyNeg123 # "hashIdentity value incorrect at 456" @@ -45,20 +46,31 @@ block hashes: else: doAssert hashWangYi1(456) == -6421749900419628582 +template jsNoInt64: untyped = + when defined js: + when compiles(compileOption("jsbigint64")): + when not compileOption("jsbigint64"): true + else: false + else: false + else: false +const sHash2 = (when defined(nimStringHash2) or jsNoInt64(): true else: false) + block empty: + const emptyStrHash = # Hash=int=4B on js even w/--jsbigint64:on => cast[Hash] + when sHash2: 0 else: cast[Hash](-7286425919675154353i64) var a = "" b = newSeq[char]() c = newSeq[int]() d = cstring"" e = "abcd" - doAssert hash(a) == 0 - doAssert hash(b) == 0 + doAssert hash(a) == emptyStrHash + doAssert hash(b) == emptyStrHash doAssert hash(c) == 0 - doAssert hash(d) == 0 + doAssert hash(d) == emptyStrHash doAssert hashIgnoreCase(a) == 0 doAssert hashIgnoreStyle(a) == 0 - doAssert hash(e, 3, 2) == 0 + doAssert hash(e, 3, 2) == emptyStrHash block sameButDifferent: doAssert hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13) @@ -92,7 +104,10 @@ block largeSize: # longer than 4 characters proc main() = doAssert hash(0.0) == hash(0) # bug #16061 - doAssert hash(cstring"abracadabra") == 97309975 + when not sHash2: # Hash=int=4B on js even w/--jsbigint64:on => cast[Hash] + doAssert hash(cstring"abracadabra") == cast[Hash](-1119910118870047694i64) + else: + doAssert hash(cstring"abracadabra") == 97309975 doAssert hash(cstring"abracadabra") == hash("abracadabra") when sizeof(int) == 8 or defined(js): diff --git a/tests/stdlib/thttpclient.nim b/tests/stdlib/thttpclient.nim index 00e728fa2..0bd479670 100644 --- a/tests/stdlib/thttpclient.nim +++ b/tests/stdlib/thttpclient.nim @@ -53,9 +53,9 @@ proc asyncTest() {.async.} = doAssert("<title>Example Domain</title>" in body) resp = await client.request("http://example.com/404") - doAssert(resp.code.is4xx) - doAssert(resp.code == Http404) - doAssert(resp.status == $Http404) + doAssert(resp.code.is4xx or resp.code.is5xx) + doAssert(resp.code == Http404 or resp.code == Http500) + doAssert(resp.status == $Http404 or resp.status == $Http500) when false: # occasionally does not give success code resp = await client.request("https://google.com/") @@ -115,9 +115,9 @@ proc syncTest() = doAssert("<title>Example Domain</title>" in resp.body) resp = client.request("http://example.com/404") - doAssert(resp.code.is4xx) - doAssert(resp.code == Http404) - doAssert(resp.status == $Http404) + doAssert(resp.code.is4xx or resp.code.is5xx) + doAssert(resp.code == Http404 or resp.code == Http500) + doAssert(resp.status == $Http404 or resp.status == $Http500) when false: # occasionally does not give success code resp = client.request("https://google.com/") diff --git a/tests/stdlib/thttpclient_ssl.nim b/tests/stdlib/thttpclient_ssl.nim index feacd3e57..6b963f029 100644 --- a/tests/stdlib/thttpclient_ssl.nim +++ b/tests/stdlib/thttpclient_ssl.nim @@ -13,7 +13,10 @@ discard """ ## Test with: ## ./bin/nim c -d:ssl -p:. --threads:on -r tests/stdlib/thttpclient_ssl.nim -when not defined(windows): + +from stdtest/testutils import disableSSLTesting + +when not defined(windows) and not disableSSLTesting(): # Disabled on Windows due to old OpenSSL version import std/[formatfloat, syncio] import diff --git a/tests/stdlib/tjson.nim b/tests/stdlib/tjson.nim index 691bedeaa..e425501f6 100644 --- a/tests/stdlib/tjson.nim +++ b/tests/stdlib/tjson.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--mm:refc; --backend:cpp --mm:refc; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on" + matrix: "; --backend:cpp; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on" """ @@ -51,7 +51,7 @@ for i in 0 .. 10000: except: discard # memory diff should less than 4M -doAssert(abs(getOccupiedMem() - startMemory) < 4 * 1024 * 1024) # todo fixme doesn;t work for ORC +doAssert(abs(getOccupiedMem() - startMemory) < 4 * 1024 * 1024) # test `$` diff --git a/tests/stdlib/tmarshalsegfault.nim b/tests/stdlib/tmarshalsegfault.nim new file mode 100644 index 000000000..71f2766c8 --- /dev/null +++ b/tests/stdlib/tmarshalsegfault.nim @@ -0,0 +1,54 @@ +# issue #12405 + +import std/[marshal, streams, times, tables, os, assertions] + +type AiredEpisodeState * = ref object + airedAt * : DateTime + tvShowId * : string + seasonNumber * : int + number * : int + title * : string + +type ShowsWatchlistState * = ref object + aired * : seq[AiredEpisodeState] + +type UiState * = ref object + shows: ShowsWatchlistState + +# Helpers to marshal and unmarshal +proc load * ( state : var UiState, file : string ) = + var strm = newFileStream( file, fmRead ) + + strm.load( state ) + + strm.close() + +proc store * ( state : UiState, file : string ) = + var strm = newFileStream( file, fmWrite ) + + strm.store( state ) + + strm.close() + +# 1. We fill the state initially +var state : UiState = UiState( shows: ShowsWatchlistState( aired: @[] ) ) + +# VERY IMPORTANT: For some reason, small numbers (like 2 or 3) don't trigger the bug. Anything above 7 or 8 on my machine triggers though +for i in 0..30: + var episode = AiredEpisodeState( airedAt: now(), tvShowId: "1", seasonNumber: 1, number: 1, title: "string" ) + + state.shows.aired.add( episode ) + +# 2. Store it in a file with the marshal module, and then load it back up +store( state, "tmarshalsegfault_data" ) +load( state, "tmarshalsegfault_data" ) +removeFile("tmarshalsegfault_data") + +# 3. VERY IMPORTANT: Without this line, for some reason, everything works fine +state.shows.aired[ 0 ] = AiredEpisodeState( airedAt: now(), tvShowId: "1", seasonNumber: 1, number: 1, title: "string" ) + +# 4. And formatting the airedAt date will now trigger the exception +for ep in state.shows.aired: + let x = $ep.seasonNumber & "x" & $ep.number & " (" & $ep.airedAt & ")" + let y = $ep.seasonNumber & "x" & $ep.number & " (" & $ep.airedAt & ")" + doAssert x == y diff --git a/tests/stdlib/tmimetypes.nim b/tests/stdlib/tmimetypes.nim index e332cea40..fd66ebd97 100644 --- a/tests/stdlib/tmimetypes.nim +++ b/tests/stdlib/tmimetypes.nim @@ -11,10 +11,18 @@ template main() = var m = newMimetypes() doAssert m.getMimetype("mp4") == "video/mp4" doAssert m.getExt("application/json") == "json" + doAssert m.getMimetype("json") == "application/json" m.register("foo", "baa") doAssert m.getMimetype("foo") == "baa" + doAssert m.getMimetype("txt") == "text/plain" + doAssert m.getExt("text/plain") == "txt" # see also `runnableExamples`. # xxx we should have a way to avoid duplicating code between runnableExamples and tests + doAssert m.getMimetype("nim") == "text/nim" + doAssert m.getMimetype("nimble") == "text/nimble" + doAssert m.getMimetype("nimf") == "text/nim" + doAssert m.getMimetype("nims") == "text/nim" + static: main() main() diff --git a/tests/stdlib/tmisc_issues.nim b/tests/stdlib/tmisc_issues.nim index 33eb9655d..86dcf4162 100644 --- a/tests/stdlib/tmisc_issues.nim +++ b/tests/stdlib/tmisc_issues.nim @@ -18,3 +18,22 @@ type var x: Object = Object(data: Test(Data(id: 12))) doAssert Data(x.data).id == 12 + +block: # bug #16771 + type A = object + n: int + + proc foo(a, b: var A) = + swap a, b + + var a, b: A + a.n = 42 + b.n = 1 + doAssert a.n == 42 + doAssert b.n == 1 + a.swap b + doAssert a.n == 1 + doAssert b.n == 42 + a.foo b + doAssert a.n == 42 + doAssert b.n == 1 diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim index ad34e479a..611659fdb 100644 --- a/tests/stdlib/tos.nim +++ b/tests/stdlib/tos.nim @@ -27,9 +27,8 @@ Raises """ # test os path creation, iteration, and deletion -import os, strutils, pathnorm from stdtest/specialpaths import buildDir -import std/[syncio, assertions] +import std/[syncio, assertions, osproc, os, strutils, pathnorm] block fileOperations: let files = @["these.txt", "are.x", "testing.r", "files.q"] @@ -161,6 +160,18 @@ block fileOperations: # createDir should not fail if `dir` is empty createDir("") + + when defined(linux): # bug #24174 + createDir("a/b") + open("a/file.txt", fmWrite).close + + if not fileExists("a/fifoFile"): + doAssert execCmd("mkfifo -m 600 a/fifoFile") == 0 + + copyDir("a/", "../dest/a/", skipSpecial = true) + copyDirWithPermissions("a/", "../dest2/a/", skipSpecial = true) + removeDir("a") + # Symlink handling in `copyFile`, `copyFileWithPermissions`, `copyFileToDir`, # `copyDir`, `copyDirWithPermissions`, `moveFile`, and `moveDir`. block: diff --git a/tests/stdlib/tparseutils.nim b/tests/stdlib/tparseutils.nim index 020964446..b69900864 100644 --- a/tests/stdlib/tparseutils.nim +++ b/tests/stdlib/tparseutils.nim @@ -99,3 +99,14 @@ block: # With this included, static: test() crashes the compiler (from a checkParseSize " 12" , 0, 1 # Leading white # Value Edge cases checkParseSize "9223372036854775807", 19, int64.high + +block: # bug #23936 + func parsePyFloat( + a: openArray[char], # here must be openArray instead of string to reproduce this bug + res: var BiggestFloat): int = + result = parseFloat(a, res) + + static: + var f = 0.0 + doAssert "1.0".parsePyFloat(f) == 3 + doAssert f == 1.0 diff --git a/tests/stdlib/tpaths.nim b/tests/stdlib/tpaths.nim index 082c4937a..edb56209a 100644 --- a/tests/stdlib/tpaths.nim +++ b/tests/stdlib/tpaths.nim @@ -6,15 +6,12 @@ import std/paths import std/assertions import pathnorm from std/private/ospaths2 {.all.} import joinPathImpl -import std/sugar +import std/[sugar, sets] proc normalizePath*(path: Path; dirSep = DirSep): Path = result = Path(pathnorm.normalizePath(path.string, dirSep)) -func `==`(x, y: Path): bool = - x.string == y.string - func joinPath*(parts: varargs[Path]): Path = var estimatedLen = 0 var state = 0 @@ -231,4 +228,11 @@ block ospaths: when doslikeFileSystem: doAssert joinPath(Path"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools\\", Path"..\\..\\VC\\vcvarsall.bat") == r"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat".Path doAssert joinPath(Path"C:\\foo", Path"..\\a") == r"C:\a".Path - doAssert joinPath(Path"C:\\foo\\", Path"..\\a") == r"C:\a".Path \ No newline at end of file + doAssert joinPath(Path"C:\\foo\\", Path"..\\a") == r"C:\a".Path + + +block: # bug #23663 + var s: HashSet[Path] + s.incl("/a/b/c/..".Path) + doAssert "/a/b/".Path in s + doAssert "/a/b/c".Path notin s diff --git a/tests/stdlib/trandom.nim b/tests/stdlib/trandom.nim index 920d429d4..eb32f7757 100644 --- a/tests/stdlib/trandom.nim +++ b/tests/stdlib/trandom.nim @@ -1,6 +1,6 @@ discard """ joinable: false # to avoid messing with global rand state - matrix: "--mm:refc; --mm:orc; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on" + matrix: "--mm:refc; --mm:orc; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on" """ import std/[assertions, formatfloat] import std/[random, math, stats, sets, tables] @@ -47,6 +47,8 @@ block: type DiceRoll = range[0..6] when not defined(js): doAssert rand(DiceRoll).int == 3 + elif compileOption("jsbigint64"): + doAssert rand(DiceRoll).int == 1 else: doAssert rand(DiceRoll).int == 6 @@ -296,7 +298,13 @@ block: # bug #22360 else: inc fc - when defined(js): - doAssert (tc, fc) == (483, 517), $(tc, fc) + when defined(js) and not compileOption("jsbigint64"): + doAssert (tc, fc) == (515, 485), $(tc, fc) else: doAssert (tc, fc) == (510, 490), $(tc, fc) + +block: + when defined(js) and not compileOption("jsbigint64"): + doAssert rand(int32.high) == 335507522 + else: + doAssert rand(int32.high) == 607539621 diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim index e39eae9c1..ceab34bc9 100644 --- a/tests/stdlib/trst.nim +++ b/tests/stdlib/trst.nim @@ -16,6 +16,8 @@ discard """ [Suite] RST escaping [Suite] RST inline markup + +[Suite] Misc isssues ''' matrix: "--mm:refc; --mm:orc" """ @@ -526,8 +528,7 @@ suite "RST parsing": rnFieldBody rnLeaf 'Nim' rnLiteralBlock - rnLeaf ' - let a = 1 + rnLeaf 'let a = 1 ```' """ @@ -637,8 +638,7 @@ suite "RST parsing": rnLeaf 'test' rnFieldBody rnLiteralBlock - rnLeaf ' - let a = 1' + rnLeaf 'let a = 1' """) check(dedent""" @@ -661,8 +661,7 @@ suite "RST parsing": rnFieldBody rnLeaf '1' rnLiteralBlock - rnLeaf ' - let a = 1' + rnLeaf 'let a = 1' """) test "additional indentation < 4 spaces is handled fine": @@ -682,8 +681,7 @@ suite "RST parsing": rnLeaf 'nim' [nil] rnLiteralBlock - rnLeaf ' - let a = 1' + rnLeaf ' let a = 1' """) # | | # | \ indentation of exactly two spaces before 'let a = 1' @@ -717,8 +715,7 @@ suite "RST parsing": rnFieldBody rnLeaf 'Nim' rnLiteralBlock - rnLeaf ' - CodeBlock()' + rnLeaf 'CodeBlock()' rnLeaf ' ' rnLeaf 'Other' rnLeaf ' ' @@ -1985,3 +1982,13 @@ suite "RST inline markup": rnLeaf ')' """) check(warnings[] == @["input(1, 5) Warning: broken link 'f'"]) + +suite "Misc isssues": + test "Markdown CodeblockFields in one line (lacking enclosing ```)": + let message = """ + ```llvm-profdata merge first.profraw second.profraw third.profraw <more stuff maybe> -output data.profdata```""" + + try: + echo rstgen.rstToHtml(message, {roSupportMarkdown}, nil) + except EParseError: + discard diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim index 934403665..6253e7146 100644 --- a/tests/stdlib/trstgen.nim +++ b/tests/stdlib/trstgen.nim @@ -1246,7 +1246,7 @@ Test1 "input(8, 4) Warning: language 'anotherLang' not supported" ]) check(output == "<pre class = \"listing\">anything</pre>" & - "<p><pre class = \"listing\">\nsomeCode</pre> </p>") + "<p><pre class = \"listing\">someCode</pre> </p>") test "RST admonitions": # check that all admonitions are implemented diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim index 0668d12bd..60c63b450 100644 --- a/tests/stdlib/tstreams.nim +++ b/tests/stdlib/tstreams.nim @@ -92,6 +92,10 @@ static: # Ensure streams it doesnt break with nimscript on arc/orc #19716 let s = newStringStream("a") doAssert s.data == "a" +static: # issue #24054, readStr + var s = newStringStream("foo bar baz") + doAssert s.readStr(3) == "foo" + template main = var strm = newStringStream("abcde") var buffer = "12345" diff --git a/tests/stdlib/tstrformat.nim b/tests/stdlib/tstrformat.nim index 3c0d55c1d..ff406f898 100644 --- a/tests/stdlib/tstrformat.nim +++ b/tests/stdlib/tstrformat.nim @@ -562,7 +562,7 @@ proc main() = doAssert &"""{(if true: "'" & "'" & ')' else: "")}""" == "'')" doAssert &"{(if true: \"\'\" & \"'\" & ')' else: \"\")}" == "'')" doAssert fmt"""{(if true: "'" & ')' else: "")}""" == "')" - + block: # issue #20381 var ss: seq[string] template myTemplate(s: string) = @@ -573,5 +573,18 @@ proc main() = foo() doAssert ss == @["hello", "hello"] + block: + proc noraises() {.raises: [].} = + const + flt = 0.0 + str = "str" + + doAssert fmt"{flt} {str}" == "0.0 str" + + noraises() + + block: + doAssert not compiles(fmt"{formatting errors detected at compile time") + static: main() main() diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim index 9cc65f218..35f6bc669 100644 --- a/tests/stdlib/tstrutils.nim +++ b/tests/stdlib/tstrutils.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on" + matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on" """ import std/strutils @@ -527,9 +527,9 @@ template main() = block: # toHex doAssert(toHex(100i16, 32) == "00000000000000000000000000000064") - doAssert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C") whenJsNoBigInt64: discard do: + doAssert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C") doAssert(toHex(high(uint64)) == "FFFFFFFFFFFFFFFF") doAssert(toHex(high(uint64), 16) == "FFFFFFFFFFFFFFFF") doAssert(toHex(high(uint64), 32) == "0000000000000000FFFFFFFFFFFFFFFF") diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim index b9cbdd3e3..2ea96cfbb 100644 --- a/tests/stdlib/tsugar.nim +++ b/tests/stdlib/tsugar.nim @@ -295,7 +295,8 @@ template main() = for i in 0..5: xs.add(i) - xs.apply(d => ys.add(d)) + xs.apply(proc (d: auto) = ys.add(d)) + # ^ can be turned into d => ys.add(d) when we can infer void return type, #16906 doAssert ys == @[0, 1, 2, 3, 4, 5] test() diff --git a/tests/stdlib/tsystem.nim b/tests/stdlib/tsystem.nim index c1cadb49d..f634ce0c2 100644 --- a/tests/stdlib/tsystem.nim +++ b/tests/stdlib/tsystem.nim @@ -4,7 +4,7 @@ discard """ """ import stdtest/testutils -import std/assertions +import std/[assertions, formatfloat] # TODO: in future work move existing `system` tests here, where they belong @@ -83,24 +83,36 @@ block: X = object a: string b: set[char] + c: int + d: float + e: int64 - var y = X(b: {'a'}) - reset(y) + var x = X(b: {'a'}, e: 10) - doAssert y.b == {} + var y = move x -block: - type - X = object - a: string - b: int - - var y = X(b: 1314) + doAssert x.a == "" + doAssert x.b == {} + doAssert x.c == 0 + doAssert x.d == 0.0 + doAssert x.e == 0 reset(y) - doAssert y.b == 0 + doAssert y.a == "" + doAssert y.b == {} + doAssert y.c == 0 + doAssert y.d == 0.0 + doAssert y.e == 0 + +block: + var x = 2 + var y = move x + doAssert y == 2 + doAssert x == 0 + reset y + doAssert y == 0 block: type @@ -170,3 +182,19 @@ block: # bug #20516 when not defined(js): let a = create(Foo) + +block: # bug #6549 + when not defined(js): + block: + const v = 18446744073709551615'u64 + + doAssert $v == "18446744073709551615" + doAssert $float32(v) == "1.8446744e+19", $float32(v) + doAssert $float64(v) == "1.8446744073709552e+19", $float64(v) + + block: + let v = 18446744073709551615'u64 + + doAssert $v == "18446744073709551615" + doAssert $float32(v) == "1.8446744e+19" + doAssert $float64(v) == "1.8446744073709552e+19" diff --git a/tests/stdlib/ttasks.nim b/tests/stdlib/ttasks.nim index 347c3347a..ba65590d9 100644 --- a/tests/stdlib/ttasks.nim +++ b/tests/stdlib/ttasks.nim @@ -523,3 +523,39 @@ block: doAssert resB == "abcdef" testReturnValues() + + +block: # bug #23635 + block: + type + Store = object + run: proc (a: int) {.nimcall, gcsafe.} + + block: + var count = 0 + proc hello(a: int) = + inc count, a + + var store = Store() + store.run = hello + + let b = toTask store.run(13) + b.invoke() + doAssert count == 13 + + block: + type + Store = object + run: proc () {.nimcall, gcsafe.} + + block: + var count = 0 + proc hello() = + inc count, 1 + + var store = Store() + store.run = hello + + let b = toTask store.run() + b.invoke() + doAssert count == 1 diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index e01ab3a4f..0f04168dc 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--mm:refc; --mm:orc; --backend:js --jsbigint64:on; --backend:js --jsbigint64:off" + matrix: "--mm:refc; --mm:orc; --backend:js --jsbigint64:on; --backend:js --jsbigint64:off -d:nimStringHash2" """ import times, strutils, unittest @@ -71,7 +71,7 @@ template runTimezoneTests() = "2006-01-12T22:04:05Z", 11) # RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00" parseTest("2006-01-12T15:04:05.999999999Z-07:00", - "yyyy-MM-dd'T'HH:mm:ss'.999999999Z'zzz", "2006-01-12T22:04:05Z", 11) + "yyyy-MM-dd'T'HH:mm:ss.'999999999Z'zzz", "2006-01-12T22:04:05Z", 11) for tzFormat in ["z", "zz", "zzz"]: # formatting timezone as 'Z' for UTC parseTest("2001-01-12T22:04:05Z", "yyyy-MM-dd'T'HH:mm:ss" & tzFormat, @@ -770,3 +770,15 @@ block: # ttimes proc test(): DateTime {.gcsafe.} = result = "1970".parse("yyyy") doAssert test().year == 1970 + + block: # test FormatLiterals + # since #23861 + block: + let dt = dateTime(2024, mJul, 21, 17, 01, 02, 123_321_123, utc()) + check dt.format("ss.fff") == "02.123" + check dt.format("fff.ffffff") == "123.123321" + block: + let dt = parse("2024.07.21", "yyyy.MM.dd") + check dt.year == 2024 + check dt.month == mJul + check dt.monthday == 21 diff --git a/tests/stdlib/ttypeinfo.nim b/tests/stdlib/ttypeinfo.nim index 8d5061124..9bbc2e92c 100644 --- a/tests/stdlib/ttypeinfo.nim +++ b/tests/stdlib/ttypeinfo.nim @@ -74,3 +74,20 @@ block: doAssert getEnumOrdinal(y, "Hello") == 0 doAssert getEnumOrdinal(y, "hello") == 1 + +block: # bug #23556 + proc test = + var + t: seq[int] + aseq = toAny(t) + + invokeNewSeq(aseq, 0) + + # Got random value only when loop 8 times. + for i in 1 .. 8: + extendSeq(aseq) + + doAssert t == @[0, 0, 0, 0, 0, 0, 0, 0] + + for i in 1 .. 7: + test() diff --git a/tests/stdlib/tunicode.nim b/tests/stdlib/tunicode.nim index adc8d2078..b9e68b15b 100644 --- a/tests/stdlib/tunicode.nim +++ b/tests/stdlib/tunicode.nim @@ -57,6 +57,7 @@ doAssert isAlpha("r") doAssert isAlpha("α") doAssert isAlpha("ϙ") doAssert isAlpha("ஶ") +doAssert isAlpha("网") doAssert(not isAlpha("$")) doAssert(not isAlpha("")) @@ -66,6 +67,7 @@ doAssert isAlpha("𐌼𐌰𐌲𐌲𐌻𐌴𐍃𐍄𐌰𐌽") doAssert isAlpha("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει") doAssert isAlpha("Јамогујестистаклоитоминештети") doAssert isAlpha("Կրնամապակիուտեևինծիանհանգիստչըներ") +doAssert isAlpha("编程语言") doAssert(not isAlpha("$Foo✓")) doAssert(not isAlpha("⠙⠕⠑⠎⠝⠞")) diff --git a/tests/stdlib/tunixsocket.nim b/tests/stdlib/tunixsocket.nim new file mode 100644 index 000000000..636fd08c6 --- /dev/null +++ b/tests/stdlib/tunixsocket.nim @@ -0,0 +1,35 @@ +import std/[assertions, net, os, osproc] + +# XXX: Make this test run on Windows too when we add support for Unix sockets on Windows +when defined(posix) and not defined(nimNetLite): + const nim = getCurrentCompilerExe() + let + dir = currentSourcePath().parentDir() + serverPath = dir / "unixsockettest" + + let (_, err) = execCmdEx(nim & " c " & quoteShell(dir / "unixsockettest.nim")) + doAssert err == 0 + + let svproc = startProcess(serverPath, workingDir = dir) + doAssert svproc.running() + # Wait for the server to open the socket and listen from it + sleep(400) + + block unixSocketSendRecv: + let + unixSocketPath = dir / "usox" + socket = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_NONE) + + socket.connectUnix(unixSocketPath) + # for a blocking Unix socket this should never fail + socket.send("data sent through the socket\c\l", maxRetries = 0) + var resp: string + socket.readLine(resp) + doAssert resp == "Hello from server" + + socket.send("bye\c\l") + socket.readLine(resp) + doAssert resp == "bye" + socket.close() + + svproc.close() diff --git a/tests/stdlib/tvarints.nim b/tests/stdlib/tvarints.nim index 35f1cd849..f9624ee5b 100644 --- a/tests/stdlib/tvarints.nim +++ b/tests/stdlib/tvarints.nim @@ -33,7 +33,7 @@ block: doAssert cast[float64](got) == test block: - var hugeIntArray: array[50, byte] + var hugeIntArray: array[9, byte] var readedInt: uint64 template chk(a) = diff --git a/tests/stdlib/tvolatile.nim b/tests/stdlib/tvolatile.nim new file mode 100644 index 000000000..c097f9723 --- /dev/null +++ b/tests/stdlib/tvolatile.nim @@ -0,0 +1,15 @@ +import std/[volatile, assertions] + +var st: int +var foo: ptr int = addr st +volatileStore(foo, 12) +doAssert volatileLoad(foo) == 12 + +# bug #14623 +proc bar = + var st: int + var foo: ptr int = addr st + volatileStore(foo, 12) + doAssert volatileLoad(foo) == 12 + +bar() diff --git a/tests/stdlib/twrongstattype.nim b/tests/stdlib/twrongstattype.nim new file mode 100644 index 000000000..4a1fc30c6 --- /dev/null +++ b/tests/stdlib/twrongstattype.nim @@ -0,0 +1,14 @@ +# issue #24076 + +when defined(macosx) or defined(freebsd) or defined(openbsd) or defined(netbsd): + import std/posix + proc uid(x: uint32): Uid = Uid(x) + var y: uint32 + let myUid = geteuid() + discard myUid == uid(y) + proc dev(x: uint32): Dev = Dev(x) + let myDev = 1.Dev + discard myDev == dev(y) + proc nlink(x: uint32): Nlink = Nlink(x) + let myNlink = 1.Nlink + discard myNlink == nlink(y) diff --git a/tests/stdlib/unixsockettest.nim b/tests/stdlib/unixsockettest.nim new file mode 100644 index 000000000..8f95d0808 --- /dev/null +++ b/tests/stdlib/unixsockettest.nim @@ -0,0 +1,26 @@ +import std/[assertions, net, os] + +let unixSocketPath = getCurrentDir() / "usox" + +removeFile(unixSocketPath) + +let socket = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_NONE) +socket.bindUnix(unixSocketPath) +socket.listen() + +var + clientSocket: Socket + data: string + +socket.accept(clientSocket) +clientSocket.readLine(data) +doAssert data == "data sent through the socket" +clientSocket.send("Hello from server\c\l") + +clientSocket.readLine(data) +doAssert data == "bye" +clientSocket.send("bye\c\l") + +clientSocket.close() +socket.close() +removeFile(unixSocketPath) diff --git a/tests/system/tdollars.nim b/tests/system/tdollars.nim index 39337cca7..eabee81b3 100644 --- a/tests/system/tdollars.nim +++ b/tests/system/tdollars.nim @@ -1,5 +1,5 @@ discard """ - matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:off; --backend:js --jsbigint64:on" + matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on" """ #[ @@ -109,10 +109,10 @@ block: # if `uint8(a1)` changes meaning to `cast[uint8](a1)` in future, update this test; # until then, this is the correct semantics. let a3 = $a2 - doAssert a2 < 3 - doAssert a3 == "-1" + doAssert a2 == 255'u8 + doAssert a3 == "255" proc intToStr(a: uint8): cstring {.importjs: "(# + \"\")".} - doAssert $intToStr(a2) == "-1" + doAssert $intToStr(a2) == "255" else: block: let x = -1'i8 diff --git a/tests/system/tensuremove.nim b/tests/system/tensuremove.nim index 52d9a43a8..668d5aed1 100644 --- a/tests/system/tensuremove.nim +++ b/tests/system/tensuremove.nim @@ -1,5 +1,5 @@ discard """ - target: "c js" + targets: "c js" matrix: "--cursorinference:on; --cursorinference:off" """ diff --git a/tests/system/tsystem_misc.nim b/tests/system/tsystem_misc.nim index 7f5914725..1debb7c48 100644 --- a/tests/system/tsystem_misc.nim +++ b/tests/system/tsystem_misc.nim @@ -212,3 +212,16 @@ block: doAssert not compiles(echo p.rawProc.repr) doAssert not compiles(echo p.rawEnv.repr) doAssert not compiles(echo p.finished) + +proc bug23223 = # bug #23223 + var stuff = "hello" + stuff.insert "" + doAssert stuff == "hello" + +bug23223() + +block: # bug #23894 + let v = high(uint) div 2 + let s = v + 1 # 9223372036854775808 + let m = succ v + doAssert s == m diff --git a/tests/template/m19277_1.nim b/tests/template/m19277_1.nim new file mode 100644 index 000000000..840bd4767 --- /dev/null +++ b/tests/template/m19277_1.nim @@ -0,0 +1,2 @@ +template foo*(x: untyped) = + echo "got: ", x diff --git a/tests/template/m19277_2.nim b/tests/template/m19277_2.nim new file mode 100644 index 000000000..de72dad45 --- /dev/null +++ b/tests/template/m19277_2.nim @@ -0,0 +1,2 @@ +proc foo*(a: string) = + echo "got string: ", a diff --git a/tests/template/mqualifiedtype1.nim b/tests/template/mqualifiedtype1.nim new file mode 100644 index 000000000..46569107f --- /dev/null +++ b/tests/template/mqualifiedtype1.nim @@ -0,0 +1,2 @@ +type A* = object + x*: int diff --git a/tests/template/mqualifiedtype2.nim b/tests/template/mqualifiedtype2.nim new file mode 100644 index 000000000..6a61c14bd --- /dev/null +++ b/tests/template/mqualifiedtype2.nim @@ -0,0 +1,2 @@ +type A* = object + x*: array[1000, byte] diff --git a/tests/template/t13426.nim b/tests/template/t13426.nim new file mode 100644 index 000000000..f7f44749c --- /dev/null +++ b/tests/template/t13426.nim @@ -0,0 +1,87 @@ +discard """ + cmd: "nim check --hints:off $file" + errormsg: "" + nimout: ''' +t13426.nim(81, 6) template/generic instantiation of `fun` from here +t13426.nim(80, 24) Error: type mismatch: got <int> but expected 'string' +t13426.nim(81, 6) template/generic instantiation of `fun` from here +t13426.nim(80, 17) Error: type mismatch: got <uint, string> +but expected one of: +proc `and`(x, y: uint): uint + first type mismatch at position: 2 + required type for y: uint + but expression 'high(@[1])' is of type: string +proc `and`(x, y: uint64): uint64 + first type mismatch at position: 2 + required type for y: uint64 + but expression 'high(@[1])' is of type: string +10 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them + +expression: 1'u and high(@[1]) +t13426.nim(81, 6) template/generic instantiation of `fun` from here +t13426.nim(80, 17) Error: expression '' has no type (or is ambiguous) +t13426.nim(87, 6) template/generic instantiation of `fun` from here +t13426.nim(86, 22) Error: type mismatch: got <int> but expected 'string' +t13426.nim(87, 6) template/generic instantiation of `fun` from here +t13426.nim(86, 15) Error: type mismatch: got <int literal(1), string> +but expected one of: +proc `and`(x, y: int): int + first type mismatch at position: 2 + required type for y: int + but expression 'high(@[1])' is of type: string +proc `and`(x, y: int16): int16 + first type mismatch at position: 2 + required type for y: int16 + but expression 'high(@[1])' is of type: string +proc `and`(x, y: int32): int32 + first type mismatch at position: 2 + required type for y: int32 + but expression 'high(@[1])' is of type: string +proc `and`(x, y: int64): int64 + first type mismatch at position: 2 + required type for y: int64 + but expression 'high(@[1])' is of type: string +proc `and`(x, y: int8): int8 + first type mismatch at position: 2 + required type for y: int8 + but expression 'high(@[1])' is of type: string +proc `and`(x, y: uint): uint + first type mismatch at position: 2 + required type for y: uint + but expression 'high(@[1])' is of type: string +proc `and`(x, y: uint16): uint16 + first type mismatch at position: 2 + required type for y: uint16 + but expression 'high(@[1])' is of type: string +proc `and`(x, y: uint32): uint32 + first type mismatch at position: 2 + required type for y: uint32 + but expression 'high(@[1])' is of type: string +proc `and`(x, y: uint64): uint64 + first type mismatch at position: 2 + required type for y: uint64 + but expression 'high(@[1])' is of type: string +proc `and`(x, y: uint8): uint8 + first type mismatch at position: 2 + required type for y: uint8 + but expression 'high(@[1])' is of type: string +2 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them + +expression: 1 and high(@[1]) +t13426.nim(87, 6) template/generic instantiation of `fun` from here +t13426.nim(86, 15) Error: expression '' has no type (or is ambiguous) +''' +""" + +# bug # #13426 +block: + template bar(t): string = high(t) + proc fun[A](key: A) = + var h = 1'u and bar(@[1]) + fun(0) + +block: + template bar(t): string = high(t) + proc fun[A](key: A) = + var h = 1 and bar(@[1]) + fun(0) diff --git a/tests/template/t19277.nim b/tests/template/t19277.nim new file mode 100644 index 000000000..16435a09c --- /dev/null +++ b/tests/template/t19277.nim @@ -0,0 +1,19 @@ +discard """ + output: ''' +got: 0 +''' +""" + +# issue #19277 + +import m19277_1, m19277_2 + +template injector(val: untyped): untyped = + template subtemplate: untyped = val + subtemplate() + +template methodCall(val: untyped): untyped = val + +{.push raises: [Defect].} + +foo(injector(0).methodCall()) diff --git a/tests/template/t24112.nim b/tests/template/t24112.nim new file mode 100644 index 000000000..175fc7d5e --- /dev/null +++ b/tests/template/t24112.nim @@ -0,0 +1,19 @@ +discard """ + matrix: "--skipParentCfg --filenames:legacyRelProj --hints:off" + action: reject +""" + +# issue #24112, needs --experimental:openSym disabled + +block: # simplified + type + SomeObj = ref object # Doesn't error if you make SomeObj be non-ref + template foo = yield SomeObj() + when compiles(foo): discard + +import std/asyncdispatch +block: + proc someProc(): Future[void] {.async.} = discard + proc foo() = + await someProc() #[tt.Error + ^ Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead]# diff --git a/tests/template/tdefaultparam.nim b/tests/template/tdefaultparam.nim new file mode 100644 index 000000000..7ea0b2b25 --- /dev/null +++ b/tests/template/tdefaultparam.nim @@ -0,0 +1,56 @@ +block: + template foo(a: untyped, b: untyped = a(0)): untyped = + let x = a(0) + let y = b + (x, y) + proc bar(x: int): int = x + 1 + doAssert foo(bar, b = bar(0)) == (1, 1) + doAssert foo(bar) == (1, 1) + +block: # issue #23506 + var a: string + template foo(x: int; y = x) = + a = $($x, $y) + foo(1) + doAssert a == "(\"1\", \"1\")" + +block: # untyped params with default value + macro foo(x: typed): untyped = + result = x + template test(body: untyped, alt: untyped = (;), maxTries = 3): untyped {.foo.} = + body + alt + var s = "a" + test: + s.add "b" + do: + s.add "c" + doAssert s == "abc" + template test2(body: untyped, alt: untyped = s.add("e"), maxTries = 3): untyped = + body + alt + test2: + s.add "d" + doAssert s == "abcde" + template test3(body: untyped = willNotCompile) = + discard + test3() + +block: # typed params with `void` default value + macro foo(x: typed): untyped = + result = x + template test(body: untyped, alt: typed = (;), maxTries = 3): untyped {.foo.} = + body + alt + var s = "a" + test: + s.add "b" + do: + s.add "c" + doAssert s == "abc" + template test2(body: untyped, alt: typed = s.add("e"), maxTries = 3): untyped = + body + alt + test2: + s.add "d" + doAssert s == "abcde" diff --git a/tests/template/tgensymhijack.nim b/tests/template/tgensymhijack.nim new file mode 100644 index 000000000..72ff3d495 --- /dev/null +++ b/tests/template/tgensymhijack.nim @@ -0,0 +1,37 @@ +# issue #23326 + +type Result*[E] = object + e*: E + +proc error*[E](v: Result[E]): E = discard + +template valueOr*[E](self: Result[E], def: untyped): int = + when E isnot void: + when false: + # Comment line below to make it work + template error(): E {.used, gensym.} = s.e + discard + else: + template error(): E {.used, inject.} = + self.e + + def + else: + def + + +block: + let rErr = Result[string](e: "a") + let rErrV = rErr.valueOr: + ord(error[0]) + +block: + template foo(x: static bool): untyped = + when x: + let a = 123 + else: + template a: untyped {.gensym.} = 456 + a + + doAssert foo(false) == 456 + doAssert foo(true) == 123 diff --git a/tests/template/tinnerouterproc.nim b/tests/template/tinnerouterproc.nim index 1f15fb13e..56e0d02df 100644 --- a/tests/template/tinnerouterproc.nim +++ b/tests/template/tinnerouterproc.nim @@ -6,3 +6,15 @@ block: # #20002 discard 3.bar # evaluates to 10 but only check if it compiles for now block: foo() + +block: # issue #23813 + template r(body: untyped) = + proc x() {.gensym.} = + body + template g() = + r: + let y = 0 + r: + proc y() = discard + y() + g() diff --git a/tests/template/tnested.nim b/tests/template/tnested.nim new file mode 100644 index 000000000..81e416a76 --- /dev/null +++ b/tests/template/tnested.nim @@ -0,0 +1,38 @@ +block: # issue #22775 + proc h(c: int) = discard + template k(v: int) = + template p() = v.h() + p() + let a = @[0] + k(0 and not a[0]) + +block: # issue #22775 case 2 + proc h(c: int, q: int) = discard + template k(v: int) = + template p() = h(v, v) + p() + let a = [0] + k(0 and not a[0]) + +block: # issue #22775 minimal cases + proc h(c: int) = discard + template k(v: int) = + template p() = h(v) + p() + let a = [0] + k(not a[0]) + block: + k(-a[0]) + block: + proc f(x: int): int = x + k(f a[0]) + +block: # bracket assignment case of above tests + proc h(c: int) = discard + template k(v: int) = + template p() = h(v) + p() + var a = [0] + k(not (block: + a[0] = 1 + 1)) diff --git a/tests/template/topensym.nim b/tests/template/topensym.nim new file mode 100644 index 000000000..2f930407b --- /dev/null +++ b/tests/template/topensym.nim @@ -0,0 +1,209 @@ +{.experimental: "openSym".} + +block: # issue #24002 + type Result[T, E] = object + func value[T, E](self: Result[T, E]): T {.inline.} = + discard + func value[T: not void, E](self: var Result[T, E]): var T {.inline.} = + discard + template unrecognizedFieldWarning = + doAssert value == 123 + let x = value + doAssert value == x + proc readValue(value: var int) = + unrecognizedFieldWarning() + var foo: int = 123 + readValue(foo) + +block: # issue #22605 for templates, normal call syntax + const error = "bad" + + template valueOr(self: int, def: untyped): untyped = + case false + of true: "" + of false: + template error: untyped {.used, inject.} = "good" + def + + template g(T: type): string = + var res = "ok" + let x = valueOr 123: + res = $error + "dummy" + res + + doAssert g(int) == "good" + + template g2(T: type): string = + bind error # use the bad version on purpose + var res = "ok" + let x = valueOr 123: + res = $error + "dummy" + res + + doAssert g2(int) == "bad" + +block: # issue #22605 for templates, method call syntax + const error = "bad" + + template valueOr(self: int, def: untyped): untyped = + case false + of true: "" + of false: + template error: untyped {.used, inject.} = "good" + def + + template g(T: type): string = + var res = "ok" + let x = 123.valueOr: + res = $error + "dummy" + res + + doAssert g(int) == "good" + + template g2(T: type): string = + bind error # use the bad version on purpose + var res = "ok" + let x = 123.valueOr: + res = $error + "dummy" + res + + doAssert g2(int) == "bad" + +block: # issue #22605 for templates, original complex example + type Xxx = enum + error + value + + type + Result[T, E] = object + when T is void: + when E is void: + oResultPrivate*: bool + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + discard + else: + when E is void: + case oResultPrivate*: bool + of false: + discard + of true: + vResultPrivate*: T + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + vResultPrivate*: T + + template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped = + let s = (self) # TODO avoid copy + case s.oResultPrivate + of true: + s.vResultPrivate + of false: + when E isnot void: + template error: untyped {.used, inject.} = s.eResultPrivate + def + + proc f(): Result[int, cstring] = + Result[int, cstring](oResultPrivate: false, eResultPrivate: "f") + + template g(T: type): string = + var res = "ok" + let x = f().valueOr: + res = $error + 123 + res + + doAssert g(int) == "f" + + template g2(T: type): string = + bind error # use the bad version on purpose + var res = "ok" + let x = f().valueOr: + res = $error + 123 + res + + doAssert g2(int) == "error" + +block: # issue #23865 for templates + type Xxx = enum + error + value + + type + Result[T, E] = object + when T is void: + when E is void: + oResultPrivate: bool + else: + case oResultPrivate: bool + of false: + eResultPrivate: E + of true: + discard + else: + when E is void: + case oResultPrivate: bool + of false: + discard + of true: + vResultPrivate: T + else: + case oResultPrivate: bool + of false: + eResultPrivate: E + of true: + vResultPrivate: T + + func error[T, E](self: Result[T, E]): E = + ## Fetch error of result if set, or raise Defect + case self.oResultPrivate + of true: + when T isnot void: + raiseResultDefect("Trying to access error when value is set", self.vResultPrivate) + else: + raiseResultDefect("Trying to access error when value is set") + of false: + when E isnot void: + self.eResultPrivate + + template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped = + let s = (self) # TODO avoid copy + case s.oResultPrivate + of true: + s.vResultPrivate + of false: + when E isnot void: + template error: untyped {.used, inject.} = s.eResultPrivate + def + proc f(): Result[int, cstring] = + Result[int, cstring](oResultPrivate: false, eResultPrivate: "f") + template g(T: type): string = + var res = "ok" + let x = f().valueOr: + res = $error + 123 + res + doAssert g(int) == "f" + +import std/sequtils + +block: # issue #15314 + var it: string + var nums = @[1,2,3] + + template doubleNums() = + nums.applyIt(it * 2) + + doubleNums() + doAssert nums == @[2, 4, 6] diff --git a/tests/template/topensymoverride.nim b/tests/template/topensymoverride.nim new file mode 100644 index 000000000..3d4bb59f1 --- /dev/null +++ b/tests/template/topensymoverride.nim @@ -0,0 +1,39 @@ +discard """ + matrix: "--skipParentCfg --filenames:legacyRelProj" +""" + +const value = "captured" +template fooOld(x: int, body: untyped): untyped = + let value {.inject.} = "injected" + body +template foo(x: int, body: untyped): untyped = + let value {.inject.} = "injected" + {.push experimental: "genericsOpenSym".} + body + {.pop.} + +proc old[T](): string = + fooOld(123): + return value +doAssert old[int]() == "captured" + +template oldTempl(): string = + block: + var res: string + fooOld(123): + res = value + res +doAssert oldTempl() == "captured" + +proc bar[T](): string = + foo(123): + return value +doAssert bar[int]() == "injected" + +template barTempl(): string = + block: + var res: string + foo(123): + res = value + res +doAssert barTempl() == "injected" diff --git a/tests/template/topensymwarning.nim b/tests/template/topensymwarning.nim new file mode 100644 index 000000000..0bbe0a9fb --- /dev/null +++ b/tests/template/topensymwarning.nim @@ -0,0 +1,60 @@ +discard """ + matrix: "--skipParentCfg --filenames:legacyRelProj" +""" + +type Xxx = enum + error + value + +type + Result[T, E] = object + when T is void: + when E is void: + oResultPrivate*: bool + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + discard + else: + when E is void: + case oResultPrivate*: bool + of false: + discard + of true: + vResultPrivate*: T + else: + case oResultPrivate*: bool + of false: + eResultPrivate*: E + of true: + vResultPrivate*: T + +template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped = + let s = (self) # TODO avoid copy + case s.oResultPrivate + of true: + s.vResultPrivate + of false: + when E isnot void: + template error: untyped {.used, inject.} = s.eResultPrivate + def + +proc f(): Result[int, cstring] = + Result[int, cstring](oResultPrivate: false, eResultPrivate: "f") + +template g(T: type): string = + var res = "ok" + let x = f().valueOr: + {.push warningAsError[IgnoredSymbolInjection]: on.} + # test spurious error + discard true + let _ = f + {.pop.} + res = $error #[tt.Warning + ^ a new symbol 'error' has been injected during template or generic instantiation, however 'error' [enumField declared in topensymwarning.nim(6, 3)] captured at the proc declaration will be used instead; either enable --experimental:openSym to use the injected symbol, or `bind` this captured symbol explicitly [IgnoredSymbolInjection]]# + 123 + res + +discard g(int) diff --git a/tests/template/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim index b68d7e253..b559c2d9e 100644 --- a/tests/template/tparams_gensymed.nim +++ b/tests/template/tparams_gensymed.nim @@ -16,6 +16,7 @@ wth (total: 6) S1 5 +abc ''' """ # bug #1915 @@ -394,3 +395,11 @@ proc chunkedReadLoop2 = test2 test1(); test2() + +block: # bug #22846 + template foo2(x: proc (y: string)) = + let f = x + f("abc") + + foo2(proc (y: string) = echo y) + diff --git a/tests/template/tqualifiedtype.nim b/tests/template/tqualifiedtype.nim new file mode 100644 index 000000000..6497af6ee --- /dev/null +++ b/tests/template/tqualifiedtype.nim @@ -0,0 +1,25 @@ +# issue #19866 + +# Switch module import order to switch which of last two +# doAsserts fails +import mqualifiedtype1 +import mqualifiedtype2 + +# this isn't officially supported but needed to point out the issue: +template f(moduleName: untyped): int = sizeof(`moduleName`.A) +template g(someType: untyped): int = sizeof(someType) + +# These are legitimately true. +doAssert sizeof(mqualifiedtype1.A) != sizeof(mqualifiedtype2.A) +doAssert g(mqualifiedtype1.A) != g(mqualifiedtype2.A) + +# Which means that this should not be true, but is in Nim 1.6 +doAssert f(`mqualifiedtype1`) != f(`mqualifiedtype2`) +doAssert f(mqualifiedtype1) != f(mqualifiedtype2) + +# These should be true, but depending on import order, exactly one +# fails in Nim 1.2, 1.6 and devel. +doAssert f(`mqualifiedtype1`) == g(mqualifiedtype1.A) +doAssert f(`mqualifiedtype2`) == g(mqualifiedtype2.A) +doAssert f(mqualifiedtype1) == g(mqualifiedtype1.A) +doAssert f(mqualifiedtype2) == g(mqualifiedtype2.A) diff --git a/tests/threads/tmembug.nim b/tests/threads/tmembug.nim new file mode 100644 index 000000000..3618f0ecc --- /dev/null +++ b/tests/threads/tmembug.nim @@ -0,0 +1,51 @@ + +import std / [atomics, strutils, sequtils] + +type + BackendMessage* = object + field*: seq[int] + +var + chan1: Channel[BackendMessage] + chan2: Channel[BackendMessage] + +chan1.open() +chan2.open() + +proc routeMessage*(msg: BackendMessage) = + discard chan2.trySend(msg) + +var + recv: Thread[void] + stopToken: Atomic[bool] + +proc recvMsg() = + while not stopToken.load(moRelaxed): + let resp = chan1.tryRecv() + if resp.dataAvailable: + routeMessage(resp.msg) + echo "child consumes ", formatSize getOccupiedMem() + +createThread[void](recv, recvMsg) + +const MESSAGE_COUNT = 100 + +proc main() = + let msg: BackendMessage = BackendMessage(field: (0..500).toSeq()) + for j in 0..0: #100: + echo "New iteration" + + for _ in 1..MESSAGE_COUNT: + chan1.send(msg) + echo "After sending" + + var counter = 0 + while counter < MESSAGE_COUNT: + let resp = recv(chan2) + counter.inc + echo "After receiving ", formatSize getOccupiedMem() + + stopToken.store true, moRelaxed + joinThreads(recv) + +main() diff --git a/tests/tools/tunused_imports.nim b/tests/tools/tunused_imports.nim index 31d6cf7d7..539608ad6 100644 --- a/tests/tools/tunused_imports.nim +++ b/tests/tools/tunused_imports.nim @@ -1,9 +1,12 @@ discard """ cmd: '''nim c --hint:Processing:off $file''' nimout: ''' -tunused_imports.nim(11, 10) Warning: BEGIN [User] -tunused_imports.nim(36, 10) Warning: END [User] -tunused_imports.nim(34, 8) Warning: imported and not used: 'strutils' [UnusedImport] +tunused_imports.nim(14, 10) Warning: BEGIN [User] +tunused_imports.nim(41, 10) Warning: END [User] +tunused_imports.nim(37, 8) Warning: imported and not used: 'strutils' [UnusedImport] +tunused_imports.nim(38, 13) Warning: imported and not used: 'strtabs' [UnusedImport] +tunused_imports.nim(38, 22) Warning: imported and not used: 'cstrutils' [UnusedImport] +tunused_imports.nim(39, 12) Warning: imported and not used: 'macrocache' [UnusedImport] ''' action: "compile" """ @@ -32,5 +35,7 @@ macro bar(): untyped = bar() import strutils +import std/[strtabs, cstrutils] +import std/macrocache {.warning: "END".} diff --git a/tests/trmacros/tor.nim b/tests/trmacros/tor.nim index 6b4e71216..9defc4d1b 100644 --- a/tests/trmacros/tor.nim +++ b/tests/trmacros/tor.nim @@ -1,7 +1,7 @@ discard """ output: ''' 3 -0 +30 true ''' """ @@ -15,7 +15,9 @@ echo z template arithOps: untyped = (`+` | `-` | `*`) -template testOr{ (arithOps{f})(a, b) }(a, b, f: untyped): untyped = f(a mod 10, b) +template testOr{ (arithOps{f})(a, b) }(a, b, f: untyped): untyped = + {.noRewrite.}: + f(a mod 10, b) let xx = 10 echo 10*xx diff --git a/tests/trmacros/trmacros_various2.nim b/tests/trmacros/trmacros_various2.nim index 257ee8ba6..981df4ca6 100644 --- a/tests/trmacros/trmacros_various2.nim +++ b/tests/trmacros/trmacros_various2.nim @@ -70,7 +70,9 @@ block tstar: for i in 1..len(s)-1: result.add s[i] inc calls - template optConc{ `&&` * a }(a: string): string = &&a + template optConc{ `&&` * a }(a: string): string = + {.noRewrite.}: + &&a let space = " " echo "my" && (space & "awe" && "some " ) && "concat" diff --git a/tests/tuples/t18125_1.nim b/tests/tuples/t18125_1.nim new file mode 100644 index 000000000..74fdfe8f5 --- /dev/null +++ b/tests/tuples/t18125_1.nim @@ -0,0 +1,14 @@ +# issue #18125 solved with type inference + +type + Parent = ref object of RootObj + + Child = ref object of Parent + c: char + +func foo(c: char): (Parent, int) = + # Works if you use (Parent(Child(c: c)), 0) + (Child(c: c), 0) + +let x = foo('x')[0] +doAssert Child(x).c == 'x' diff --git a/tests/tuples/t18125_2.nim b/tests/tuples/t18125_2.nim new file mode 100644 index 000000000..fe0a4a8bb --- /dev/null +++ b/tests/tuples/t18125_2.nim @@ -0,0 +1,20 @@ +discard """ + errormsg: "type mismatch: got <(Child, int)> but expected '(Parent, int)'" + line: 17 +""" + +# issue #18125 solved with correct type relation + +type + Parent = ref object of RootObj + + Child = ref object of Parent + c: char + +func foo(c: char): (Parent, int) = + # Works if you use (Parent(Child(c: c)), 0) + let x = (Child(c: c), 0) + x + +let x = foo('x')[0] +doAssert Child(x).c == 'x' diff --git a/tests/typerel/tuncheckedarray_eq.nim b/tests/typerel/tuncheckedarray_eq.nim new file mode 100644 index 000000000..c07696b5f --- /dev/null +++ b/tests/typerel/tuncheckedarray_eq.nim @@ -0,0 +1,2 @@ +type p = ptr UncheckedArray[char] +doAssert p is ptr UncheckedArray \ No newline at end of file diff --git a/tests/types/t15836.nim b/tests/types/t15836.nim index 9c0c26dec..27d3ad0d0 100644 --- a/tests/types/t15836.nim +++ b/tests/types/t15836.nim @@ -1,5 +1,5 @@ discard """ - errormsg: "type mismatch: got <string> but expected 'int'" + errormsg: "type mismatch: got <int literal(1), proc (a: GenericParam): auto>" line: 11 """ diff --git a/tests/types/t15836_2.nim b/tests/types/t15836_2.nim index 9afef416a..6a16e2d22 100644 --- a/tests/types/t15836_2.nim +++ b/tests/types/t15836_2.nim @@ -1,8 +1,3 @@ - -discard """ - action: "compile" - disabled: true -""" import std/sugar type Tensor[T] = object diff --git a/tests/types/tinheritgenericparameter.nim b/tests/types/tinheritgenericparameter.nim index c88c50b7b..d0d313635 100644 --- a/tests/types/tinheritgenericparameter.nim +++ b/tests/types/tinheritgenericparameter.nim @@ -4,11 +4,11 @@ discard """ nimout:''' tinheritgenericparameter.nim(36, 15) Error: Cannot inherit from: 'MyObject' tinheritgenericparameter.nim(36, 15) Error: Cannot inherit from: 'MyObject' -tinheritgenericparameter.nim(36, 23) Error: object constructor needs an object type [proxy] +tinheritgenericparameter.nim(36, 23) Error: object constructor needs an object type [error] tinheritgenericparameter.nim(36, 23) Error: expression '' has no type (or is ambiguous) tinheritgenericparameter.nim(37, 15) Error: Cannot inherit from: 'int' tinheritgenericparameter.nim(37, 15) Error: Cannot inherit from: 'int' -tinheritgenericparameter.nim(37, 23) Error: object constructor needs an object type [proxy] +tinheritgenericparameter.nim(37, 23) Error: object constructor needs an object type [error] tinheritgenericparameter.nim(37, 23) Error: expression '' has no type (or is ambiguous) ''' """ diff --git a/tests/types/tisopr.nim b/tests/types/tisopr.nim index 64b3d03c0..c95b63c90 100644 --- a/tests/types/tisopr.nim +++ b/tests/types/tisopr.nim @@ -165,3 +165,7 @@ block: # previously tisop.nim doAssert f.y.typeof is float doAssert f.z.typeof is float p(A, f) + +block: # issue #22850 + doAssert not (type is int) + doAssert not (typedesc is int) diff --git a/tests/types/tissues_types.nim b/tests/types/tissues_types.nim index eab4e8e9b..6bb1258f4 100644 --- a/tests/types/tissues_types.nim +++ b/tests/types/tissues_types.nim @@ -96,3 +96,23 @@ block: # issue #12582 x: foo(int) # error let b = Bar() let b2 = Bar(x: [123]) + +block: + when true: # bug #14710 + type Foo[T] = object + x1: int + when T.sizeof == 4: discard # SIGSEGV + when sizeof(T) == 4: discard # ok + let t = Foo[float](x1: 1) + doAssert t.x1 == 1 + +block: + template s(d: varargs[typed])=discard + + proc something(x:float)=discard + proc something(x:int)=discard + proc otherthing()=discard + + s(something) + s(otherthing, something) + s(something, otherthing) diff --git a/tests/types/ttopdowninference.nim b/tests/types/ttopdowninference.nim index 2a26e0e34..765761e99 100644 --- a/tests/types/ttopdowninference.nim +++ b/tests/types/ttopdowninference.nim @@ -325,3 +325,9 @@ block: # bug #22180 else: (ref A)(nil) doAssert y.isNil + +block: # issue #24164, related regression + proc foo(x: proc ()) = discard + template bar(x: untyped = nil) = + foo(x) + bar() diff --git a/tests/varres/tprevent_forloopvar_mutations.nim b/tests/varres/tprevent_forloopvar_mutations.nim index b27c327a9..c9aeb94d8 100644 --- a/tests/varres/tprevent_forloopvar_mutations.nim +++ b/tests/varres/tprevent_forloopvar_mutations.nim @@ -2,7 +2,7 @@ discard """ errormsg: "type mismatch: got <int>" nimout: '''tprevent_forloopvar_mutations.nim(16, 3) Error: type mismatch: got <int> but expected one of: -proc inc[T: Ordinal](x: var T; y: int = 1) +proc inc[T, V: Ordinal](x: var T; y: V = 1) first type mismatch at position: 1 required type for x: var T: Ordinal but expression 'i' is immutable, not 'var' diff --git a/tests/varstmt/tvardecl.nim b/tests/varstmt/tvardecl.nim index 37bc4bad7..d5ccfafb7 100644 --- a/tests/varstmt/tvardecl.nim +++ b/tests/varstmt/tvardecl.nim @@ -2,6 +2,7 @@ discard """ output: "44" """ # Test the new variable declaration syntax +import std/sequtils var x = 0 @@ -10,3 +11,9 @@ var write(stdout, a) writeLine(stdout, b) #OUT 44 + +proc p() = # bug #18104 + var x, y = newSeqWith(10, newString(3)) + discard (x, y) + +p() diff --git a/tests/views/tviews1.nim b/tests/views/tviews1.nim index 6662e3e5a..9785d25e5 100644 --- a/tests/views/tviews1.nim +++ b/tests/views/tviews1.nim @@ -105,3 +105,32 @@ block: # bug #22117 result = aref doAssert main() == 10 + +type + Slice*[T] = object + first, last: int + p: ptr UncheckedArray[T] + +var i = 0 + +converter autoToOpenArray*[T](s: Slice[T]): openArray[T] = + inc i + result = toOpenArray(s.p, s.first, s.last) + +proc acceptOpenArray(s: openArray[byte]) = discard + +proc bug22597 = # bug #22597 + acceptOpenArray(Slice[byte]()) + doAssert i == 1 + +bug22597() + +block: # bug #20048 + type + Test = object + tokens: openArray[string] + + func init(Self: typedesc[Test], tokens: openArray[string]): Self = Self(tokens: tokens) + + let data = Test.init(["123"]) + doAssert @(data.tokens) == @["123"] diff --git a/tests/views/tviews2.nim b/tests/views/tviews2.nim new file mode 100644 index 000000000..29aff76df --- /dev/null +++ b/tests/views/tviews2.nim @@ -0,0 +1,90 @@ +discard """ + targets: "c js" +""" + +{.experimental: "views".} + +block: + type + Foo = object + id: openArray[char] + + proc foo(): Foo = + var source = "1245" + result = Foo(id: source.toOpenArray(0, 1)) + + doAssert foo().id == @['1', '2'] + +block: # bug #15778 + type + Reader = object + data: openArray[char] + current: int + + var count = 0 + + proc read(data: var Reader, length: int): openArray[char] = + inc count + let start = data.current + data.current.inc length + return data.data.toOpenArray(start, data.current-1) + + var data = "hello there" + var reader = Reader(data: data.toOpenArray(0, data.len-1), current: 0) + doAssert @(reader.read(2)) == @['h', 'e'] + doAssert @(reader.read(3)) == @['l', 'l', 'o'] + doAssert count == 2 + +block: # bug #16671 + block: + type X = ref object of RootObj + type Y = ref object of X + field: openArray[int] + + var s: seq[X] + proc f() = + s.add(Y(field: [1])) + + f() + + block: + type X = ref object of RootObj + type Y = ref object of X + field: openArray[int] + + var s: seq[X] + proc f() = + s.add(Y(field: toOpenArray([1, 2, 3], 0, 1))) + + f() + +block: # bug #15746 + type + Reader = object + data: openArray[char] + current: int + + proc initReader(data: openArray[char], offset = 0): Reader = + result = Reader(data: data, current: offset) + + let s = "\x01\x00\x00\x00" + doAssert initReader(s).data[0].int == 1 + +block: + proc foo(x: openArray[char]) = + discard x + + foo("12254") + foo(@['a', 'b']) + + var a1 = "12254" + foo(a1) + + var a2 = @['a', 'b'] + foo(a2) + + var s = "138443" + var ooo: openArray[char] = s + var xxx: openArray[char] = ooo + foo(ooo) + foo(xxx) diff --git a/tests/vm/tconst.nim b/tests/vm/tconst.nim index c2bcf78b5..5cfe7533e 100644 --- a/tests/vm/tconst.nim +++ b/tests/vm/tconst.nim @@ -42,6 +42,16 @@ template main() = discard (x, increment, a) mytemp() + block: # bug #12334 + block: + const b: cstring = "foo" + var c = b + doAssert c == "foo" + block: + const a = "foo" + const b: cstring = a + var c = b + doAssert c == "foo" static: main() diff --git a/tests/vm/tconstarrayresem.nim b/tests/vm/tconstarrayresem.nim new file mode 100644 index 000000000..6701cfe4d --- /dev/null +++ b/tests/vm/tconstarrayresem.nim @@ -0,0 +1,29 @@ +# issue #23010 + +type + Result[T, E] = object + case oResult: bool + of false: + discard + of true: + vResult: T + + Opt[T] = Result[T, void] + +template ok[T, E](R: type Result[T, E], x: untyped): R = + R(oResult: true, vResult: x) + +template c[T](v: T): Opt[T] = Opt[T].ok(v) + +type + FixedBytes[N: static[int]] = distinct array[N, byte] + + H = object + d: FixedBytes[2] + +const b = default(H) +template g(): untyped = + const t = default(H) + b + +discard c(g()) diff --git a/tests/vm/tconstscope1.nim b/tests/vm/tconstscope1.nim new file mode 100644 index 000000000..41c45a28f --- /dev/null +++ b/tests/vm/tconstscope1.nim @@ -0,0 +1,5 @@ +# issue #5395 + +const a = (var b = 3; b) +echo b #[tt.Error + ^ undeclared identifier: 'b']# diff --git a/tests/vm/tconstscope2.nim b/tests/vm/tconstscope2.nim new file mode 100644 index 000000000..d858e96c2 --- /dev/null +++ b/tests/vm/tconstscope2.nim @@ -0,0 +1,5 @@ +const + a = (var x = 3; x) + # should we allow this? + b = x #[tt.Error + ^ undeclared identifier: 'x']# diff --git a/tests/vm/tconsttable.nim b/tests/vm/tconsttable.nim index 64a74a59d..152a33cba 100644 --- a/tests/vm/tconsttable.nim +++ b/tests/vm/tconsttable.nim @@ -17,3 +17,18 @@ x = "ah" echo foo[x] x = "possible." echo foo[x] + +block: # bug #19840 + const testBytes = [byte 0xD8, 0x08, 0xDF, 0x45, 0x00, 0x3D, 0x00, 0x52, 0x00, 0x61] + var tempStr = "__________________" + + tempStr.prepareMutation + copyMem(addr tempStr[0], addr testBytes[0], testBytes.len) + +block: # bug #22389 + func foo(): ptr UncheckedArray[byte] = + const bar = [77.byte] + cast[ptr UncheckedArray[byte]](addr bar[0]) + + doAssert foo()[0] == 77 + diff --git a/tests/vm/tconvaddr.nim b/tests/vm/tconvaddr.nim new file mode 100644 index 000000000..9762a9e59 --- /dev/null +++ b/tests/vm/tconvaddr.nim @@ -0,0 +1,49 @@ +block: # issue #24097 + type Foo = distinct int + proc foo(x: var Foo) = + int(x) += 1 + proc bar(x: var int) = + x += 1 + static: + var x = Foo(1) + int(x) = int(x) + 1 + doAssert x.int == 2 + int(x) += 1 + doAssert x.int == 3 + foo(x) + doAssert x.int == 4 + bar(int(x)) # need vmgen flags propagated for this + doAssert x.int == 5 + type Bar = object + x: Foo + static: + var obj = Bar(x: Foo(1)) + int(obj.x) = int(obj.x) + 1 + doAssert obj.x.int == 2 + int(obj.x) += 1 + doAssert obj.x.int == 3 + foo(obj.x) + doAssert obj.x.int == 4 + bar(int(obj.x)) # need vmgen flags propagated for this + doAssert obj.x.int == 5 + static: + var arr = @[Foo(1)] + int(arr[0]) = int(arr[0]) + 1 + doAssert arr[0].int == 2 + int(arr[0]) += 1 + doAssert arr[0].int == 3 + foo(arr[0]) + doAssert arr[0].int == 4 + bar(int(arr[0])) # need vmgen flags propagated for this + doAssert arr[0].int == 5 + proc testResult(): Foo = + result = Foo(1) + int(result) = int(result) + 1 + doAssert result.int == 2 + int(result) += 1 + doAssert result.int == 3 + foo(result) + doAssert result.int == 4 + bar(int(result)) # need vmgen flags propagated for this + doAssert result.int == 5 + doAssert testResult().int == 5 diff --git a/tests/vm/tgenericcompiletimeproc.nim b/tests/vm/tgenericcompiletimeproc.nim new file mode 100644 index 000000000..08099ebbe --- /dev/null +++ b/tests/vm/tgenericcompiletimeproc.nim @@ -0,0 +1,36 @@ +block: # issue #10753 + proc foo(x: int): int {.compileTime.} = x + const a = foo(123) + doAssert foo(123) == a + + proc bar[T](x: T): T {.compileTime.} = x + const b = bar(123) + doAssert bar(123) == b + const c = bar("abc") + doAssert bar("abc") == c + +block: # issue #22021 + proc foo(x: static int): int {.compileTime.} = x + 1 + doAssert foo(123) == 124 + +block: # issue #19365 + proc f[T](x: static T): T {.compileTime.} = x + x + doAssert f(123) == 246 + doAssert f(1.0) == 2.0 + +block: + # don't fold compile time procs in typeof + proc fail[T](x: T): T {.compileTime.} = + doAssert false + x + doAssert typeof(fail(123)) is typeof(123) + proc p(x: int): int = x + + type Foo = typeof(p(fail(123))) + +block: # issue #24150, related regression + proc w(T: type): T {.compileTime.} = default(ptr T)[] + template y(v: auto): auto = typeof(v) is int + discard compiles(y(w int)) + proc s(): int {.compileTime.} = discard + discard s() diff --git a/tests/vm/tnilclosurecall.nim b/tests/vm/tnilclosurecall.nim new file mode 100644 index 000000000..449865b9c --- /dev/null +++ b/tests/vm/tnilclosurecall.nim @@ -0,0 +1,8 @@ +discard """ + errormsg: "attempt to call nil closure" + line: 8 +""" + +static: + let x: proc () = nil + x() diff --git a/tests/vm/tnilclosurecallstacktrace.nim b/tests/vm/tnilclosurecallstacktrace.nim new file mode 100644 index 000000000..879060e8e --- /dev/null +++ b/tests/vm/tnilclosurecallstacktrace.nim @@ -0,0 +1,23 @@ +discard """ + action: reject + nimout: ''' +stack trace: (most recent call last) +tnilclosurecallstacktrace.nim(23, 6) tnilclosurecallstacktrace +tnilclosurecallstacktrace.nim(20, 6) baz +tnilclosurecallstacktrace.nim(17, 6) bar +tnilclosurecallstacktrace.nim(14, 4) foo +tnilclosurecallstacktrace.nim(14, 4) Error: attempt to call nil closure +''' +""" + +proc foo(x: proc ()) = + x() + +proc bar(x: proc ()) = + foo(x) + +proc baz(x: proc ()) = + bar(x) + +static: + baz(nil) diff --git a/tests/vm/topenarrays.nim b/tests/vm/topenarrays.nim index 0a822f583..375d2523d 100644 --- a/tests/vm/topenarrays.nim +++ b/tests/vm/topenarrays.nim @@ -67,3 +67,23 @@ template fn= doAssert test([0,1,2,3,4,5]).id == 0 fn() # ok static: fn() + + +block: # bug #22095 + type + StUint = object + limbs: array[4, uint64] + + func shlAddMod(a: var openArray[uint64]) = + a[0] = 10 + + func divRem(r: var openArray[uint64]) = + shlAddMod(r.toOpenArray(0, 3)) + + func fn(): StUint = + divRem(result.limbs) + + const + z = fn() + + doAssert z.limbs[0] == 10 diff --git a/tests/vm/ttypedesc.nim b/tests/vm/ttypedesc.nim index a112584c5..d799e5adb 100644 --- a/tests/vm/ttypedesc.nim +++ b/tests/vm/ttypedesc.nim @@ -16,3 +16,16 @@ block: # issue #15760 doAssert x[SpecialBanana]() == "SpecialBanana" doAssert y(SpecialBanana) == "SpecialBanana" + +import macros + +block: # issue #23112 + type Container = object + foo: string + + proc canBeImplicit(t: typedesc) {.compileTime.} = + let tDesc = getType(t) + doAssert tDesc.kind == nnkObjectTy + + static: + canBeImplicit(Container) diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim index cade68577..6aeac5529 100644 --- a/tests/vm/tvmmisc.nim +++ b/tests/vm/tvmmisc.nim @@ -4,8 +4,7 @@ import os # bug #4462 block: proc foo(t: typedesc) {.compileTime.} = - assert sameType(getType(t), getType(typedesc[int])) - assert sameType(getType(t), getType(type int)) + assert sameType(getType(t), getType(int)) static: foo(int) @@ -302,14 +301,6 @@ block: # bug #10815 const a = P() doAssert $a == "" -when defined osx: # xxx bug #13481 - block: - type CharSet {.union.} = object - cs: set[char] - vs: array[4, uint64] - const a = Charset(cs: {'a'..'z'}) - doAssert a.repr.len > 0 - import tables block: # bug #8007 @@ -364,7 +355,7 @@ block: # bug #8007 block: # bug #14340 block: proc opl3EnvelopeCalcSin0() = discard - type EnvelopeSinfunc = proc() + type EnvelopeSinfunc = proc() {.nimcall.} # todo: fixme # const EnvelopeCalcSin0 = opl3EnvelopeCalcSin0 # ok const EnvelopeCalcSin0: EnvelopeSinfunc = opl3EnvelopeCalcSin0 # was bug const envelopeSin = [EnvelopeCalcSin0] @@ -575,7 +566,7 @@ block: block: static: let x = int 1 - doAssert $(x.type) == "Foo" # Foo + doAssert $(x.type) == "int" # Foo block: static: @@ -775,3 +766,31 @@ block: # issue #15730 static: # more nil cstring issues let x = cstring(nil) doAssert x.len == 0 + +block: # bug #23925 + type Foo = enum A = -1 + proc foo = + doAssert cast[Foo](-1) == A + doAssert ord(A) == -1 + + static: foo() + foo() + + type E = enum + e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 e10 e11 e12 e13 e14 e15 e16 e17 e18 e19 e20 + e21 e22 e23 e24 e25 e26 e27 e28 e29 e30 e31 e32 e33 e34 e35 e36 e37 e38 + e39 e40 e41 e42 e43 e44 e45 e46 e47 e48 e49 e50 e51 e52 e53 e54 e55 e56 + e57 e58 e59 e60 e61 e62 e63 e64 e65 e66 e67 e68 e69 e70 e71 e72 e73 e74 + e75 e76 e77 e78 e79 e80 e81 e82 e83 e84 e85 e86 e87 e88 e89 e90 e91 e92 + e93 e94 e95 e96 e97 e98 e99 e100 e101 e102 e103 e104 e105 e106 e107 e108 + e109 e110 e111 e112 e113 e114 e115 e116 e117 e118 e119 e120 e121 e122 + e123 e124 e125 e126 e127 e128 + proc bar = + doAssert cast[E](int(e128)) == e128 + + static: bar() + bar() + +static: # bug #21353 + var s: proc () = default(proc ()) + doAssert s == nil diff --git a/tests/vm/tvmopsDanger.nim b/tests/vm/tvmopsDanger.nim index 5e7bac29a..966feffe6 100644 --- a/tests/vm/tvmopsDanger.nim +++ b/tests/vm/tvmopsDanger.nim @@ -3,8 +3,11 @@ discard """ """ when defined(nimPreviewSlimSystem): import std/assertions -import std/times +import std/[times, os] const foo = getTime() let bar = foo -doAssert bar > low(Time) \ No newline at end of file +doAssert bar > low(Time) + +static: # bug #23932 + doAssert getCurrentDir().len > 0 |