diff options
Diffstat (limited to 'tests/template')
91 files changed, 2779 insertions, 312 deletions
diff --git a/tests/template/annotate.nim b/tests/template/annotate.nim index 5f395557b..a7e2f8fdb 100644 --- a/tests/template/annotate.nim +++ b/tests/template/annotate.nim @@ -1,7 +1,7 @@ import macros, parseutils # Generate tags -macro make(names: openarray[expr]): stmt {.immediate.} = +macro make(names: untyped{nkBracket}): untyped = result = newStmtList() for i in 0 .. names.len-1: diff --git a/tests/template/i2416.nim b/tests/template/i2416.nim new file mode 100644 index 000000000..4b53cd0ca --- /dev/null +++ b/tests/template/i2416.nim @@ -0,0 +1 @@ +template i2416*() = echo "i2416" 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/mcan_access_hidden_field.nim b/tests/template/mcan_access_hidden_field.nim index bf3592701..2c0026ec1 100644 --- a/tests/template/mcan_access_hidden_field.nim +++ b/tests/template/mcan_access_hidden_field.nim @@ -5,5 +5,4 @@ type proc createFoo*(a, b: int): Foo = Foo(fooa: a, foob: b) -template geta*(f: Foo): expr = f.fooa - +template geta*(f: Foo): untyped = f.fooa 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/mgensym_generic_cross_module.nim b/tests/template/mgensym_generic_cross_module.nim new file mode 100644 index 000000000..ea88f67e6 --- /dev/null +++ b/tests/template/mgensym_generic_cross_module.nim @@ -0,0 +1,14 @@ + +template makeDomElement(x: untyped, name: string = "") = + const tag {.gensym.} = if name.len == 0: astToStr(x) else: name + + proc x*(p: int|float) = + echo tag, p + + proc x*(p: string|cstring) = + echo tag, p + +#proc wrappedUp[T](x: T) = +# mixin foo, bar +makeDomElement(foo, "foo") +makeDomElement(bar) diff --git a/tests/template/mlt.nim b/tests/template/mlt.nim new file mode 100644 index 000000000..e567cf085 --- /dev/null +++ b/tests/template/mlt.nim @@ -0,0 +1,3 @@ + +type Point* = ref object of RootObj +proc `>`*(p1, p2: Point): bool = false 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/mtempl5.nim b/tests/template/mtempl5.nim index 3c2881764..2cc6f91bc 100644 --- a/tests/template/mtempl5.nim +++ b/tests/template/mtempl5.nim @@ -7,4 +7,18 @@ template templ*(): int = bind gx, gy gx + gy +import json + +const + codeField = "foobar" + messageField = "more" + +template trap*(path: string, body: untyped): untyped = + #bind codeField, messageField + try: + body + except: + let msg = getCurrentExceptionMsg() + #debug "Error occurred within RPC ", path = path, errorMessage = msg + result = %*{codeField: "SERVER_ERROR", messageField: msg} 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.tmpl b/tests/template/sunset.nimf index 465b12a5e..bd57bb8e1 100644 --- a/tests/template/sunset.tmpl +++ 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/t2do.nim b/tests/template/t2do.nim deleted file mode 100644 index ec364c5f3..000000000 --- a/tests/template/t2do.nim +++ /dev/null @@ -1,23 +0,0 @@ -discard """ - output: "8.0" -""" - -# bug #2057 - -proc mpf_get_d(x: int): float = float(x) -proc mpf_cmp_d(a: int; b: float): int = 0 - -template toFloatHelper(result: expr; tooSmall, tooLarge: stmt) {.immediate.} = - result = mpf_get_d(a) - if result == 0.0 and mpf_cmp_d(a,0.0) != 0: - tooSmall - if result == Inf: - tooLarge - -proc toFloat*(a: int): float = - toFloatHelper(result) do: - raise newException(ValueError, "number too small") - do: - raise newException(ValueError, "number too large") - -echo toFloat(8) 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/t_otemplates.nim b/tests/template/t_otemplates.nim index 6c419f72f..b278bea0f 100644 --- a/tests/template/t_otemplates.nim +++ b/tests/template/t_otemplates.nim @@ -126,7 +126,7 @@ iterator parse_compound_statements(value, identifier: string, index: int): strin ## and returns the initialization of each as an empty statement ## i.e. if x == 5 { ... } becomes if x == 5: nil. - template get_next_ident(expected): stmt = + template get_next_ident(expected) = var nextIdent: string discard value.parseWhile(nextIdent, {'$'} + identChars, i) @@ -312,14 +312,14 @@ proc parse_until_symbol(node: NimNode, value: string, index: var int): bool {.co proc parse_template(node: NimNode, value: string) = - ## Parses through entire template, outputing valid + ## Parses through entire template, outputting valid ## Nim code into the input `node` AST. var index = 0 while index < value.len and - parse_until_symbol(node, value, index): nil + parse_until_symbol(node, value, index): discard -macro tmpli*(body: expr): stmt = +macro tmpli*(body: untyped): untyped = result = newStmtList() result.add parseExpr("result = \"\"") @@ -330,7 +330,7 @@ macro tmpli*(body: expr): stmt = parse_template(result, reindent(value)) -macro tmpl*(body: expr): stmt = +macro tmpl*(body: untyped): untyped = result = newStmtList() var value = if body.kind in nnkStrLit..nnkTripleStrLit: body.strVal @@ -340,6 +340,6 @@ macro tmpl*(body: expr): stmt = # Run tests -when isMainModule: +when true: include otests echo "Success" 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/tcan_access_hidden_field.nim b/tests/template/tcan_access_hidden_field.nim deleted file mode 100644 index a6f6490cc..000000000 --- a/tests/template/tcan_access_hidden_field.nim +++ /dev/null @@ -1,9 +0,0 @@ -discard """ - output: 33 -""" - -import mcan_access_hidden_field - -var myfoo = createFoo(33, 44) - -echo myfoo.geta diff --git a/tests/template/tconfusinglocal.nim b/tests/template/tconfusinglocal.nim new file mode 100644 index 000000000..9f641e2bf --- /dev/null +++ b/tests/template/tconfusinglocal.nim @@ -0,0 +1,21 @@ +discard """ +output: "0" +""" + + +# bug #5135 +proc fail*[E](e: E): void = + raise newException(Exception, e) + +# bug #4875 +type Bar = object + mFoo: int + +template foo(a: Bar): int = a.mFoo + +proc main = + let foo = 5 # Rename this to smth else to make it work + var b: Bar + echo b.foo + +main() diff --git a/tests/template/tdefault_nil.nim b/tests/template/tdefault_nil.nim deleted file mode 100644 index 891166306..000000000 --- a/tests/template/tdefault_nil.nim +++ /dev/null @@ -1,14 +0,0 @@ - -# bug #2629 -import sequtils, os - -template glob_rst(basedir: string = nil): expr = - if baseDir.isNil: - to_seq(walk_files("*.rst")) - else: - to_seq(walk_files(basedir/"*.rst")) - -let - rst_files = concat(glob_rst(), glob_rst("docs")) - -when isMainModule: echo rst_files 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/tdefined_overload.nim b/tests/template/tdefined_overload.nim new file mode 100644 index 000000000..bcc83e414 --- /dev/null +++ b/tests/template/tdefined_overload.nim @@ -0,0 +1,46 @@ +discard """ + output: "Valid and not defined" +""" +# test for issue #7997 +# checking for `when not defined` in a template for some compile time symbol +# results in a compilation error of: +# Error: obsolete usage of 'defined', use 'declared' instead +# if the symbol is 'overloaded' by some variable or procedure, because in +# that case the argument of `defined` is of kind `nkSym` instead of `nkIdent` +# (for which was checked in `semexprs.semDefined`). + +block: + # check whether a proc with the same name as the argument to `defined` + # compiles + proc overloaded() = + discard + + template definedCheck(): untyped = + when not defined(overloaded): true + else: false + doAssert definedCheck == true + +block: + # check whether a variable with the same name as the argument to `defined` + # compiles + var overloaded: int + + template definedCheck(): untyped = + when not defined(overloaded): true + else: false + doAssert definedCheck == true + +block: + # check whether a non overloaded when check still works properly + when not defined(validIdentifier): + echo "Valid and not defined" + +block: + # now check that invalid identifiers cause a compilation error + # by using reject template. + template reject(b) = + static: doAssert(not compiles(b)) + + reject: + when defined(123): + echo "Invalid identifier! Will not be echoed" 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 new file mode 100644 index 000000000..58c40941d --- /dev/null +++ b/tests/template/template_issues.nim @@ -0,0 +1,304 @@ +discard """ +output: ''' +@[] +5 +0 +a +hi +Hello, World! +(e: 42) +hey +foo +foo +foo +false +true +''' +""" + + +import macros, json + + +block t2057: + proc mpf_get_d(x: int): float = float(x) + proc mpf_cmp_d(a: int; b: float): int = 0 + + template toFloatHelper(result, tooSmall, tooLarge: untyped) = + result = mpf_get_d(a) + if result == 0.0 and mpf_cmp_d(a,0.0) != 0: + tooSmall + if result == Inf: + tooLarge + + proc toFloat(a: int): float = + toFloatHelper(result) do: + raise newException(ValueError, "number too small") + do: + raise newException(ValueError, "number too large") + + doAssert toFloat(8) == 8.0 + + + +import sequtils, os +block t2629: + template glob_rst(basedir: string = ""): untyped = + if baseDir.len == 0: + to_seq(walk_files("*.rst")) + else: + to_seq(walk_files(basedir/"*.rst")) + + let rst_files = concat(glob_rst(), glob_rst("docs")) + + when true: echo rst_files + + +block t5417: + macro genBody: untyped = + let sbx = genSym(nskLabel, "test") + when true: + result = quote do: + block `sbx`: + break `sbx` + else: + template foo(s1, s2) = + block s1: + break s2 + result = getAst foo(sbx, sbx) + + proc test() = + genBody() + + + +block t909: + template baz() = + proc bar() = + var x = 5 + iterator foo(): int {.closure.} = + echo x + var y = foo + discard y() + + macro test(): untyped = + result = getAst(baz()) + + test() + bar() + + + +block t993: + type PNode = ref object of RootObj + + template litNode(name, ty) = + type name = ref object of PNode + val: ty + litNode PIntNode, int + + template withKey(j: JsonNode; key: string; varname, + body: untyped): typed = + if j.hasKey(key): + let varname{.inject.}= j[key] + block: + body + + var j = parsejson("{\"zzz\":1}") + withkey(j, "foo", x): + echo(x) + + + + +block t1337: + template someIt(a, pred): untyped = + var it {.inject.} = 0 + pred + + proc aProc(n: auto) = + n.someIt(echo(it)) + + aProc(89) + + + +import mlt +block t4564: + type Bar = ref object of RootObj + proc foo(a: Bar): int = 0 + var a: Bar + let b = a.foo() > 0 + + + +block t8052: + type + UintImpl[N: static[int], T: SomeUnsignedInt] = object + raw_data: array[N, T] + + template genLoHi(TypeImpl: untyped): untyped = + template loImpl[N: static[int], T: SomeUnsignedInt](dst: TypeImpl[N div 2, T], src: TypeImpl[N, T]) = + let halfSize = N div 2 + for i in 0 ..< halfSize: + dst.raw_data[i] = src.raw_data[i] + + proc lo[N: static[int], T: SomeUnsignedInt](x: TypeImpl[N,T]): TypeImpl[N div 2, T] {.inline.}= + loImpl(result, x) + + genLoHi(UintImpl) + + var a: UintImpl[4, uint32] + + a.raw_data = [1'u32, 2'u32, 3'u32, 4'u32] + doAssert a.lo.raw_data.len == 2 + doAssert a.lo.raw_data[0] == 1 + doAssert a.lo.raw_data[1] == 2 + + + +block t2585: + type + RenderPass = object + state: ref int + RenderData = object + fb: int + walls: seq[RenderPass] + Mat2 = int + Vector2[T] = T + Pixels=int + + template use(fb: int, st: untyped): untyped = + echo "a ", $fb + st + echo "a ", $fb + + proc render(rdat: var RenderData; passes: var openArray[RenderPass]; proj: Mat2; + indexType = 1) = + for i in 0 ..< len(passes): + echo "blah ", repr(passes[i]) + + proc render2(rdat: var RenderData; screenSz: Vector2[Pixels]; proj: Mat2) = + use rdat.fb: + render(rdat, rdat.walls, proj, 1) + + + +block t4292: + template foo(s: string): string = s + proc variadicProc(v: varargs[string, foo]) = echo v[0] + variadicProc("a") + + + +block t2670: + template testTemplate(b: bool): typed = + when b: + var a = "hi" + else: + var a = 5 + echo a + testTemplate(true) + + + +block t4097: + var i {.compileTime.} = 2 + + template defineId(t: typedesc) = + const id {.genSym.} = i + static: inc(i) + proc idFor(T: typedesc[t]): int {.inline, raises: [].} = id + + defineId(int8) + defineId(int16) + + doAssert idFor(int8) == 2 + doAssert idFor(int16) == 3 + + + +block t5235: + template outer(body: untyped) = + template test(val: string) = + const SomeConst: string = val + echo SomeConst + body + + outer: + test("Hello, World!") + + +# bug #11941 +type X = object + e: int + +proc works(T: type X, v: auto): T = T(e: v) +template fails(T: type X, v: auto): T = T(e: v) + +var + w = X.works(42) + x = X.fails(42) + +echo x + +import mtempl5 + + +proc foo(): auto = + trap "foo": + echo "hey" + +discard foo() + + +# bug #4722 +type + IteratorF*[In] = iterator() : In {.closure.} + +template foof(In: untyped) : untyped = + proc ggg*(arg: IteratorF[In]) = + for i in arg(): + echo "foo" + + +iterator hello() : int {.closure.} = + for i in 1 .. 3: + yield i + +foof(int) +ggg(hello) + + +# bug #2586 +var z = 10'u8 +echo z < 9 # Works +echo z > 9 # Error: type mismatch + + +# bug #5993 +template foo(p: proc) = + var bla = 5 + p(bla) + +foo() do(t: var int): + discard + t = 5 + +proc bar(t: var int) = + t = 5 + +foo(bar) + +block: # bug #12595 + template test() = + let i = 42 + 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 new file mode 100644 index 000000000..da532b010 --- /dev/null +++ b/tests/template/template_pragmas.nim @@ -0,0 +1,9 @@ +proc output_x:string {.compileTime.} = "x" + +template t = + const x = output_x() + let + bar {.exportc:"bar" & x.} = 100 + +static: + doAssert(compiles (t())) diff --git a/tests/template/template_various.nim b/tests/template/template_various.nim new file mode 100644 index 000000000..2088b1739 --- /dev/null +++ b/tests/template/template_various.nim @@ -0,0 +1,406 @@ +discard """ +output: ''' +i2416 +33 +foo55 +foo8.0 +fooaha +bar7 +10 +4true +132 +20 +1 +-1 +4 +11 +26 +57 +-1-1-1 + 4 +4 + 4 + 11 +11 + 4 + 11 + 26 +26 + 4 + 11 + 26 + 57 +57 +-1-1-1 +''' +""" + +import macros + + + + +import i2416 +i2416() + + +import mcan_access_hidden_field +var myfoo = createFoo(33, 44) +echo myfoo.geta + + +import mgensym_generic_cross_module +foo(55) +foo 8.0 +foo "aha" +bar 7 + + + +block generic_templates: + type + SomeObj = object of RootObj + Foo[T, U] = object + x: T + y: U + + template someTemplate[T](): tuple[id: int32, obj: T] = + var result: tuple[id: int32, obj: T] = (0'i32, T()) + result + + let ret = someTemplate[SomeObj]() + + # https://github.com/nim-lang/Nim/issues/7829 + proc inner[T](): int = + discard + + template outer[A](): untyped = + inner[A]() + + template outer[B](x: int): untyped = + inner[B]() + + var i1 = outer[int]() + var i2 = outer[int](i1) + + # https://github.com/nim-lang/Nim/issues/7883 + template t1[T: int|int64](s: string): T = + var t: T + t + + template t1[T: int|int64](x: int, s: string): T = + var t: T + t + + var i3: int = t1[int]("xx") + +from strutils import contains + +block tgetast_typeliar: + proc error(s: string) = quit s + + macro assertOrReturn2(condition: bool; message: string) = + var line = condition.lineInfo() + result = quote do: + block: + if not likely(`condition`): + error("Assertion failed: " & $(`message`) & "\n" & `line`) + return + + macro assertOrReturn(condition: bool) = + var message : NimNode = newLit(condition.repr) + # echo message + result = getAst assertOrReturn2(condition, message) + # 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` + assertOrReturn size > 0 + + + +type + MyFloat = object + val: float +converter to_myfloat(x: float): MyFloat {.inline.} = + MyFloat(val: x) + +block pattern_with_converter: + proc `+`(x1, x2: MyFloat): MyFloat = + MyFloat(val: x1.val + x2.val) + + proc `*`(x1, x2: MyFloat): MyFloat = + MyFloat(val: x1.val * x2.val) + + template optMul{`*`(a, 2.0)}(a: MyFloat): MyFloat = + a + a + + func floatMyFloat(x: MyFloat): MyFloat = + result = x * 2.0 + + func floatDouble(x: float): float = + result = x * 2.0 + + doAssert floatDouble(5) == 10.0 + + + + +block procparshadow: + template something(name: untyped) = + proc name(x: int) = + var x = x # this one should not be rejected by the compiler (#5225) + echo x + + something(what) + what(10) + + # bug #4750 + type + O = object + i: int + OP = ptr O + + template alf(p: pointer): untyped = + cast[OP](p) + + proc t1(al: pointer) = + var o = alf(al) + + proc t2(alf: pointer) = + var x = alf + var o = alf(x) + + + +block symchoicefield: + type Foo = object + len: int + + var f = Foo(len: 40) + + template getLen(f: Foo): int = f.len + + doAssert f.getLen == 40 + # This fails, because `len` gets the nkOpenSymChoice + # treatment inside the template early pass and then + # it can't be recognized as a field anymore + + + +import os, times +include "sunset.nimf" +block ttempl: + const + tabs = [["home", "index"], + ["news", "news"], + ["documentation", "documentation"], + ["download", "download"], + ["FAQ", "question"], + ["links", "links"]] + + + var i = 0 + for item in items(tabs): + var content = $i + var file: File + if open(file, changeFileExt(item[1], "html"), fmWrite): + write(file, sunsetTemplate(current=item[1], ticker="", content=content, + tabs=tabs)) + close(file) + else: + write(stdout, "cannot open file for writing") + inc(i) + + + +block ttempl4: + template `:=`(name, val: untyped) = + var name = val + + ha := 1 * 4 + hu := "ta-da" == "ta-da" + echo ha, hu + + + + +import mtempl5 +block ttempl5: + echo templ() + + #bug #892 + proc parse_to_close(value: string, index: int, open='(', close=')'): int = + discard + + # Call parse_to_close + template get_next_ident = + discard "{something}".parse_to_close(0, open = '{', close = '}') + + get_next_ident() + + #identifier expected, but found '(open|open|open)' + #bug #880 (also example in the manual!) + template typedef(name: untyped, typ: typedesc) = + type + `T name` {.inject.} = typ + `P name` {.inject.} = ref `T name` + + typedef(myint, int) + var x: PMyInt + + + +block templreturntype: + template `=~` (a: int, b: int): bool = false + var foo = 2 =~ 3 + +# bug #7117 +template parse9(body: untyped): untyped = + + template val9(arg: string): int {.inject.} = + var b: bool + if b: 10 + else: 20 + + body + +parse9: + echo val9("1") + + +block gensym1: + template x: untyped = -1 + template t1() = + template x: untyped {.gensym, redefine.} = 1 + echo x() # 1 + template t2() = + template x: untyped {.redefine.} = 1 # defaults to {.inject.} + echo x() # -1 injected x not available during template definition + t1() + t2() + +block gensym2: + let x,y,z = -1 + template `!`(xx,yy: typed): untyped = + template x: untyped {.gensym.} = xx + template y: untyped {.gensym.} = yy + let z = x + x + y + z + var + a = 1 + b = 2 + c = 3 + d = 4 + e = 5 + echo a ! b + echo a ! b ! c + echo a ! b ! c ! d + echo a ! b ! c ! d ! e + echo x,y,z + +block gensym3: + macro liftStmts(body: untyped): auto = + # convert + # template x: untyped {.gensym.} = + # let z = a + a + b + # echo z + # z + # to + # let z = a + a + b + # echo z + # template x: untyped {.gensym.} = + # z + #echo body.repr + body.expectKind nnkStmtList + result = newNimNode nnkStmtList + for s in body: + s.expectKind nnkTemplateDef + var sle = s[6] + while sle.kind == nnkStmtList: + doAssert(sle.len==1) + sle = sle[0] + if sle.kind == nnkStmtListExpr: + let n = sle.len + for i in 0..(n-2): + result.add sle[i] + var td = newNimNode nnkTemplateDef + for i in 0..5: + td.add s[i] + td.add sle[n-1] + result.add td + else: + result.add s + #echo result.repr + let x,y,z = -1 + template `!`(xx,yy: typed): untyped = + liftStmts: + template x: untyped {.gensym.} = xx + template y: untyped {.gensym.} = yy + let z = x + x + y + echo " ", z + z + var + a = 1 + b = 2 + c = 3 + d = 4 + e = 5 + echo a ! b + echo a ! b ! c + 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/texponential_eval.nim b/tests/template/texponential_eval.nim index 32af9e8f7..b4e3faefb 100644 --- a/tests/template/texponential_eval.nim +++ b/tests/template/texponential_eval.nim @@ -1,13 +1,17 @@ # bug #1940 discard """ - nimout: '''=== +nimout: ''' +=== merge (A) with (B) merge (A B) with (C) merge (A B C) with (D) merge (A B C D) with (E) merge (A B C D E) with (F) -===''' +=== +''' + +output: "A B C D E F" """ type SqlStmt = tuple 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/tgensym_instantiationinfo.nim b/tests/template/tgensym_instantiationinfo.nim new file mode 100644 index 000000000..4b997ed6a --- /dev/null +++ b/tests/template/tgensym_instantiationinfo.nim @@ -0,0 +1,24 @@ +discard """ + action: "compile" +""" + +# bug #7937 + +template printError(error: typed) = + # Error: inconsistent typing for reintroduced symbol 'instInfo': previous type was: tuple[filename: string, line: int, column: int]; new type is: (string, int, int) + let instInfo {.gensym.} = instantiationInfo() + echo "Error at ", instInfo.filename, ':', instInfo.line, ": ", error + +# Removing this overload fixes the error +template someTemplate(someBool: bool, body) = + discard + +template someTemplate(body) = + body + +proc main() = + someTemplate: + printError("ERROR 1") + printError("ERROR 2") + +main() 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/tgensymregression.nim b/tests/template/tgensymregression.nim new file mode 100644 index 000000000..2a5dca934 --- /dev/null +++ b/tests/template/tgensymregression.nim @@ -0,0 +1,88 @@ +discard """ + output: '''[0.0, 0.0, 0.0] +[0.0, 0.0, 0.0, 0.0] +5050 +123''' +""" + +template mathPerComponent(op: untyped): untyped = + proc op*[N,T](v,u: array[N,T]): array[N,T] {.inline.} = + for i in 0 ..< len(result): + result[i] = `*`(v[i], u[i]) + +mathPerComponent(`***`) +# bug #5285 +when true: + if true: + var v1: array[3, float64] + var v2: array[3, float64] + echo repr(v1 *** v2) + + +proc foo(): void = + var v1: array[4, float64] + var v2: array[4, float64] + echo repr(v1 *** v2) + +foo() + +# bug #5383 +import sequtils + +proc zipWithIndex[A](ts: seq[A]): seq[(int, A)] = + toSeq(pairs(ts)) + +proc main = + discard zipWithIndex(@["foo", "bar"]) + discard zipWithIndex(@[1, 2]) + discard zipWithIndex(@[true, false]) + +main() + +# bug #5405 + +proc main2() = + let s = toSeq(1..100).foldL(a + b) + echo s + +main2() + +# bug #5467 +import macros + +converter int2string(x: int): string = $x + +template wrap(body: typed): untyped = + body + +macro makeProc() = + # Make a template tree + result = quote do: + proc someProc* = + wrap do: + let x = 123 + # Implicit conversion here + let s: string = x + echo s + +makeProc() + +someProc() + +# bug #12193 +import macros, strutils + +macro gen(T: typedesc): untyped = + let typeSym = getTypeImpl(T)[1] + let param = genSym(nskParam, "s") + let value = nnkBracketExpr.newTree(param, newIntLitNode(0)) + result = newProc( + name = ident"pack", + params = [typeSym, + newIdentDefs(param, nnkBracketExpr.newTree(ident"seq", ident"string"))], + body = newStmtList(newCall(typeSym, newCall(bindSym"parseInt", value))), + procType = nnkTemplateDef) + echo repr result + +gen(int) +let i = pack(@["2"]) diff --git a/tests/template/thygienictempl.nim b/tests/template/thygienictempl.nim index 5e4f534f8..9020c3e28 100644 --- a/tests/template/thygienictempl.nim +++ b/tests/template/thygienictempl.nim @@ -1,8 +1,12 @@ +discard """ +action: compile +""" + var e = "abc" -raise newException(EIO, e & "ha!") +raise newException(IOError, e & "ha!") template t() = echo(foo) @@ -10,9 +14,9 @@ var foo = 12 t() -template test_in(a, b, c: expr): bool {.immediate, dirty.} = +template test_in(a, b, c: untyped): bool {.dirty.} = var result {.gensym.}: bool = false false -when isMainModule: +when true: assert test_in(ret2, "test", str_val) 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/tissue909.nim b/tests/template/tissue909.nim deleted file mode 100644 index 5b57a3558..000000000 --- a/tests/template/tissue909.nim +++ /dev/null @@ -1,16 +0,0 @@ -import macros - -template baz() = - proc bar() = - var x = 5 - iterator foo(): int {.closure.} = - echo x - var y = foo - discard y() - -macro test(): stmt = - result = getAst(baz()) - echo(treeRepr(result)) - -test() -bar() diff --git a/tests/template/tissue993.nim b/tests/template/tissue993.nim deleted file mode 100644 index dae9df683..000000000 --- a/tests/template/tissue993.nim +++ /dev/null @@ -1,21 +0,0 @@ - -type PNode* = ref object of RootObj - -template litNode (name, ty): stmt = - type name* = ref object of PNode - val*: ty -litNode PIntNode, int - -import json - -template withKey*(j: JsonNode; key: string; varname: expr; - body:stmt): stmt {.immediate.} = - if j.hasKey(key): - let varname{.inject.}= j[key] - block: - body - -var j = parsejson("{\"zzz\":1}") -withkey(j, "foo", x): - echo(x) - diff --git a/tests/template/tit.nim b/tests/template/tit.nim deleted file mode 100644 index cf50d2f6f..000000000 --- a/tests/template/tit.nim +++ /dev/null @@ -1,11 +0,0 @@ - -# bug #1337 - -template someIt(a, pred: expr): expr = - var it {.inject.} = 0 - pred - -proc aProc(n: auto) = - n.someIt(echo(it)) - -aProc(89) diff --git a/tests/template/tmethodcall.nim b/tests/template/tmethodcall.nim new file mode 100644 index 000000000..d209443c8 --- /dev/null +++ b/tests/template/tmethodcall.nim @@ -0,0 +1,24 @@ +# bug #5909 +type + Vec2[T] = tuple + x,y: T + Vec2f = Vec2[float32] + +proc vec2f(x,y: float): Vec2f = + result.x = x + result.y = y + +proc `-`[T](a,b: Vec2[T]): Vec2[T] = + result.x = a.x - b.x + result.y = a.y - b.y + +proc foo[T](a: Vec2[T]): Vec2[T] = + result = a + +block: + # this being called foo is a problem when calling .foo() + var foo = true + + let a = vec2f(1.0,0.0) + let b = vec2f(3.0,1.0) + let c = (a - b).foo() # breaks diff --git a/tests/template/tmixin_in_proc.nim b/tests/template/tmixin_in_proc.nim new file mode 100644 index 000000000..fede9290b --- /dev/null +++ b/tests/template/tmixin_in_proc.nim @@ -0,0 +1,22 @@ +discard """ + output: '''monkey''' +""" +# bug #5478 +template creature*(name: untyped) = + type + name*[T] = object + color: T + + proc `init name`*[T](c: T): name[T] = + mixin transform + transform() + +creature(Lion) + +type Monkey* = object +proc transform*() = + echo "monkey" + +var + m: Monkey + y = initLion(m) #this one failed to compile 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/tmore_regressions.nim b/tests/template/tmore_regressions.nim new file mode 100644 index 000000000..8b4b5fa4c --- /dev/null +++ b/tests/template/tmore_regressions.nim @@ -0,0 +1,44 @@ +discard """ +output: '''0 + +0.0''' +""" + +# bug #11494 +import macros + +macro staticForEach(arr: untyped, body: untyped): untyped = + result = newNimNode(nnkStmtList) + + arr.expectKind(nnkBracket) + for n in arr: + let b = copyNimTree(body) + result.add quote do: + block: + type it {.inject.} = `n` + `b` + +template forEveryMatchingEntity*() = + staticForEach([int, string, float]): + var a: it + echo a + +forEveryMatchingEntity() + + +# bug #11483 +proc main = + template first(body) = + template second: var int = + var o: int + var i = addr(o) + i[] + + body + + first: + second = 5 + second = 6 + +main() + 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 6c4413866..b559c2d9e 100644 --- a/tests/template/tparams_gensymed.nim +++ b/tests/template/tparams_gensymed.nim @@ -1,12 +1,32 @@ - +discard """ +output: ''' +0 +1 +2 +3 +0 +1 +2 +3 +wth +3 +2 +1 +0 +(total: 6) +S1 +5 +abc +''' +""" # bug #1915 import macros # Test that parameters are properly gensym'ed finally: -template genNodeKind(kind, name: expr): stmt = - proc name*(children: varargs[PNimrodNode]): PNimrodNode {.compiletime.}= +template genNodeKind(kind, name: untyped) = + proc name*(children: varargs[NimNode]): NimNode {.compiletime.}= result = newNimNode(kind) for c in children: result.add(c) @@ -22,7 +42,7 @@ type Something = object proc testA(x: Something) = discard -template def(name: expr) {.immediate.} = +template def(name: untyped) = proc testB[T](reallyUniqueName: T) = `test name`(reallyUniqueName) def A @@ -35,8 +55,7 @@ testB(x) # Test that templates in generics still work (regression to fix the # regression...) -template forStatic(index: expr, slice: Slice[int], predicate: stmt): - stmt {.immediate.} = +template forStatic(index, slice, predicate: untyped) = const a = slice.a const b = slice.b when a <= b: @@ -44,7 +63,7 @@ template forStatic(index: expr, slice: Slice[int], predicate: stmt): block: const index = i predicate - template iterateStartingFrom(i: int): stmt = + template iterateStartingFrom(i: int) = when i <= b: iteration i iterateStartingFrom i + 1 @@ -54,9 +73,333 @@ proc concreteProc(x: int) = forStatic i, 0..3: echo i -proc genericProc(x: any) = +proc genericProc(x: auto) = forStatic i, 0..3: echo i concreteProc(7) # This works genericProc(7) # This doesn't compile + +import tables + +# bug #9476 +proc getTypeInfo*(T: typedesc): pointer = + var dummy: T + getTypeInfo(dummy) + + +macro implementUnary(op: untyped): untyped = + result = newStmtList() + + template defineTable(tableSymbol) = + var tableSymbol = initTable[pointer, pointer]() + let tableSymbol = genSym(nskVar, "registeredProcs") + result.add(getAst(defineTable(tableSymbol))) + + template defineRegisterInstantiation(tableSym, regTemplSym, instSym, op) = + template regTemplSym*(T: typedesc) = + let ti = getTypeInfo(T) + + proc instSym(xOrig: int): int {.gensym, cdecl.} = + let x {.inject.} = xOrig + op + + tableSym[ti] = cast[pointer](instSym) + + let regTemplSymbol = ident("registerInstantiation") + let instSymbol = ident("instantiation") + result.add(getAst(defineRegisterInstantiation( + tableSymbol, regTemplSymbol, instSymbol, op + ))) + + echo result.repr + + +implementUnary(): x*x + +registerInstantiation(int) +registerInstantiation(float) + +# bug #10192 +template nest(body) {.dirty.} = + template p1(b1: untyped) {.dirty, used.} = + template implp1: untyped {.dirty.} = b1 + template p2(b2: untyped) {.dirty, used.} = + template implp2: untyped {.dirty.} = b2 + + body + implp1 + implp2 + +template test() = + nest: + p1: + var foo = "bar" + p2: + doAssert(foo.len == 3) + +test() + +# regression found in PMunch's parser generator + +proc namedcall(arg: string) = + discard + +macro m(): untyped = + result = quote do: + (proc (arg: string) = + namedcall(arg = arg) + echo arg) + +let meh = m() +meh("wth") + + +macro foo(body: untyped): untyped = + result = body + +template baz(): untyped = + foo: + proc bar2(b: int): int = + echo b + if b > 0: b + bar2(b = b - 1) + else: 0 + echo (total: bar2(3)) + +baz() + +# bug #12121 +macro state_machine_enum(states: varargs[untyped]) = + result = nnkTypeSection.newTree( + nnkTypeDef.newTree( + nnkPragmaExpr.newTree(ident("State"), nnkPragma.newTree(ident("pure"))), + newEmptyNode(), + nnkEnumTy.newTree(newEmptyNode()) + ) + ) + + for s in states: + expectKind(s, nnkIdent) + result[0][2].add s + +template mystate_machine(body: untyped) = + state_machine_enum(S1, S2, S3) + var state_stack: seq[State] + template state_current(): State {.inject, used.} = + state_stack[^1] + template state_push(state_name) {.inject, used.} = + state_stack.add State.state_name + template state_pop(n = 1) {.inject, used.} = + state_stack.setLen(state_stack.len - n) + body + +mystate_machine: + state_push(S1) + echo state_current() + state_pop() + +# bug #15075 +block: #Doesn't work + template genGenTempl: untyped = + proc loop(locals: int) + proc loop(locals: int) = discard + genGenTempl() + let pool = loop + +block: #Doesn't work + macro genGenMacro: untyped = + quote do: + proc loop(locals: int) + proc loop(locals: int) = discard + genGenMacro() + let pool = loop + +block: #This works + proc loop(locals: int) + proc loop(locals: int) = discard + let pool = loop + +#Now somewhat recursive: +type Cont = ref object of RootObj + fn*: proc(c: Cont): Cont {.nimcall.} + +block: #Doesn't work + template genGenTempl(): untyped = + proc loop(locals: Cont): Cont + proc loop(locals: Cont): Cont = + return Cont(fn: loop) + proc doServer(): Cont = + return Cont(fn: loop) + genGenTempl() + discard doServer() + +block: #Doesn't work + macro genGenMacro(): untyped = + quote: + proc loop(locals: Cont): Cont + proc loop(locals: Cont): Cont = + return Cont(fn: loop) + proc doServer(): Cont = + return Cont(fn: loop) + genGenMacro() + discard doServer() + +block: #This works + proc loop(locals: Cont): Cont + proc loop(locals: Cont): Cont = + return Cont(fn: loop) + proc doServer(): Cont = + return Cont(fn: loop) + discard doServer() + +#And fully recursive: +block: #Doesn't work + template genGenTempl: untyped = + proc loop(locals: int) + proc loop(locals: int) = loop(locals) + genGenTempl() + let pool = loop + +block: #Doesn't work + macro genGenMacro: untyped = + quote do: + proc loop(locals: int) + proc loop(locals: int) = loop(locals) + genGenMacro() + let pool = loop + +block: #This works + proc loop(locals: int) + proc loop(locals: int) = loop(locals) + let pool = loop + +block: + template genAndCallLoop: untyped = + proc loop() {.gensym.} + proc loop() {.gensym.} = + discard + loop() + genAndCallLoop + +block: #Fully recursive and gensymmed: + template genGenTempl: untyped = + proc loop(locals: int) {.gensym.} + proc loop(locals: int) {.gensym.} = loop(locals) + let pool = loop + genGenTempl() + +block: #Make sure gensymmed symbol doesn't overwrite the forward decl + proc loop() + proc loop() = discard + template genAndCallLoop: untyped = + proc loop() {.gensym.} = + discard + loop() + genAndCallLoop() + +template genLoopDecl: untyped = + proc loop() +template genLoopDef: untyped = + proc loop() = discard +block: + genLoopDecl + genLoopDef + loop() +block: + proc loop() + genLoopDef + loop() +block: + genLoopDecl + proc loop() = discard + loop() + +block: #Gensymmed sym sharing forward decl + macro genGenMacro: untyped = + let sym = genSym(nskProc, "loop") + nnkStmtList.newTree( + newProc(sym, body = newEmptyNode()), + newCall(sym), + newProc(sym, body = newStmtList()), + ) + genGenMacro + +# inject pragma on params + +template test(procname, body: untyped): untyped = + proc procname(data {.inject.}: var int = 0) = + body + +test(hello): + echo data + data = 3 + +var data = 5 + +hello(data) + +# bug #5691 + +template bar(x: typed) = discard +macro barry(x: typed) = discard + +var a = 0 + +bar: + var a = 10 + +barry: + var a = 20 + +bar: + var b = 10 + +barry: + var b = 20 + +var b = 30 + +# template bar(x: static int) = discard +#You may think that this should work: +# bar((var c = 1; echo "hey"; c)) +# echo c +#But it must not! Since this would be incorrect: +# bar((var b = 3; const c = 1; echo "hey"; c)) +# echo b # <- b wouldn't exist + +discard not (let xx = 1; true) +discard xx + +template barrel(a: typed): untyped = a + +barrel: + var aa* = 1 + var bb = 3 + export bb + +# Test declaredInScope within params +template test1: untyped = + when not declaredInScope(thing): + var thing {.inject.}: int + +proc chunkedReadLoop = + test1 + test1 + +template test2: untyped = + when not not not declaredInScope(thing): + var thing {.inject.}: int + +proc chunkedReadLoop2 = + test2 + 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/tparamscope.nim b/tests/template/tparamscope.nim new file mode 100644 index 000000000..177c682cf --- /dev/null +++ b/tests/template/tparamscope.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "undeclared identifier: 'a'" + line: 10 +""" + + +template secondArg(a, b: typed): untyped = + b + +echo secondArg((var a = 1; 1), a) diff --git a/tests/template/tprefer_immediate.nim b/tests/template/tprefer_immediate.nim deleted file mode 100644 index 578f447b0..000000000 --- a/tests/template/tprefer_immediate.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ - output: '''immediate''' -""" - -# Test that immediate templates are preferred over non-immediate templates - -template foo(a, b: expr) = echo "foo expr" - -template foo(a, b: int) = echo "foo int" -template foo(a, b: float) = echo "foo float" -template foo(a, b: string) = echo "foo string" -template foo(a, b: expr) {.immediate.} = echo "immediate" -template foo(a, b: bool) = echo "foo bool" -template foo(a, b: char) = echo "foo char" - -foo(undeclaredIdentifier, undeclaredIdentifier2) - 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.nim b/tests/template/tredefinition.nim new file mode 100644 index 000000000..8efc5ae2f --- /dev/null +++ b/tests/template/tredefinition.nim @@ -0,0 +1,13 @@ +discard """ + errormsg: "redefinition of 'a`gensym" + line: 9 +""" +# bug #10180 +proc f() = + template t() = + var a = 1 + var a = 2 + echo a + t() + +f() 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/tscope.nim b/tests/template/tscope.nim index 2d5841af3..1eeebbdd4 100644 --- a/tests/template/tscope.nim +++ b/tests/template/tscope.nim @@ -3,7 +3,7 @@ discard """ """ var x = 1 -template quantity(): stmt {.immediate.} = +template quantity() = # Causes internal error in compiler/sem.nim proc unit*(x = 1.0): float = 12 # Throws the correct error: redefinition of 'x' diff --git a/tests/template/tshadow.nim b/tests/template/tshadow.nim new file mode 100644 index 000000000..a4de71592 --- /dev/null +++ b/tests/template/tshadow.nim @@ -0,0 +1,29 @@ +discard """ + output: '''fish +fish''' +""" + +import macros + +block: + template init(initHook: proc(s: string)) = + proc dostuff = + var s = "fish" + initHook(s) + dostuff() + + init do(s: string): + echo s + +block: + macro init(initHook: proc(s: string)) = + result = newStmtList( + newProc(name = ident("dostuff"), body = newStmtList( + newVarStmt(ident("s"), newStrLitNode("fish")), + newCall(initHook, ident("s")) + )), + newCall("dostuff") + ) + + init proc(s: string) = + echo s diff --git a/tests/template/tsighash_regression.nim b/tests/template/tsighash_regression.nim new file mode 100644 index 000000000..f3a6b4833 --- /dev/null +++ b/tests/template/tsighash_regression.nim @@ -0,0 +1,8 @@ +discard """ +exitcode: 1 +outputsub: "0" +""" + +import tconfusinglocal + +fail "foo" diff --git a/tests/template/tstmt_semchecked_twice.nim b/tests/template/tstmt_semchecked_twice.nim deleted file mode 100644 index 05c16c3c9..000000000 --- a/tests/template/tstmt_semchecked_twice.nim +++ /dev/null @@ -1,30 +0,0 @@ - -# bug #2585 - -type - RenderPass = object - state: ref int - - RenderData* = object - fb: int - walls: seq[RenderPass] - - Mat2 = int - Vector2[T] = T - Pixels=int - -template use*(fb: int, st: stmt) : stmt = - echo "a ", $fb - st - echo "a ", $fb - -proc render(rdat: var RenderData; passes: var openarray[RenderPass]; proj: Mat2; - indexType = 1) = - for i in 0 .. <len(passes): - echo "blah ", repr(passes[i]) - - - -proc render2*(rdat: var RenderData; screenSz: Vector2[Pixels]; proj: Mat2) = - use rdat.fb: - render(rdat, rdat.walls, proj, 1) diff --git a/tests/template/tsymchoicefield.nim b/tests/template/tsymchoicefield.nim deleted file mode 100644 index ab05500bf..000000000 --- a/tests/template/tsymchoicefield.nim +++ /dev/null @@ -1,12 +0,0 @@ -type Foo = object - len: int - -var f = Foo(len: 40) - -template getLen(f: Foo): expr = f.len - -echo f.getLen -# This fails, because `len` gets the nkOpenSymChoice -# treatment inside the template early pass and then -# it can't be recognized as a field anymore - diff --git a/tests/template/ttempl.nim b/tests/template/ttempl.nim deleted file mode 100644 index 5f1341990..000000000 --- a/tests/template/ttempl.nim +++ /dev/null @@ -1,27 +0,0 @@ -# Test the new template file mechanism - -import - os, times - -include "sunset.tmpl" - -const - tabs = [["home", "index"], - ["news", "news"], - ["documentation", "documentation"], - ["download", "download"], - ["FAQ", "question"], - ["links", "links"]] - - -var i = 0 -for item in items(tabs): - var content = $i - var file: TFile - if open(file, changeFileExt(item[1], "html"), fmWrite): - write(file, sunsetTemplate(current=item[1], ticker="", content=content, - tabs=tabs)) - close(file) - else: - write(stdout, "cannot open file for writing") - inc(i) diff --git a/tests/template/ttempl2.nim b/tests/template/ttempl2.nim index aaa2f1344..e84e0630b 100644 --- a/tests/template/ttempl2.nim +++ b/tests/template/ttempl2.nim @@ -1,12 +1,12 @@ discard """ + errormsg: "undeclared identifier: \'b\'" file: "ttempl2.nim" line: 18 - errormsg: "undeclared identifier: \'b\'" """ -template declareInScope(x: untyped, t: typeDesc): untyped {.immediate.} = +template declareInScope(x: untyped, t: typeDesc): untyped = var x: t -template declareInNewScope(x: untyped, t: typeDesc): untyped {.immediate.} = +template declareInNewScope(x: untyped, t: typeDesc): untyped = # open a new scope: block: var x: t @@ -16,4 +16,3 @@ a = 42 # works, `a` is known here declareInNewScope(b, int) b = 42 #ERROR_MSG undeclared identifier: 'b' - diff --git a/tests/template/ttempl3.nim b/tests/template/ttempl3.nim index 56daf9fe6..17421cd87 100644 --- a/tests/template/ttempl3.nim +++ b/tests/template/ttempl3.nim @@ -1,9 +1,13 @@ +discard """ +action: compile +""" -template withOpenFile(f: expr, filename: string, mode: TFileMode, - actions: stmt): stmt {.immediate.} = + +template withOpenFile(f: untyped, filename: string, mode: FileMode, + actions: untyped): untyped = block: # test that 'f' is implicitly 'injecting': - var f: TFile + var f: File if open(f, filename, mode): try: actions @@ -20,20 +24,20 @@ var myVar: array[0..1, int] # Test zero argument template: -template ha: expr = myVar[0] +template ha: untyped = myVar[0] ha = 1 echo(ha) # Test identifier generation: -template prefix(name: expr): expr {.immediate.} = `"hu" name` +template prefix(name): untyped = `"hu" name` var `hu "XYZ"` = "yay" echo prefix(XYZ) -template typedef(name: expr, typ: typeDesc) {.immediate, dirty.} = +template typedef(name: untyped, typ: typeDesc) {.dirty.} = type `T name`* = typ `P name`* = ref `T name` @@ -51,8 +55,29 @@ type proc initFoo(arg: int): Foo = result.arg = arg -template create(typ: typeDesc, arg: expr): expr = `init typ`(arg) +template create(typ: typeDesc, arg: untyped): untyped = `init typ`(arg) var ff = Foo.create(12) echo ff.arg + + +import macros + +# bug #11494 +macro staticForEach(arr: untyped, body: untyped): untyped = + result = newNimNode(nnkStmtList) + arr.expectKind(nnkBracket) + for n in arr: + let b = copyNimTree(body) + result.add quote do: + block: + type it {.inject.} = `n` + `b` + +template forEveryMatchingEntity*() = + staticForEach([int, string, float]): + var a {.inject.}: it + echo a + +forEveryMatchingEntity() diff --git a/tests/template/ttempl4.nim b/tests/template/ttempl4.nim deleted file mode 100644 index 26c82e471..000000000 --- a/tests/template/ttempl4.nim +++ /dev/null @@ -1,8 +0,0 @@ - -template `:=`(name, val: expr): stmt {.immediate.} = - var name = val - -ha := 1 * 4 -hu := "ta-da" == "ta-da" -echo ha, hu - diff --git a/tests/template/ttempl5.nim b/tests/template/ttempl5.nim deleted file mode 100644 index a020a8e2c..000000000 --- a/tests/template/ttempl5.nim +++ /dev/null @@ -1,29 +0,0 @@ - -import mtempl5 - -echo templ() - -#bug #892 - -proc parse_to_close(value: string, index: int, open='(', close=')'): int = - discard - -# Call parse_to_close -template get_next_ident: stmt = - discard "{something}".parse_to_close(0, open = '{', close = '}') - -get_next_ident() - - -#identifier expected, but found '(open|open|open)' - -#bug #880 (also example in the manual!) - -template typedef(name: expr, typ: typedesc) {.immediate.} = - type - `T name`* {.inject.} = typ - `P name`* {.inject.} = ref `T name` - -typedef(myint, int) -var x: PMyInt - diff --git a/tests/template/ttemplreturntype.nim b/tests/template/ttemplreturntype.nim deleted file mode 100644 index 642fa1b72..000000000 --- a/tests/template/ttemplreturntype.nim +++ /dev/null @@ -1,4 +0,0 @@ - -template `=~` (a: int, b: int): bool = false -var foo = 2 =~ 3 - 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/twhen_gensym.nim b/tests/template/twhen_gensym.nim deleted file mode 100644 index d84ee6f03..000000000 --- a/tests/template/twhen_gensym.nim +++ /dev/null @@ -1,13 +0,0 @@ -discard """ - output: "hi" -""" - -# bug #2670 -template testTemplate(b: bool): stmt = - when b: - var a = "hi" - else: - var a = 5 - echo a - -testTemplate(true) diff --git a/tests/template/twhenintemplates.nim b/tests/template/twhenintemplates.nim new file mode 100644 index 000000000..6fded856d --- /dev/null +++ b/tests/template/twhenintemplates.nim @@ -0,0 +1,11 @@ +# bug #3670 + +template someTempl(someConst: bool) = + when someConst: + var a : int + if true: + when not someConst: + var a : int + a = 5 + +someTempl(true) diff --git a/tests/template/twrong_getast.nim b/tests/template/twrong_getast.nim new file mode 100644 index 000000000..1d158f7a5 --- /dev/null +++ b/tests/template/twrong_getast.nim @@ -0,0 +1,19 @@ +discard """ + errormsg: "expected a template that takes 3 arguments" + line: 16 +""" + +import macros + +template grainBlock(proxyTypeName: untyped, proxyProcs: untyped): typed = + discard + +var + proxyTypeName: string + proxyProcs: string + +macro foo(): untyped = + let x = getAst grainBlock(proxyTypeName, proxyProcs, proxyTypeName) + +foo() + diff --git a/tests/template/twrongmapit.nim b/tests/template/twrongmapit.nim index df695fcd6..2d53d03f5 100644 --- a/tests/template/twrongmapit.nim +++ b/tests/template/twrongmapit.nim @@ -1,24 +1,22 @@ discard """ - output: "####" + joinable: false """ -# unfortunately our tester doesn't support multiple lines of compiler -# error messages yet... # bug #1562 type Foo* {.pure, final.} = object elt: float -template defineOpAssign(T: expr, op: expr) {.immediate.} = - proc op*(v: var T, w: T) {.inline.} = +template defineOpAssign(T, op: untyped) = + proc `op`*(v: var T, w: T) {.inline.} = for i in 0..1: - op(v.elt, w.elt) + `op`(v.elt, w.elt) const ATTEMPT = 0 when ATTEMPT == 0: # FAILS: defining `/=` with template calling template # ERROR about sem.nim line 144 - template defineOpAssigns(T: expr) {.immediate.} = + template defineOpAssigns(T: untyped) = mixin `/=` defineOpAssign(T, `/=`) @@ -29,4 +27,4 @@ import sequtils (var i = @[""];i).applyIt(it) # now works: -echo "##", i[0], "##" +doAssert i[0] == "" diff --git a/tests/template/twrongopensymchoice.nim b/tests/template/twrongopensymchoice.nim index 360c92037..7a2bb48d3 100644 --- a/tests/template/twrongopensymchoice.nim +++ b/tests/template/twrongopensymchoice.nim @@ -20,5 +20,5 @@ proc main = var f = Foo.new() echo f.b -when isMainModule: +when true: main() diff --git a/tests/template/twrongsymkind.nim b/tests/template/twrongsymkind.nim index be3d8c652..5fa618914 100644 --- a/tests/template/twrongsymkind.nim +++ b/tests/template/twrongsymkind.nim @@ -9,7 +9,7 @@ type MyData = object x: int -template newDataWindow(data: ref MyData): stmt = +template newDataWindow(data: ref MyData): untyped = proc testProc(data: ref MyData) = echo "Hello, ", data.x testProc(data) diff --git a/tests/template/typedescids.nim b/tests/template/typedescids.nim deleted file mode 100644 index ebed49b17..000000000 --- a/tests/template/typedescids.nim +++ /dev/null @@ -1,17 +0,0 @@ -discard """ - output: '''2 3''' -""" - -# bug #4097 - -var i {.compileTime.} = 2 - -template defineId*(t: typedesc): stmt = - const id {.genSym.} = i - static: inc(i) - proc idFor*(T: typedesc[t]): int {.inline, raises: [].} = id - -defineId(int8) -defineId(int16) - -echo idFor(int8), " ", idFor(int16) diff --git a/tests/template/utemplates.nim b/tests/template/utemplates.nim index 8b9ae5d26..d70746578 100644 --- a/tests/template/utemplates.nim +++ b/tests/template/utemplates.nim @@ -1,32 +1,36 @@ import unittest -template t(a: int): expr = "int" -template t(a: string): expr = "string" +template t(a: int): string = "int" +template t(a: string): string = "string" -test "templates can be overloaded": +block: # templates can be overloaded check t(10) == "int" check t("test") == "string" -test "previous definitions can be further overloaded or hidden in local scopes": - template t(a: bool): expr = "bool" +block: # previous definitions can be further overloaded or hidden in local scopes + template t(a: bool): string = "bool" check t(true) == "bool" check t(10) == "int" - template t(a: int): expr = "inner int" + template t(a: int): string = "inner int" check t(10) == "inner int" check t("test") == "string" -test "templates can be redefined multiple times": - template customAssert(cond: bool, msg: string): stmt {.immediate, dirty.} = +block: # templates can be redefined multiple times + template customAssert(cond: bool, msg: string): typed {.dirty.} = if not cond: fail(msg) - template assertion_failed(body: stmt) {.immediate, dirty.} = - template fail(msg: string): stmt = body + template assertionFailed(body: untyped) {.dirty.} = + template fail(msg: string): typed {.redefine.} = + body + + assertionFailed: + check(msg == "first fail path") - assertion_failed: check msg == "first fail path" customAssert false, "first fail path" - assertion_failed: check msg == "second fail path" - customAssert false, "second fail path" + assertionFailed: + check(msg == "second fail path") + customAssert false, "second fail path" |