diff options
Diffstat (limited to 'tests/template')
49 files changed, 1314 insertions, 16 deletions
diff --git a/tests/template/m1027a.nim b/tests/template/m1027a.nim new file mode 100644 index 000000000..fad915a2f --- /dev/null +++ b/tests/template/m1027a.nim @@ -0,0 +1 @@ +const version_str* = "mod a" diff --git a/tests/template/m1027b.nim b/tests/template/m1027b.nim new file mode 100644 index 000000000..5ff0b9714 --- /dev/null +++ b/tests/template/m1027b.nim @@ -0,0 +1 @@ +const version_str* = "mod b" 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/mdotcall.nim b/tests/template/mdotcall.nim new file mode 100644 index 000000000..fecd8ee26 --- /dev/null +++ b/tests/template/mdotcall.nim @@ -0,0 +1,82 @@ +# issue #20073 + +type Foo = object +proc foo(f: Foo) = discard + +template works*() = + var f: Foo + foo(f) + +template boom*() = + var f: Foo + f.foo() # Error: attempting to call undeclared routine: 'foo' + f.foo # Error: undeclared field: 'foo' for type a.Foo + +# issue #7085 + +proc bar(a: string): string = + return a & "bar" + +template baz*(a: string): string = + var b = a.bar() + b + +# issue #7223 + +import mdotcall2 + +type + Bytes* = seq[byte] + + BytesRange* = object + bytes*: Bytes + ibegin*, iend*: int + +proc privateProc(r: BytesRange): int = r.ibegin + +template rangeBeginAddr*(r: BytesRange): pointer = + r.bytes.baseAddr.shift(r.privateProc) + +# issue #11733 + +type ObjA* = object + +proc foo2(o: var ObjA) = discard +proc bar2(o: var ObjA, arg: Natural) = discard + +template publicTemplateObjSyntax*(o: var ObjA, arg: Natural, doStuff: untyped) = + o.foo2() + doStuff + o.bar2(arg) + +# issue #15246 +import os + +template sourceBaseName*(): string = + bind splitFile + instantiationInfo().filename.splitFile().name + +# issue #12683 + +import unicode +template toRune(s: string): Rune = s.runeAt(0) +proc heh*[T](x: Slice[T], chars: string) = discard chars.toRune + +# issue #7889 + +from streams import newStringStream, readData, writeData + +template bindmeTemplate*(): untyped = + var tst = "sometext" + var ss = newStringStream("anothertext") + ss.writeData(tst[0].addr, 2) + discard ss.readData(tst[0].addr, 2) # <= comment this out to make compilation successful + +from macros import quote, newIdentNode + +macro bindmeQuote*(): untyped = + quote do: + var tst = "sometext" + var ss = newStringStream("anothertext") + ss.writeData(tst[0].addr, 2) + discard ss.readData(tst[0].addr, 2) # <= comment this out to make compilation successful diff --git a/tests/template/mdotcall2.nim b/tests/template/mdotcall2.nim new file mode 100644 index 000000000..e906ac9d6 --- /dev/null +++ b/tests/template/mdotcall2.nim @@ -0,0 +1,7 @@ +# imported by mdotcall + +proc baseAddr*[T](x: openarray[T]): pointer = + cast[pointer](x) + +proc shift*(p: pointer, delta: int): pointer = + cast[pointer](cast[int](p) + delta) 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/otests.nim b/tests/template/otests.nim index 120146343..9cb9d7fcb 100644 --- a/tests/template/otests.nim +++ b/tests/template/otests.nim @@ -163,7 +163,7 @@ when true: #embeddingTest """ # Expression template - proc test_expression(nums: openarray[int] = []): string = + proc test_expression(nums: openArray[int] = []): string = var i = 2 tmpli html""" $(no_substitution()) @@ -171,7 +171,7 @@ when true: #embeddingTest <div id="age">Age: $($nums[i] & "!!")</div> """ - proc test_statements(nums: openarray[int] = []): string = + proc test_statements(nums: openArray[int] = []): string = tmpli html""" $(test_expression(nums)) $if true { diff --git a/tests/template/sunset.nimf b/tests/template/sunset.nimf index 465b12a5e..bd57bb8e1 100644 --- a/tests/template/sunset.nimf +++ b/tests/template/sunset.nimf @@ -1,6 +1,6 @@ #? stdtmpl #proc sunsetTemplate*(current, ticker, content: string, -# tabs: openarray[array[0..1, string]]): string = +# tabs: openArray[array[0..1, string]]): string = # result = "" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> diff --git a/tests/template/t1027.nim b/tests/template/t1027.nim new file mode 100644 index 000000000..fe03c4ea9 --- /dev/null +++ b/tests/template/t1027.nim @@ -0,0 +1,22 @@ +discard """ + cmd: "nim check --hints:off $file" + errormsg: "" + nimout: ''' +t1027.nim(20, 19) Error: ambiguous identifier: 'version_str' -- use one of the following: + m1027a.version_str: string + m1027b.version_str: string +''' +""" + + + + + + +import m1027a, m1027b + +# bug #1027 +template wrap_me(stuff): untyped = + echo "Using " & version_str + +wrap_me("hey") diff --git a/tests/template/t11705.nim b/tests/template/t11705.nim new file mode 100644 index 000000000..65ddc7e6c --- /dev/null +++ b/tests/template/t11705.nim @@ -0,0 +1,17 @@ +type RefObj = ref object + +proc `[]`(val: static[int]) = # works with different name/overload or without static arg + discard + +template noRef*(T: typedesc): typedesc = # works without template indirection + typeof(default(T)[]) + +proc `=destroy`(x: var noRef(RefObj)) = + discard + +proc foo = + var x = new RefObj + doAssert $(x[]) == "()" + +# bug #11705 +foo() 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/t17433.nim b/tests/template/t17433.nim new file mode 100644 index 000000000..053d33ff0 --- /dev/null +++ b/tests/template/t17433.nim @@ -0,0 +1,16 @@ +# Inside template bodies, ensure return types referencing a param are replaced. +# This helps guarantee that return parameter analysis happens after argument +# analysis. + +# bug #17433 + +from std/macros import expandMacros + +proc bar(a: typedesc): a = default(a) +doAssert bar(float) == 0.0 +doAssert bar(string) == "" + +template main = + proc baz(a: typedesc): a = default(a) + doAssert baz(float) == 0.0 +main() diff --git a/tests/template/t18113.nim b/tests/template/t18113.nim new file mode 100644 index 000000000..a84b3fd0e --- /dev/null +++ b/tests/template/t18113.nim @@ -0,0 +1,14 @@ +# ensure template pragma handling doesn't eagerly attempt to add an implicit +# 'pushed' pragma to the evaluation of any intermediate AST prior to +# substitution. + +# bug #18113 + +import sequtils + +{.push raises: [Defect].} + +var a = toSeq([1, 2, 3, 5, 10]).filterIt(it > 5) + +doAssert a.len == 1 +doAssert a[0] == 10 diff --git a/tests/template/t19149.nim b/tests/template/t19149.nim new file mode 100644 index 000000000..631e8fc30 --- /dev/null +++ b/tests/template/t19149.nim @@ -0,0 +1,19 @@ +type Foo = tuple[active: bool, index: int] + + +var f: Foo + +# template result type during match stage +# f:var Foo +# a:Foo +# tyVar +# tyTuple +# after change to proc +# f:Foo +# a:Foo +# tyTuple +# tyTuple + +template cursor(): var Foo = f +discard cursor() + 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/t19700.nim b/tests/template/t19700.nim new file mode 100644 index 000000000..cc2944944 --- /dev/null +++ b/tests/template/t19700.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "type mismatch: got <Obj, Obj, template (x: untyped, y: untyped): untyped>" +""" + +type Obj = object + +proc apply[T, R](a, b: T; f: proc(x, y: T): R): R = f(a, b) + +let a, b = Obj() +discard apply(a, b, `!=`) diff --git a/tests/template/t21231.nim b/tests/template/t21231.nim new file mode 100644 index 000000000..51e96cdd6 --- /dev/null +++ b/tests/template/t21231.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "undeclared identifier: 'x'" +""" + +var x: int +# bug #21231 +template f(y: untyped) = echo y.x +for i in 1 .. 10: + x = i + f(system) diff --git a/tests/template/t21532.nim b/tests/template/t21532.nim new file mode 100644 index 000000000..3193b0dc3 --- /dev/null +++ b/tests/template/t21532.nim @@ -0,0 +1,8 @@ + +template elementType(a: untyped): typedesc = + typeof(block: (for ai in a: ai)) + +func fn[T](a: T) = + doAssert elementType(a) is int + +@[1,2,3].fn \ No newline at end of file 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/t6217.nim b/tests/template/t6217.nim new file mode 100644 index 000000000..b27b61881 --- /dev/null +++ b/tests/template/t6217.nim @@ -0,0 +1,19 @@ +discard """ + output: ''' +start +side effect! +end +''' +""" + +# bug #6217 + +template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a+a + +proc f(): int = + echo "side effect!" + result = 55 + +echo "start" +doAssert f() * 2 == 110 +echo "end" diff --git a/tests/template/t9534.nim b/tests/template/t9534.nim new file mode 100644 index 000000000..8d66f42a0 --- /dev/null +++ b/tests/template/t9534.nim @@ -0,0 +1,21 @@ +discard """ + targets: "c cpp" +""" + +# bug #9534 +type + Object = object + data: int + +template test() = + proc methodName(o: Object): int = + var p: pointer + doAssert o.data == 521 + let f {.used.} = cast[proc (o: int): int {.nimcall.}](p) + doAssert o.data == 521 + result = 1314 + + var a = Object(data: 521) + doAssert methodName(a) == 1314 + +test() diff --git a/tests/template/taliassyntax.nim b/tests/template/taliassyntax.nim new file mode 100644 index 000000000..2d8237d93 --- /dev/null +++ b/tests/template/taliassyntax.nim @@ -0,0 +1,74 @@ +type Foo = object + bar: int + +var foo = Foo(bar: 10) +template bar: int = foo.bar +doAssert bar == 10 +bar = 15 +doAssert bar == 15 +var foo2 = Foo(bar: -10) +doAssert bar == 15 +# works in generics +proc genericProc[T](x: T): string = + $(x, bar) +doAssert genericProc(true) == "(true, 15)" +# redefine +template bar: int {.redefine.} = foo2.bar +doAssert bar == -10 + +block: # subscript + var bazVal = @[1, 2, 3] + template baz: seq[int] = bazVal + doAssert baz[1] == 2 + proc genericProc2[T](x: T): string = + result = $(x, baz[1]) + baz[1] = 7 + doAssert genericProc2(true) == "(true, 2)" + doAssert baz[1] == 7 + baz[1] = 14 + doAssert baz[1] == 14 + +block: # type alias + template Int2: untyped = int + let x: Int2 = 123 + proc generic[T](): string = + template U: untyped = T + var x: U + result = $typeof(x) + doAssert result == $U + doAssert result == $T + doAssert generic[int]() == "int" + doAssert generic[Int2]() == "int" + doAssert generic[string]() == "string" + doAssert generic[seq[int]]() == "seq[int]" + doAssert generic[seq[Int2]]() == "seq[int]" + discard generic[123]() + proc genericStatic[X; T: static[X]](): string = + template U: untyped = T + result = $U + doAssert result == $T + doAssert genericStatic[int, 123]() == "123" + doAssert genericStatic[Int2, 123]() == "123" + doAssert genericStatic[(string, bool), ("a", true)]() == "(\"a\", true)" + +block: # issue #13515 + template test: bool = true + # compiles: + if not test: + doAssert false + # does not compile: + template x = + if not test: + doAssert false + x + +import macros + +block: # issue #21727 + template debugAnnotation(s: typed): string = + astToStr s + + macro cpsJump(x: int): untyped = + result = newLit(debugAnnotation(cpsJump)) + + doAssert cpsJump(13) == "cpsJump" diff --git a/tests/template/taliassyntaxerrors.nim b/tests/template/taliassyntaxerrors.nim new file mode 100644 index 000000000..f16acaf91 --- /dev/null +++ b/tests/template/taliassyntaxerrors.nim @@ -0,0 +1,28 @@ +discard """ + cmd: "nim check --hints:off $file" +""" + +block: # with params + type Foo = object + bar: int + + var foo = Foo(bar: 10) + template bar(x: int): int = x + foo.bar + let a = bar #[tt.Error + ^ invalid type: 'template (x: int): int' for let. Did you mean to call the template with '()'?]# + bar = 15 #[tt.Error + ^ 'bar' cannot be assigned to]# + +block: # generic template + type Foo = object + bar: int + + var foo = Foo(bar: 10) + template bar[T]: T = T(foo.bar) + let a = bar #[tt.Error + ^ invalid type: 'template (): T' for let. Did you mean to call the template with '()'?; tt.Error + ^ 'bar' has unspecified generic parameters]# + let b = bar[float]() + doAssert b == 10.0 + bar = 15 #[tt.Error + ^ 'bar' cannot be assigned to]# diff --git a/tests/template/tcallsitelineinfo.nim b/tests/template/tcallsitelineinfo.nim new file mode 100644 index 000000000..5fed93363 --- /dev/null +++ b/tests/template/tcallsitelineinfo.nim @@ -0,0 +1,17 @@ +discard """ + nimout: ''' +tcallsitelineinfo.nim(17, 4) Warning: abc [User] +''' + exitcode: 1 + outputsub: ''' +tcallsitelineinfo.nim(17) tcallsitelineinfo +Error: unhandled exception: def [ValueError] +''' +""" + +template foo(): untyped {.callsite.} = + {.warning: "abc".} + raise newException(ValueError, "def") + echo "hello" + +foo() diff --git a/tests/template/tcallsitelineinfo2.nim b/tests/template/tcallsitelineinfo2.nim new file mode 100644 index 000000000..d5f257474 --- /dev/null +++ b/tests/template/tcallsitelineinfo2.nim @@ -0,0 +1,20 @@ +discard """ + nimout: ''' +tcallsitelineinfo2.nim(18, 1) Warning: abc [User] +tcallsitelineinfo2.nim(19, 12) Warning: def [User] +''' + exitcode: 1 + outputsub: ''' +tcallsitelineinfo2.nim(20) tcallsitelineinfo2 +Error: unhandled exception: ghi [ValueError] +''' +""" + +template foo(a: untyped): untyped {.callsite.} = + {.warning: "abc".} + a + echo "hello" + +foo: # with `{.line.}:`, the following do not keep their line information: + {.warning: "def".} + raise newException(ValueError, "ghi") 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/tdotcall.nim b/tests/template/tdotcall.nim new file mode 100644 index 000000000..dc97fd52e --- /dev/null +++ b/tests/template/tdotcall.nim @@ -0,0 +1,32 @@ +import mdotcall + +block: # issue #20073 + works() + boom() + +block: # issue #7085 + doAssert baz("hello") == "hellobar" + doAssert baz"hello" == "hellobar" + doAssert "hello".baz == "hellobar" + +block: # issue #7223 + var r = BytesRange(bytes: @[1.byte, 2, 3], ibegin: 0, iend: 2) + var a = r.rangeBeginAddr + +block: # issue #11733 + var a: ObjA + var evaluated = false + a.publicTemplateObjSyntax(42): evaluated = true + doAssert evaluated + +block: # issue #15246 + doAssert sourceBaseName() == "tdotcall" + +block: # issue #12683 + heh(0..40, "|") + +block: # issue #7889 + if false: + bindmeQuote() + if false: + bindmeTemplate() diff --git a/tests/template/template_issues.nim b/tests/template/template_issues.nim index 502c6d1ee..58c40941d 100644 --- a/tests/template/template_issues.nim +++ b/tests/template/template_issues.nim @@ -173,7 +173,7 @@ block t2585: st echo "a ", $fb - proc render(rdat: var RenderData; passes: var openarray[RenderPass]; proj: Mat2; + proc render(rdat: var RenderData; passes: var openArray[RenderPass]; proj: Mat2; indexType = 1) = for i in 0 ..< len(passes): echo "blah ", repr(passes[i]) @@ -296,3 +296,9 @@ block: # bug #12595 discard {i: ""} test() + +block: # bug #21920 + template t[T](): T = + discard + + t[void]() # Error: expression has no type: discard diff --git a/tests/template/template_pragmas.nim b/tests/template/template_pragmas.nim index d6c99080d..da532b010 100644 --- a/tests/template/template_pragmas.nim +++ b/tests/template/template_pragmas.nim @@ -3,7 +3,7 @@ proc output_x:string {.compileTime.} = "x" template t = const x = output_x() let - bar {.exportC:"bar" & x.} = 100 + bar {.exportc:"bar" & x.} = 100 static: doAssert(compiles (t())) diff --git a/tests/template/template_various.nim b/tests/template/template_various.nim index 75226ea2d..2088b1739 100644 --- a/tests/template/template_various.nim +++ b/tests/template/template_various.nim @@ -94,7 +94,7 @@ block generic_templates: var i3: int = t1[int]("xx") - +from strutils import contains block tgetast_typeliar: proc error(s: string) = quit s @@ -111,7 +111,9 @@ block tgetast_typeliar: var message : NimNode = newLit(condition.repr) # echo message result = getAst assertOrReturn2(condition, message) - echo result.repr + # echo result.repr + let s = result.repr + doAssert """error("Assertion failed:""" in s proc point(size: int16): tuple[x, y: int16] = # returns random point in square area with given `size` @@ -272,10 +274,10 @@ parse9: block gensym1: template x: untyped = -1 template t1() = - template x: untyped {.gensym.} = 1 + template x: untyped {.gensym, redefine.} = 1 echo x() # 1 template t2() = - template x: untyped = 1 # defaults to {.inject.} + template x: untyped {.redefine.} = 1 # defaults to {.inject.} echo x() # -1 injected x not available during template definition t1() t2() @@ -351,3 +353,54 @@ block gensym3: echo a ! b ! c ! d echo a ! b ! c ! d ! e echo x,y,z + +block: # issue #2465 + template t() = + template declX(str: string) {.gensym.} = + var x {.inject.} : string = str + + t() + doAssert not declared(declX) + doAssert not compiles(declX("a string")) + + template t2() = + template fooGensym() {.gensym.} = + echo 42 + + t2() + doAssert not declared(fooGensym) + doAssert not compiles(fooGensym()) + + +block identifier_construction_with_overridden_symbol: + # could use add, but wanna make sure it's an override no matter what + func examplefn = discard + func examplefn(x: int) = discard + + # the function our template wants to use + func examplefn1 = discard + + template exampletempl(n) = + # attempt to build a name using the overridden symbol "examplefn" + `examplefn n`() + + exampletempl(1) + +import typetraits + +block: # issue #4596 + type + T0 = object + T1 = object + + template printFuncsT() = + proc getV[A](a: typedesc[A]): string = + var s {. global .} = name(A) + return s + + printFuncsT() + + doAssert getV(T1) == "T1" + doAssert getV(T0) == "T0" + doAssert getV(T0) == "T0" + doAssert getV(T1) == "T1" diff --git a/tests/template/tgenericparam.nim b/tests/template/tgenericparam.nim new file mode 100644 index 000000000..becf75d36 --- /dev/null +++ b/tests/template/tgenericparam.nim @@ -0,0 +1,93 @@ +block: # basic template generic parameter substitution + block: # issue #13527 + template typeNameTempl[T](a: T): string = $T + proc typeNameProc[T](a: T): string = $T + doAssert typeNameTempl(1) == typeNameProc(1) + doAssert typeNameTempl(true) == typeNameProc(true) + doAssert typeNameTempl(1.0) == typeNameProc(1.0) + doAssert typeNameTempl(1u8) == typeNameProc(1u8) + + template isDefault[T](a: T): bool = a == default(T) + doAssert isDefault(0.0) + + block: # issue #17240 + func to(c: int, t: typedesc[float]): t = discard + template converted[I, T](i: seq[I], t: typedesc[T]): seq[T] = + var result = newSeq[T](2) + result[0] = i[0].to(T) + result + doAssert newSeq[int](3).converted(float) == @[0.0, 0.0] + + block: # issue #6340 + type A[T] = object + v: T + proc foo(x: int): string = "int" + proc foo(x: typedesc[int]): string = "typedesc[int]" + template fooT(x: int): string = "int" + template fooT(x: typedesc[int]): string = "typedesc[int]" + proc foo[T](x: A[T]): (string, string) = + (foo(T), fooT(T)) + template fooT[T](x: A[T]): (string, string) = + (foo(T), fooT(T)) + var x: A[int] + doAssert foo(x) == fooT(x) + + block: # issue #20033 + template run[T](): T = default(T) + doAssert run[int]() == 0 + +import options, tables, typetraits + +block: # complex cases of above with imports + block: # issue #19576, complex case + type RegistryKey = object + key, val: string + var regKey = @[RegistryKey(key: "abc", val: "def")] + template findFirst[T](s: seq[T], pred: proc(x: T): bool): Option[T] = + var res = none(T) # important line + for x in s: + if pred(x): + res = some(x) + break + res + proc getval(searchKey: string): Option[string] = + let found = regKey.findFirst(proc (rk: RegistryKey): bool = rk.key == searchKey) + if found.isNone: none(string) + else: some(found.get().val) + doAssert getval("strange") == none(string) + doAssert getval("abc") == some("def") + block: # issue #19076 + block: # case 1 + var tested: Table[string,int] + template `[]`[V](t:Table[string,V],key:string):untyped = + $V + doAssert tested["abc"] == "int" + template `{}`[V](t:Table[string,V],key:string):untyped = + ($V, tables.`[]`(t, key)) + doAssert (try: tested{"abc"} except KeyError: ("not there", 123)) == ("not there", 123) + tables.`[]=`(tested, "abc", 456) + doAssert tested["abc"] == "int" + doAssert tested{"abc"} == ("int", 456) + block: # case 2 + type Foo[A,T] = object + t:T + proc init[A,T](f:type Foo,a:typedesc[A],t:T):Foo[A,T] = Foo[A,T](t:t) + template fromOption[A](o:Option[A]):auto = + when o.isSome: + Foo.init(A,35) + else: + Foo.init(A,"hi") + let op = fromOption(some(5)) + block: # issue #7461 + template p[T](): untyped = none(T) + doAssert p[int]() == none(int) + block: # issue #7995 + var res: string + template copyRange[T](dest: seq[T], destOffset: int) = + when supportsCopyMem(T): + res = "A" + else: + res = "B" + var a = @[1, 2, 3] + copyRange(a, 0) + doAssert res == "A" 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/tidentconcatenations.nim b/tests/template/tidentconcatenations.nim new file mode 100644 index 000000000..ddd2e49cc --- /dev/null +++ b/tests/template/tidentconcatenations.nim @@ -0,0 +1,31 @@ +type + Hash*[bits: static[int]] = object + data*: array[bits div 8, uint8] + +{.emit: """ + +void sha_256(void* input, int input_len, void* output, int output_len) {} +void sha_512(void* input, int input_len, void* output, int output_len) {} + +void keccak_256(void* input, int input_len, void* output, int output_len) {} +void keccak_512(void* input, int input_len, void* output, int output_len) {} + +""".} + +template defineKeccak(bits: untyped) = + proc `extKeccak bits`(output: pointer, outSize: csize_t, input: pointer, inputSize: csize_t) {.nodecl, importc: "keccak_" & astToStr(bits).} + +template defineSha(bits: static[int]) = + proc `extSha bits`(output: pointer, outSize: csize_t, input: pointer, inputSize: csize_t) {.nodecl, importc: "sha_" & astToStr(bits).} + +template defineHashProcs(bits) = + defineSha(bits) + defineKeccak(bits) + +defineHashProcs(256) +defineHashProcs(512) + +extSha256(nil, 0, nil, 0) +extSha512(nil, 0, nil, 0) +extKeccak256(nil, 0, nil, 0) +extKeccak512(nil, 0, nil, 0) diff --git a/tests/template/tinnerouterproc.nim b/tests/template/tinnerouterproc.nim new file mode 100644 index 000000000..56e0d02df --- /dev/null +++ b/tests/template/tinnerouterproc.nim @@ -0,0 +1,20 @@ +block: # #20002 + proc bar(x: int): int = 10 + template foo = + proc bar(x: int): int {.gensym.} = x + 2 + doAssert bar(3) == 5 + 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/tmodulealias.nim b/tests/template/tmodulealias.nim index 6681379fb..79b5ec9c6 100644 --- a/tests/template/tmodulealias.nim +++ b/tests/template/tmodulealias.nim @@ -7,7 +7,7 @@ when defined(windows): else: import posix -when defined(Windows): +when defined(windows): template orig: expr = winlean else: 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/tobjectdeclfield.nim b/tests/template/tobjectdeclfield.nim new file mode 100644 index 000000000..afce2cae8 --- /dev/null +++ b/tests/template/tobjectdeclfield.nim @@ -0,0 +1,21 @@ +block: # issue #16005 + var x = 0 + + block: + type Foo = object + x: float # ok + + template main() = + block: + type Foo = object + x: float # Error: cannot use symbol of kind 'var' as a 'field' + + main() + +block: # issue #19552 + template test = + type + test2 = ref object + reset: int + + test() 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 1444667f4..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 @@ -72,7 +73,7 @@ proc concreteProc(x: int) = forStatic i, 0..3: echo i -proc genericProc(x: any) = +proc genericProc(x: auto) = forStatic i, 0..3: echo i @@ -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/tqualifiedident.nim b/tests/template/tqualifiedident.nim new file mode 100644 index 000000000..463b14ee7 --- /dev/null +++ b/tests/template/tqualifiedident.nim @@ -0,0 +1,8 @@ +block: # issue #19865 + template f() = discard default(system.int) + f() + +# issue #21221, same as above +type M = object +template r() = discard default(tqualifiedident.M) +r() 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/template/tredefinition_override.nim b/tests/template/tredefinition_override.nim new file mode 100644 index 000000000..7ae232bba --- /dev/null +++ b/tests/template/tredefinition_override.nim @@ -0,0 +1,33 @@ +{.push warningAsError[ImplicitTemplateRedefinition]: on.} + +doAssert not (compiles do: + template foo(): int = 1 + template foo(): int = 2) +doAssert (compiles do: + template foo(): int = 1 + template foo(): int {.redefine.} = 2) +doAssert not (compiles do: + block: + template foo() = + template bar: string {.gensym.} = "a" + template bar: string {.gensym.} = "b" + foo()) +doAssert (compiles do: + block: + template foo() = + template bar: string {.gensym.} = "a" + template bar: string {.gensym, redefine.} = "b" + foo()) + +block: + template foo(): int = 1 + template foo(): int {.redefine.} = 2 + doAssert foo() == 2 +block: + template foo(): string = + template bar: string {.gensym.} = "a" + template bar: string {.gensym, redefine.} = "b" + bar() + doAssert foo() == "b" + +{.pop.} diff --git a/tests/template/tunderscore1.nim b/tests/template/tunderscore1.nim new file mode 100644 index 000000000..d74e5ba63 --- /dev/null +++ b/tests/template/tunderscore1.nim @@ -0,0 +1,11 @@ +discard """ + errormsg: "the special identifier '_' is ignored in declarations and cannot be used" +""" + +# issue #12094, #13804 + +template foo = + let _ = 1 + echo _ + +foo() diff --git a/tests/template/twrongmapit.nim b/tests/template/twrongmapit.nim index 5b8663cf9..2d53d03f5 100644 --- a/tests/template/twrongmapit.nim +++ b/tests/template/twrongmapit.nim @@ -1,8 +1,6 @@ discard """ - output: "####" + joinable: false """ -# unfortunately our tester doesn't support multiple lines of compiler -# error messages yet... # bug #1562 type Foo* {.pure, final.} = object @@ -29,4 +27,4 @@ import sequtils (var i = @[""];i).applyIt(it) # now works: -echo "##", i[0], "##" +doAssert i[0] == "" diff --git a/tests/template/utemplates.nim b/tests/template/utemplates.nim index 7674ba7c0..d70746578 100644 --- a/tests/template/utemplates.nim +++ b/tests/template/utemplates.nim @@ -22,7 +22,7 @@ block: # templates can be redefined multiple times if not cond: fail(msg) template assertionFailed(body: untyped) {.dirty.} = - template fail(msg: string): typed = + template fail(msg: string): typed {.redefine.} = body assertionFailed: |