diff options
Diffstat (limited to 'tests/pragmas')
42 files changed, 1519 insertions, 0 deletions
diff --git a/tests/pragmas/cfunction.c b/tests/pragmas/cfunction.c new file mode 100644 index 000000000..bf49d6a29 --- /dev/null +++ b/tests/pragmas/cfunction.c @@ -0,0 +1,4 @@ + +int cfunction(void) { + return NUMBER_HERE; +} diff --git a/tests/pragmas/custom_pragma.nim b/tests/pragmas/custom_pragma.nim new file mode 100644 index 000000000..d2fc969d0 --- /dev/null +++ b/tests/pragmas/custom_pragma.nim @@ -0,0 +1,5 @@ +# imported by tcustom_pragmas to test scoping + +template serializationKey*(s: string) {.pragma.} +template defaultValue*(V: typed) {.pragma.} +template alternativeKey*(s: string = "", V: typed) {.pragma.} diff --git a/tests/pragmas/foobar.nim b/tests/pragmas/foobar.nim new file mode 100644 index 000000000..46032e187 --- /dev/null +++ b/tests/pragmas/foobar.nim @@ -0,0 +1,3 @@ +import macros +macro async*(body: untyped): untyped = + return newStmtList() diff --git a/tests/pragmas/monoff1.nim b/tests/pragmas/monoff1.nim new file mode 100644 index 000000000..85d6c57b3 --- /dev/null +++ b/tests/pragmas/monoff1.nim @@ -0,0 +1 @@ +proc on*() = discard diff --git a/tests/pragmas/mpushexperimental.nim b/tests/pragmas/mpushexperimental.nim new file mode 100644 index 000000000..569861c1d --- /dev/null +++ b/tests/pragmas/mpushexperimental.nim @@ -0,0 +1,30 @@ + +import macros + +macro enumerate(x: ForLoopStmt): untyped = + expectKind x, nnkForStmt + # we strip off the first for loop variable and use + # it as an integer counter: + result = newStmtList() + result.add newVarStmt(x[0], newLit(0)) + var body = x[^1] + if body.kind != nnkStmtList: + body = newTree(nnkStmtList, body) + body.add newCall(bindSym"inc", x[0]) + var newFor = newTree(nnkForStmt) + for i in 1..x.len-3: + newFor.add x[i] + # transform enumerate(X) to 'X' + newFor.add x[^2][1] + newFor.add body + result.add newFor + +proc main*[T](x: T) = + {.push experimental: "forLoopMacros".} + + for a, b in enumerate(items([1, 2, 3])): + echo a, " ", b + + for a2, b2 in enumerate([1, 2, 3, 5]): + echo a2, " ", b2 + {.pop.} diff --git a/tests/pragmas/mqualifiedmacro.nim b/tests/pragmas/mqualifiedmacro.nim new file mode 100644 index 000000000..908973206 --- /dev/null +++ b/tests/pragmas/mqualifiedmacro.nim @@ -0,0 +1,10 @@ +template t*(x:untyped): untyped = + echo "template t" + +import macros +macro m*(name: static string, x: untyped): untyped = + let newName = ident(name) + result = quote do: + type `newName` = object + if result.kind == nnkStmtList: + result = result[^1] diff --git a/tests/pragmas/t12558.nim b/tests/pragmas/t12558.nim new file mode 100644 index 000000000..14fc74cee --- /dev/null +++ b/tests/pragmas/t12558.nim @@ -0,0 +1,15 @@ +discard """ + nimout: '''@["1", "2", "3"]''' +""" + +import sequtils + +{.push compile_time.} + +proc foo = + echo map_it([1, 2, 3], $it) + +{.pop.} + +static: + foo() diff --git a/tests/pragmas/t12640.nim b/tests/pragmas/t12640.nim new file mode 100644 index 000000000..c85185699 --- /dev/null +++ b/tests/pragmas/t12640.nim @@ -0,0 +1,26 @@ +discard """ + matrix: "--mm:refc" + nimout: '''1 +2 +3 +[1, 2, 3]''' + + output: '''1 +2 +3 +[1, 2, 3]''' +""" + +# todo fixme it doesn't work with ORC +proc doIt(a: openArray[int]) = + echo a + +proc foo() = + var bug {.global, compiletime.}: seq[int] + bug = @[1, 2 ,3] + for i in 0 .. high(bug): echo bug[i] + doIt(bug) + +static: + foo() +foo() diff --git a/tests/pragmas/t13306.nim b/tests/pragmas/t13306.nim new file mode 100644 index 000000000..36713dd04 --- /dev/null +++ b/tests/pragmas/t13306.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "'testEpo' can have side effects" + line: 8 +""" + +import times + +func testEpo(x: float): float = epochTime() + x + +echo testEpo(1.0) diff --git a/tests/pragmas/t22713.nim b/tests/pragmas/t22713.nim new file mode 100644 index 000000000..3d3384632 --- /dev/null +++ b/tests/pragmas/t22713.nim @@ -0,0 +1,12 @@ +import std/macros + + +template myPragma(x: int) {.pragma.} + +type + A = object + x: int64 + + B {.myPragma(sizeof(A)).} = object + +doAssert B.getCustomPragmaVal(myPragma) == 8 \ No newline at end of file diff --git a/tests/pragmas/t4384.nim b/tests/pragmas/t4384.nim new file mode 100644 index 000000000..e6b193f79 --- /dev/null +++ b/tests/pragmas/t4384.nim @@ -0,0 +1,3 @@ +macro testMacro(body: untyped): untyped = discard +macro testMacro(s: string, body: untyped): untyped = discard +proc foo() {.testMacro: "foo".} = discard diff --git a/tests/pragmas/t5149.nim b/tests/pragmas/t5149.nim new file mode 100644 index 000000000..2d242a8d5 --- /dev/null +++ b/tests/pragmas/t5149.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "{.exportc.} not allowed for type aliases" + line: 9 +""" + +type + X* = object + a: int + Y* {.exportc.} = X + +proc impl*(x: X) = + echo "it works" diff --git a/tests/pragmas/t6448.nim b/tests/pragmas/t6448.nim new file mode 100644 index 000000000..6efb56e08 --- /dev/null +++ b/tests/pragmas/t6448.nim @@ -0,0 +1,17 @@ +discard """ + errormsg: '''ambiguous call''' + line: 10 + disabled: "32bit" +""" + +import foobar +import asyncdispatch, macros + +proc bar() {.async.} = + echo 42 + +proc foo() {.async.} = + await bar() + +asyncCheck foo() +runForever() diff --git a/tests/pragmas/t8741.nim b/tests/pragmas/t8741.nim new file mode 100644 index 000000000..bf97b0e29 --- /dev/null +++ b/tests/pragmas/t8741.nim @@ -0,0 +1,29 @@ +discard """ + cmd: "nim check --hint:processing:off $file" + errormsg: "3 is not two" + nimout: '''t8741.nim(13, 9) Error: invalid pragma: foobar +t8741.nim(29, 15) template/generic instantiation of `onlyTwo` from here +t8741.nim(25, 12) Error: 3 is not two +''' +""" + +for a {.gensym, inject.} in @[1,2,3]: + discard + +for a {.foobar.} in @[1,2,3]: + discard + +type Foo[N: static[int]] = distinct int + +proc isTwo(n: int): bool = + n == 2 + +proc onlyTwo[N: static[int]](a: Foo[N]): int = + when isTwo(N): + int(a) + else: + {.error: $(N) & " is not two".} + +when isMainModule: + let foo: Foo[3] = Foo[3](5) + echo onlyTwo(foo) diff --git a/tests/pragmas/tbitsize.nim b/tests/pragmas/tbitsize.nim new file mode 100644 index 000000000..39aee445f --- /dev/null +++ b/tests/pragmas/tbitsize.nim @@ -0,0 +1,22 @@ +discard """ +ccodeCheck: "\\i @'unsigned int flag:1;' .*" +""" + +type + bits* = object + flag* {.bitsize: 1.}: cuint + opts* {.bitsize: 4.}: cint + +var + b: bits + +doAssert b.flag == 0 +b.flag = 1 +doAssert b.flag == 1 +b.flag = 2 +doAssert b.flag == 0 + +b.opts = 7 +doAssert b.opts == 7 +b.opts = 9 +doAssert b.opts == -7 diff --git a/tests/pragmas/tcompile_missing_file.nim b/tests/pragmas/tcompile_missing_file.nim new file mode 100644 index 000000000..fd90bd57d --- /dev/null +++ b/tests/pragmas/tcompile_missing_file.nim @@ -0,0 +1,5 @@ +discard """ + joinable: false + errormsg: "cannot find: noexist.c" +""" +{.compile: "noexist.c".} diff --git a/tests/pragmas/tcompile_pragma.nim b/tests/pragmas/tcompile_pragma.nim new file mode 100644 index 000000000..5b99352dd --- /dev/null +++ b/tests/pragmas/tcompile_pragma.nim @@ -0,0 +1,10 @@ +discard """ + output: '''34''' + joinable: false +""" + +{.compile("cfunction.c", "-DNUMBER_HERE=34").} + +proc cfunction(): cint {.importc.} + +echo cfunction() diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim new file mode 100644 index 000000000..11a6df813 --- /dev/null +++ b/tests/pragmas/tcustom_pragma.nim @@ -0,0 +1,540 @@ +{.experimental: "notnil".} + +import macros, asyncmacro, asyncfutures + +block: + template myAttr() {.pragma.} + + proc myProc():int {.myAttr.} = 2 + const hasMyAttr = myProc.hasCustomPragma(myAttr) + static: + doAssert(hasMyAttr) + +block: + template myAttr(a: string) {.pragma.} + + type + MyObj = object + myField1, myField2 {.myAttr: "hi".}: int + + MyGenericObj[T] = object + myField1, myField2 {.myAttr: "hi".}: int + + MyOtherObj = MyObj + + + var o: MyObj + static: + doAssert o.myField2.hasCustomPragma(myAttr) + doAssert(not o.myField1.hasCustomPragma(myAttr)) + doAssert(not o.myField1.hasCustomPragma(MyObj)) + doAssert(not o.myField1.hasCustomPragma(MyOtherObj)) + + var ogen: MyGenericObj[int] + static: + doAssert ogen.myField2.hasCustomPragma(myAttr) + doAssert(not ogen.myField1.hasCustomPragma(myAttr)) + doAssert(not ogen.myField1.hasCustomPragma(MyGenericObj)) + doAssert(not ogen.myField1.hasCustomPragma(MyGenericObj)) + + +import custom_pragma +block: # A bit more advanced case + type + Subfield {.defaultValue: "catman".} = object + `c`* {.serializationKey: "cc".}: float + + MySerializable = object + a {.serializationKey"asdf", defaultValue: 5.} : int + b {.custom_pragma.defaultValue"hello".} : int + field: Subfield + d {.alternativeKey("df", 5).}: float + e {.alternativeKey(V = 5).}: seq[bool] + + proc myproc(x: int, s: string) {.alternativeKey(V = 5), serializationKey"myprocSS".} = + echo x, s + + + var s: MySerializable + + const aDefVal = s.a.getCustomPragmaVal(defaultValue) + static: doAssert(aDefVal == 5) + + const aSerKey = s.a.getCustomPragmaVal(serializationKey) + static: doAssert(aSerKey == "asdf") + + const cSerKey = getCustomPragmaVal(s.field.c, serializationKey) + static: doAssert(cSerKey == "cc") + + const procSerKey = getCustomPragmaVal(myproc, serializationKey) + static: doAssert(procSerKey == "myprocSS") + + static: doAssert(hasCustomPragma(myproc, alternativeKey)) + + const hasFieldCustomPragma = s.field.hasCustomPragma(defaultValue) + static: doAssert(hasFieldCustomPragma == false) + + # pragma on an object + static: + doAssert Subfield.hasCustomPragma(defaultValue) + doAssert(Subfield.getCustomPragmaVal(defaultValue) == "catman") + + doAssert hasCustomPragma(type(s.field), defaultValue) + + proc foo(s: var MySerializable) = + static: doAssert(s.a.getCustomPragmaVal(defaultValue) == 5) + + foo(s) + +block: # ref types + type + Node = object of RootObj + left {.serializationKey:"l".}, right {.serializationKey:"r".}: NodeRef + NodeRef = ref Node + NodePtr = ptr Node + + SpecialNodeRef = ref object of NodeRef + data {.defaultValue"none".}: string + + MyFile {.defaultValue: "closed".} = ref object + path {.defaultValue: "invalid".}: string + + TypeWithoutPragma = object + + var s = NodeRef() + + const + leftSerKey = getCustomPragmaVal(s.left, serializationKey) + rightSerKey = getCustomPragmaVal(s.right, serializationKey) + static: + doAssert leftSerKey == "l" + doAssert rightSerKey == "r" + + var specS = SpecialNodeRef() + + const + dataDefVal = hasCustomPragma(specS.data, defaultValue) + specLeftSerKey = hasCustomPragma(specS.left, serializationKey) + static: + doAssert dataDefVal == true + doAssert specLeftSerKey == true + + var ptrS = NodePtr(nil) + const + ptrRightSerKey = getCustomPragmaVal(ptrS.right, serializationKey) + static: + doAssert ptrRightSerKey == "r" + + var f = MyFile() + const + fileDefVal = f.getCustomPragmaVal(defaultValue) + filePathDefVal = f.path.getCustomPragmaVal(defaultValue) + static: + doAssert fileDefVal == "closed" + doAssert filePathDefVal == "invalid" + + static: + doAssert TypeWithoutPragma.hasCustomPragma(defaultValue) == false + +block: + type + VariantKind = enum + variInt, + variFloat + variString + variNestedCase + Variant = object + case kind: VariantKind + of variInt: integer {.serializationKey: "int".}: BiggestInt + of variFloat: floatp: BiggestFloat + of variString: str {.serializationKey: "string".}: string + of variNestedCase: + case nestedKind: VariantKind + of variInt..variNestedCase: nestedItem {.defaultValue: "Nimmers of the world, unite!".}: int + + let vari = Variant(kind: variInt) + + const + hasIntSerKey = vari.integer.hasCustomPragma(serializationKey) + strSerKey = vari.str.getCustomPragmaVal(serializationKey) + nestedItemDefVal = vari.nestedItem.getCustomPragmaVal(defaultValue) + + static: + doAssert hasIntSerKey + doAssert strSerKey == "string" + doAssert nestedItemDefVal == "Nimmers of the world, unite!" + +block: + template simpleAttr {.pragma.} + + type Annotated {.simpleAttr.} = object + + proc generic_proc[T]() = + doAssert Annotated.hasCustomPragma(simpleAttr) + +#-------------------------------------------------------------------------- +# Pragma on proc type + +type + MyAnnotatedProcType {.defaultValue(4).} = proc(x: int) + +let a {.defaultValue(4).}: proc(x: int) = nil +var b: MyAnnotatedProcType = nil +var c: proc(x: int): void {.defaultValue(5).} = nil +var d {.defaultValue(44).}: MyAnnotatedProcType = nil +static: + doAssert hasCustomPragma(a, defaultValue) + doAssert hasCustomPragma(MyAnnotatedProcType, defaultValue) + doAssert hasCustomPragma(b, defaultValue) + doAssert hasCustomPragma(typeof(c), defaultValue) + doAssert getCustomPragmaVal(d, defaultValue) == 44 + doAssert getCustomPragmaVal(typeof(d), defaultValue) == 4 + +# bug #8371 +template thingy {.pragma.} + +type + Cardinal = enum + north, east, south, west + Something = object + a: float32 + case cardinal: Cardinal + of north: + b {.thingy.}: int + of east: + c: int + of south: discard + else: discard + +var foo: Something +foo.cardinal = north +doAssert foo.b.hasCustomPragma(thingy) == true + +proc myproc(s: string): int = + {.thingy.}: + s.len + +doAssert myproc("123") == 3 + +let xx = compiles: + proc myproc_bad(s: string): int = + {.not_exist.}: + s.len +doAssert: xx == false + +macro checkSym(s: typed{nkSym}): untyped = + let body = s.getImpl.body + doAssert body[1].kind == nnkPragmaBlock + doAssert body[1][0].kind == nnkPragma + doAssert body[1][0][0] == bindSym"thingy" + +checkSym(myproc) + +# var and let pragmas +block: + template myAttr() {.pragma.} + template myAttr2(x: int) {.pragma.} + template myAttr3(x: string) {.pragma.} + + type + MyObj2 = ref object + MyObjNotNil = MyObj2 not nil + + let a {.myAttr,myAttr2(2),myAttr3:"test".}: int = 0 + let b {.myAttr,myAttr2(2),myAttr3:"test".} = 0 + var x {.myAttr,myAttr2(2),myAttr3:"test".}: int = 0 + var y {.myAttr,myAttr2(2),myAttr3:"test".}: int + var z {.myAttr,myAttr2(2),myAttr3:"test".} = 0 + var z2 {.myAttr.}: MyObjNotNil + + template check(s: untyped) = + doAssert s.hasCustomPragma(myAttr) + doAssert s.hasCustomPragma(myAttr2) + doAssert s.getCustomPragmaVal(myAttr2) == 2 + doAssert s.hasCustomPragma(myAttr3) + doAssert s.getCustomPragmaVal(myAttr3) == "test" + + check(a) + check(b) + check(x) + check(y) + check(z) + +# pragma with multiple fields +block: + template myAttr(first: string, second: int, third: float) {.pragma.} + let a {.myAttr("one", 2, 3.0).} = 0 + let ps = a.getCustomPragmaVal(myAttr) + doAssert ps.first == ps[0] and ps.first == "one" + doAssert ps.second == ps[1] and ps.second == 2 + doAssert ps.third == ps[2] and ps.third == 3.0 + +# pragma with implicit&explicit generic types +block: + template fooBar[T](x: T; c: static[int] = 42; m: char) {.pragma.} + var e {.fooBar("foo", 123, 'u').}: int + doAssert(hasCustomPragma(e, fooBar)) + doAssert(getCustomPragmaVal(e, fooBar).c == 123) + +block: + macro expectedAst(expectedRepr: static[string], input: untyped): untyped = + doAssert input.treeRepr & "\n" == expectedRepr + return input + + macro expectedAstRepr(expectedRepr: static[string], input: untyped): untyped = + doAssert input.repr == expectedRepr + return input + + const procTypeAst = """ +ProcTy + FormalParams + Empty + IdentDefs + Ident "x" + Ident "int" + Empty + Pragma + Ident "async" +""" + + type + Foo = proc (x: int) {.expectedAst(procTypeAst), async.} + + static: doAssert Foo is proc(x: int): Future[void] + + const asyncProcTypeAst = """ +proc (s: string): Future[void] {..}""" + # using expectedAst would show `OpenSymChoice` for Future[void], which is fragile. + type + Bar = proc (s: string) {.async, expectedAstRepr(asyncProcTypeAst).} + + static: doAssert Bar is proc(x: string): Future[void] + + const typeAst = """ +TypeDef + PragmaExpr + Ident "Baz" + Pragma + Empty + ObjectTy + Empty + Empty + RecList + IdentDefs + Ident "x" + Ident "string" + Empty +""" + + type + Baz {.expectedAst(typeAst).} = object + x: string + + static: doAssert Baz.x is string + + const procAst = """ +ProcDef + Ident "bar" + Empty + Empty + FormalParams + Ident "string" + IdentDefs + Ident "s" + Ident "string" + Empty + Empty + Empty + StmtList + ReturnStmt + Ident "s" +""" + + proc bar(s: string): string {.expectedAst(procAst).} = + return s + + static: doAssert bar("x") == "x" + +#------------------------------------------------------ +# bug #13909 + +template dependency*(id: string, weight = 0.0) {.pragma.} + +type + MyObject* = object + provider*: proc(obj: string): pointer {.dependency("Data/" & obj, 16.1), noSideEffect.} + +proc myproc(obj: string): string {.dependency("Data/" & obj, 16.1).} = + result = obj + +# bug 12523 +template myCustomPragma {.pragma.} + +type + RefType = ref object + field {.myCustomPragma.}: int + + ObjType = object + field {.myCustomPragma.}: int + RefType2 = ref ObjType + +block: + let x = RefType() + for fieldName, fieldSym in fieldPairs(x[]): + doAssert hasCustomPragma(fieldSym, myCustomPragma) + +block: + let x = RefType2() + for fieldName, fieldSym in fieldPairs(x[]): + doAssert hasCustomPragma(fieldSym, myCustomPragma) + +# bug 8457 +block: + template world {.pragma.} + + type + Hello = ref object + a: float32 + b {.world.}: int + + discard Hello(a: 1.0, b: 12) + +# test routines +block: + template prag {.pragma.} + proc hello {.prag.} = discard + iterator hello2: int {.prag.} = discard + template hello3(x: int): int {.prag.} = x + macro hello4(x: int): int {.prag.} = x + func hello5(x: int): int {.prag.} = x + doAssert hello.hasCustomPragma(prag) + doAssert hello2.hasCustomPragma(prag) + doAssert hello3.hasCustomPragma(prag) + doAssert hello4.hasCustomPragma(prag) + doAssert hello5.hasCustomPragma(prag) + +# test push doesn't break +block: + template prag {.pragma.} + {.push prag.} + proc hello = discard + iterator hello2: int = discard + template hello3(x: int): int = x + macro hello4(x: int): int = x + func hello5(x: int): int = x + type + Foo = enum a + Bar[T] = ref object of RootObj + x: T + case y: bool + of false: discard + else: + when true: discard + for a in [1]: discard a + {.pop.} + +# issue #11511 +when false: + template myAttr {.pragma.} + + type TObj = object + a {.myAttr.}: int + + macro hasMyAttr(t: typedesc): untyped = + let objTy = t.getType[1].getType + let recList = objTy[2] + let sym = recList[0] + assert sym.kind == nnkSym and sym.eqIdent("a") + let hasAttr = sym.hasCustomPragma(myAttr) + newLit(hasAttr) + + doAssert hasMyAttr(TObj) + + +# bug #11415 +template noserialize() {.pragma.} + +type + Point[T] = object + x, y: T + + ReplayEventKind = enum + FoodAppeared, FoodEaten, DirectionChanged + + ReplayEvent = object + case kind: ReplayEventKind + of FoodEaten, FoodAppeared: # foodPos is in multiple branches + foodPos {.noserialize.}: Point[float] + of DirectionChanged: + playerPos: float +let ev = ReplayEvent( + kind: FoodEaten, + foodPos: Point[float](x: 5.0, y: 1.0) + ) + +doAssert ev.foodPos.hasCustomPragma(noserialize) + + +when false: + # misc + {.pragma: haha.} + {.pragma: hoho.} + template hehe(key, val: string, haha) {.pragma.} + + type A {.haha, hoho, haha, hehe("hi", "hu", "he").} = int + + assert A.getCustomPragmaVal(hehe) == (key: "hi", val: "hu", haha: "he") + + template hehe(key, val: int) {.pragma.} + + var bb {.haha, hoho, hehe(1, 2), haha, hehe("hi", "hu", "he").} = 3 + + # left-to-right priority/override order for getCustomPragmaVal + assert bb.getCustomPragmaVal(hehe) == (key: "hi", val: "hu", haha: "he") + +{.experimental: "dynamicBindSym".} + +# const +block: + template myAttr() {.pragma.} + template myAttr2(x: int) {.pragma.} + template myAttr3(x: string) {.pragma.} + + type + MyObj2 = ref object + + const a {.myAttr,myAttr2(2),myAttr3:"test".}: int = 0 + const b {.myAttr,myAttr2(2),myAttr3:"test".} = 0 + + macro forceHasCustomPragma(x: untyped, y: typed): untyped = + var x = bindSym(x.repr) + for c in x: + if c.symKind == nskConst: + x = c + break + result = getAst(hasCustomPragma(x, y)) + + macro forceGetCustomPragmaVal(x: untyped, y: typed): untyped = + var x = bindSym(x.repr) + for c in x: + if c.symKind == nskConst: + x = c + break + result = getAst(getCustomPragmaVal(x, y)) + + template check(s: untyped) = + doAssert forceHasCustomPragma(s, myAttr) + doAssert forceHasCustomPragma(s, myAttr2) + doAssert forceGetCustomPragmaVal(s, myAttr2) == 2 + doAssert forceHasCustomPragma(s, myAttr3) + doAssert forceGetCustomPragmaVal(s, myAttr3) == "test" + + check(a) + check(b) + +block: # https://forum.nim-lang.org/t/12522, backticks + template `mypragma`() {.pragma.} + # Error: invalid pragma: `mypragma` + type Test = object + field {.`mypragma`.}: int + doAssert Test().field.hasCustomPragma(mypragma) diff --git a/tests/pragmas/tdeprecated.nim b/tests/pragmas/tdeprecated.nim new file mode 100644 index 000000000..a5d07f727 --- /dev/null +++ b/tests/pragmas/tdeprecated.nim @@ -0,0 +1,10 @@ +# bug #6436 +proc foo(size: int, T: typedesc): seq[T] {.deprecated.}= + result = newSeq[T](size) + +proc foo[T](size: int): seq[T]= + result = newSeq[T](size) + +let bar = foo[int](3) # Warning foo is deprecated + +doAssert bar == @[0, 0, 0] diff --git a/tests/pragmas/thintprocessing.nim b/tests/pragmas/thintprocessing.nim new file mode 100644 index 000000000..c608bc6e4 --- /dev/null +++ b/tests/pragmas/thintprocessing.nim @@ -0,0 +1,18 @@ +discard """ + disabled: windows + matrix: "--hint:processing" + nimout: ''' +compile start +.. +warn_module.nim(6, 6) Hint: 'test' is declared but not used [XDeclaredButNotUsed] +compile end +''' +""" + +static: + echo "compile start" + +import warn_module + +static: + echo "compile end" diff --git a/tests/pragmas/tinvalid_user_pragma.nim b/tests/pragmas/tinvalid_user_pragma.nim new file mode 100644 index 000000000..3081db842 --- /dev/null +++ b/tests/pragmas/tinvalid_user_pragma.nim @@ -0,0 +1,9 @@ +discard """ +cmd: "nim check $file" +""" + +{.pragma test: foo.} #[tt.Error +^ invalid pragma: {.pragma, test: foo.} ]# + +{.pragma: 1.} #[tt.Error +^ invalid pragma: {.pragma: 1.} ]# diff --git a/tests/pragmas/tinvalidcustompragma.nim b/tests/pragmas/tinvalidcustompragma.nim new file mode 100644 index 000000000..a31695809 --- /dev/null +++ b/tests/pragmas/tinvalidcustompragma.nim @@ -0,0 +1,23 @@ +discard """ + cmd: "nim check $file" +""" + +# issue #21652 +type Foo = object +template foo() {.tags:[Foo].} = #[tt.Error + ^ invalid pragma: tags: [Foo]]# + discard + +{.foobar.} #[tt.Error + ^ invalid pragma: foobar]# +type A = enum a {.foobar.} #[tt.Error + ^ invalid pragma: foobar]# +for b {.foobar.} in [1]: discard #[tt.Error + ^ invalid pragma: foobar]# +template foobar {.pragma.} +{.foobar.} #[tt.Error + ^ cannot attach a custom pragma to 'tinvalidcustompragma'; custom pragmas are not supported for modules]# +type A = enum a {.foobar.} #[tt.Error + ^ cannot attach a custom pragma to 'a'; custom pragmas are not supported for enum fields]# +for b {.foobar.} in [1]: discard #[tt.Error + ^ cannot attach a custom pragma to 'b'; custom pragmas are not supported for `for` loop variables]# diff --git a/tests/pragmas/tlocks.nim b/tests/pragmas/tlocks.nim new file mode 100644 index 000000000..5d6fcdd9c --- /dev/null +++ b/tests/pragmas/tlocks.nim @@ -0,0 +1,12 @@ +type SomeBase* = ref object of RootObj +type SomeDerived* = ref object of SomeBase + memberProc*: proc () + +method testMethod(g: SomeBase) {.base, locks: "unknown".} = discard +method testMethod(g: SomeDerived) = + if g.memberProc != nil: + g.memberProc() + +# ensure int literals still work +proc plain*() {.locks: 0.} = + discard diff --git a/tests/pragmas/tnoreturn.nim b/tests/pragmas/tnoreturn.nim new file mode 100644 index 000000000..6a58055fe --- /dev/null +++ b/tests/pragmas/tnoreturn.nim @@ -0,0 +1,27 @@ +discard """ +matrix: "--mm:refc" +ccodeCheck: "\\i @'__attribute__((noreturn))' .*" +action: compile +""" + +proc noret1*(i: int) {.noreturn.} = + echo i + + +proc noret2*(i: int): void {.noreturn.} = + echo i + +if true: noret1(1) +if true: noret2(2) + +var p {.used.}: proc(i: int): int +doAssert(not compiles( + p = proc(i: int): int {.noreturn.} = i # noreturn lambda returns int +)) + + +doAssert(not compiles( + block: + noret1(5) + echo 1 # statement after noreturn +)) diff --git a/tests/pragmas/tonoff1.nim b/tests/pragmas/tonoff1.nim new file mode 100644 index 000000000..20ba7def2 --- /dev/null +++ b/tests/pragmas/tonoff1.nim @@ -0,0 +1,8 @@ +# issue #23002 + +import monoff1 + +proc test() = + {.warning[ProveInit]: on.} + +test() diff --git a/tests/pragmas/tonoff2.nim b/tests/pragmas/tonoff2.nim new file mode 100644 index 000000000..9dff5ef11 --- /dev/null +++ b/tests/pragmas/tonoff2.nim @@ -0,0 +1,14 @@ +discard """ + action: compile +""" + +# issue #22841 + +import unittest + +proc on() = + discard + +suite "some suite": + test "some test": + discard diff --git a/tests/pragmas/tpragmas_misc.nim b/tests/pragmas/tpragmas_misc.nim new file mode 100644 index 000000000..adb7e73c3 --- /dev/null +++ b/tests/pragmas/tpragmas_misc.nim @@ -0,0 +1,75 @@ +##[ +tests for misc pragmas that don't need a separate file +]## + +block: + static: doAssert not defined(tpragmas_misc_def) + {.undef(tpragmas_misc_def).} # works even if not set + static: doAssert not defined(tpragmas_misc_def) + {.define(tpragmas_misc_def).} + static: doAssert defined(tpragmas_misc_def) + {.undef(tpragmas_misc_def).} + static: doAssert not defined(tpragmas_misc_def) + +block: # (partial fix) bug #15920 + block: # var template pragmas don't work in templates + template foo(expr) = + expr + proc fun1()= + let a {.foo.} = 1 + template fun2()= + let a {.foo.} = 1 + fun1() # ok + fun2() # WAS bug + + template foo2() = discard # distractor (template or other symbol kind) + block: + template foo2(expr) = + expr + proc fun1()= + let a {.foo2.} = 1 + template fun2()= + let a {.foo2.} = 1 + fun1() # ok + fun2() # bug: Error: invalid pragma: foo2 + + block: # template pragmas don't work for templates, #18212 + # adapted from $nim/lib/std/private/since.nim + # case without overload + template since3(version: (int, int), body: untyped) {.dirty.} = + when (NimMajor, NimMinor) >= version: + body + when true: # bug + template fun3(): int {.since3: (1, 3).} = 12 + + block: # ditto, w + # case with overload + template since2(version: (int, int), body: untyped) {.dirty.} = + when (NimMajor, NimMinor) >= version: + body + template since2(version: (int, int, int), body: untyped) {.dirty.} = + when (NimMajor, NimMinor, NimPatch) >= version: + body + when true: # bug + template fun3(): int {.since2: (1, 3).} = 12 + +when true: # D20210801T100514:here + from macros import genSym + block: + template fn() = + var ret {.gensym.}: int # must special case template pragmas so it doesn't get confused + discard ret + fn() + static: discard genSym() + +block: # issue #10994 + macro foo(x): untyped = x + template bar {.pragma.} + + proc a {.bar.} = discard # works + proc b {.bar, foo.} = discard # doesn't + +block: # issue #22525 + macro catch(x: typed) = x + proc thing {.catch.} = discard + thing() diff --git a/tests/pragmas/tpragmas_reorder.nim b/tests/pragmas/tpragmas_reorder.nim new file mode 100644 index 000000000..c4b1a6b0a --- /dev/null +++ b/tests/pragmas/tpragmas_reorder.nim @@ -0,0 +1,19 @@ +discard """ + matrix: "--experimental:codeReordering" +""" + +runnableExamples: + import strtabs + var t = newStringTable() + t["name"] = "John" + t["city"] = "Monaco" + doAssert t.len == 2 + doAssert t.hasKey "name" + doAssert "name" in t + +include "system/inclrtl" + +{.pragma: rtlFunc, rtl.} + +proc hasKey*(): bool {.rtlFunc.} = + discard \ No newline at end of file diff --git a/tests/pragmas/tpush.nim b/tests/pragmas/tpush.nim new file mode 100644 index 000000000..9c6b85c4e --- /dev/null +++ b/tests/pragmas/tpush.nim @@ -0,0 +1,144 @@ +discard """ + targets: "c js" +""" + +# test the new pragmas + +{.push warnings: off, hints: off.} +proc noWarning() = + var + x: int + echo(x) + +{.pop.} + +proc WarnMe() = + var + x: int + echo(x) + +# bug #11852 +proc foo(x: string, y: int, res: int) = + {.push checks: off} + var a: ptr char = unsafeAddr(x[y]) + {.pop.} + if x.len > y: + doAssert ord(a[]) == 51 + else: + doAssert x.len + 48 == res + +foo("", 0, 48) +foo("abc", 40, 51) + +# bug #22362 +{.push staticBoundChecks: on.} +proc main(): void = + {.pop.} + discard + {.push staticBoundChecks: on.} + +main() + + +proc timnFoo[T](obj: T) {.noSideEffect.} = discard # BUG + +{.push exportc.} +proc foo1() = + var s1 = "bar" + timnFoo(s1) + var s2 = @[1] + timnFoo(s2) +{.pop.} + + +block: # bug #22913 + block: + type r = object + + template std[T](x: T) = + let ttt {.used.} = x + result = $ttt + + proc bar[T](x: T): string = + std(x) + + {.push exportc: "$1".} + proc foo(): r = + let s = bar(123) + {.pop.} + + discard foo() + + block: + type r = object + {.push exportc: "$1".} + proc foo2(): r = + let s = $result + {.pop.} + + discard foo2() + +block: # bug #23019 + proc f(x: bool) + + proc a(x: int) = + if false: f(true) + + proc f(x: bool) = + if false: a(0) + + proc k(r: int|int) {.inline.} = # seems to require being generic and inline + if false: a(0) + + + # {.push tags: [].} + {.push raises: [].} + + {.push warning[ObservableStores]:off.} # can be any warning, off or on + let w = 0 + k(w) + {.pop.} + {.pop.} + +{.push exportC.} + +block: + proc foo11() = + const factor = [1, 2, 3, 4] + doAssert factor[0] == 1 + proc foo21() = + const factor = [1, 2, 3, 4] + doAssert factor[0] == 1 + + foo11() + foo21() + +template foo31() = + let factor = [1, 2, 3, 4] + doAssert factor[0] == 1 +template foo41() = + let factor = [1, 2, 3, 4] + doAssert factor[0] == 1 + +foo31() +foo41() + +{.pop.} + +import macros + +block: + {.push deprecated.} + template test() = discard + test() + {.pop.} + macro foo(): bool = + let ast = getImpl(bindSym"test") + var found = false + if ast[4].kind == nnkPragma: + for x in ast[4]: + if x.eqIdent"deprecated": + found = true + break + result = newLit(found) + doAssert foo() diff --git a/tests/pragmas/tpushexperimental.nim b/tests/pragmas/tpushexperimental.nim new file mode 100644 index 000000000..301419f60 --- /dev/null +++ b/tests/pragmas/tpushexperimental.nim @@ -0,0 +1,13 @@ +discard """ + output: '''0 1 +1 2 +2 3 +0 1 +1 2 +2 3 +3 5''' +""" + +import mpushexperimental + +main(12) diff --git a/tests/pragmas/tpushnotes.nim b/tests/pragmas/tpushnotes.nim new file mode 100644 index 000000000..27ba0bec4 --- /dev/null +++ b/tests/pragmas/tpushnotes.nim @@ -0,0 +1,13 @@ +discard """ + matrix: "--warningAsError:HoleEnumConv" +""" + +type + e = enum + a = 0 + b = 2 + +var i: int +{.push warning[HoleEnumConv]:off.} +discard i.e +{.pop.} diff --git a/tests/pragmas/tqualifiedmacro.nim b/tests/pragmas/tqualifiedmacro.nim new file mode 100644 index 000000000..bc95ec1ea --- /dev/null +++ b/tests/pragmas/tqualifiedmacro.nim @@ -0,0 +1,14 @@ +discard """ + output: ''' +template t +''' +""" + +# issue #12696 + +import mqualifiedmacro +proc p() {. mqualifiedmacro.t .} = # errors with identifier expected but a.t found + echo "proc p" + +type Foo {. mqualifiedmacro.m("Bar") .} = object +doAssert Bar is object diff --git a/tests/pragmas/treorder.nim b/tests/pragmas/treorder.nim new file mode 100644 index 000000000..09a98ef6a --- /dev/null +++ b/tests/pragmas/treorder.nim @@ -0,0 +1,75 @@ +discard """ +output:'''0 +1 +2 +3''' +""" + +import macros +# {.reorder: on .} +{.experimental: "codeReordering".} + +echo foo(-1) +echo callWithFoo(0) +echo(CA+CD) +echo useTypes(TA(x:TB(x:1)), 2) +second(0) + +template callWithFoo(arg: untyped): untyped = + foo(arg) + +proc first(i: int): void + +proc second(i: int): void = + make(first) + first(i) + +proc useTypes(a: TA, d: TD): int = + result = a.x.x+d + +type + TDoubleCyclic = ref object + x: TCyclicA + y: TCyclicB + +type + TCyclicA = ref object + x: TDoubleCyclic + +type + TCyclicB = ref object + x: TDoubleCyclic + +const + CA = 1 + CB = CC + +type + TA = object + x: TB + TC = type(CC) + TD = type(CA) + +const + CC = 1 + CD = CB + +type + TB = object + x: TC + +proc foo(x: int): int = + result = bar(x) + +proc bar(x: int): int = + result = x+1 + +macro make(arg: untyped): untyped = + ss &= arg.repr + ss &= " " + discard + +proc first(i: int): void = + make(second) + +var ss {.compileTime.}: string = "" diff --git a/tests/pragmas/tsym_as_pragma.nim b/tests/pragmas/tsym_as_pragma.nim new file mode 100644 index 000000000..788311244 --- /dev/null +++ b/tests/pragmas/tsym_as_pragma.nim @@ -0,0 +1,8 @@ + +# bug #3171 + +template newDataWindow(): untyped = + let eventClosure = proc (closure: pointer): bool {.closure, cdecl.} = + discard + +newDataWindow() diff --git a/tests/pragmas/ttypedef_macro.nim b/tests/pragmas/ttypedef_macro.nim new file mode 100644 index 000000000..dd4c87757 --- /dev/null +++ b/tests/pragmas/ttypedef_macro.nim @@ -0,0 +1,66 @@ +import macros + +macro makeref(s): untyped = + expectKind s, nnkTypeDef + result = newTree(nnkTypeDef, s[0], s[1], newTree(nnkRefTy, s[2])) + +type + Obj {.makeref.} = object + a: int + +doAssert Obj is ref +doAssert Obj(a: 3)[].a == 3 + +macro multiply(amount: static int, s): untyped = + let name = $s[0].basename + result = newNimNode(nnkTypeSection) + for i in 1 .. amount: + result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2])) + +type + Foo = object + Bar {.multiply: 2.} = object + x, y, z: int + Baz = object + +let bar1 = Bar1(x: 1, y: 2, z: 3) +let bar2 = Bar2(x: bar1.x, y: bar1.y, z: bar1.z) +doAssert Bar1 isnot Bar2 +doAssert not declared(Bar) +doAssert not declared(Bar3) + +# https://github.com/nim-lang/RFCs/issues/219 + +macro inferKind(td): untyped = + let name = $td[0].basename + var rhs = td[2] + while rhs.kind in {nnkPtrTy, nnkRefTy}: rhs = rhs[0] + if rhs.kind != nnkObjectTy: + result = td + else: + for n in rhs[^1]: + if n.kind == nnkRecCase and n[0][^2].eqIdent"_": + let kindTypeName = ident(name & "Kind") + let en = newTree(nnkEnumTy, newEmptyNode()) + for i in 1 ..< n.len: + let branch = n[i] + if branch.kind == nnkOfBranch: + for j in 0 ..< branch.len - 1: + en.add(branch[j]) + n[0][^2] = kindTypeName + return newTree(nnkTypeSection, + newTree(nnkTypeDef, kindTypeName, newEmptyNode(), en), + td) + +type Node {.inferKind.} = ref object + case kind: _ + of opValue: value: int + of opAdd, opSub, opMul, opCall: kids: seq[Node] + +doAssert opValue is NodeKind +let node = Node(kind: opMul, kids: @[ + Node(kind: opValue, value: 3), + Node(kind: opValue, value: 5) +]) +doAssert node.kind == opMul +doAssert node.kids[0].value * node.kids[1].value == 15 diff --git a/tests/pragmas/tused.nim b/tests/pragmas/tused.nim new file mode 100644 index 000000000..d0c533f9a --- /dev/null +++ b/tests/pragmas/tused.nim @@ -0,0 +1,43 @@ +discard """ + nimout: ''' +compile start +tused.nim(17, 8) Hint: 'echoSub' is declared but not used [XDeclaredButNotUsed] +compile end''' + output: "8\n8" + joinable: false +""" + +# not joinable because paths in nimout differ when imported +static: + echo "compile start" + +template implementArithOpsOld(T) = + proc echoAdd(a, b: T) = + echo a + b + proc echoSub(a, b: T) = + echo a - b + +template implementArithOpsNew(T) = + proc echoAdd(a, b: T) {.used.} = + echo a + b + proc echoSub(a, b: T) {.used.} = + echo a - b + +block: + # should produce warning for the unused 'echoSub' + implementArithOpsOld(int) + echoAdd 3, 5 + +block: + # no warning produced for the unused 'echoSub' + implementArithOpsNew(int) + echoAdd 3, 5 + +# issue #9896 +type + MyEnum {.used.} = enum + Val1, Val2, Val3 + + +static: + echo "compile end" diff --git a/tests/pragmas/tuserpragma.nim b/tests/pragmas/tuserpragma.nim new file mode 100644 index 000000000..784baa176 --- /dev/null +++ b/tests/pragmas/tuserpragma.nim @@ -0,0 +1,7 @@ + +{.pragma: rtl, cdecl, exportc.} + +proc myproc(x, y: int): int {.rtl} = + nil + + diff --git a/tests/pragmas/tuserpragma2.nim b/tests/pragmas/tuserpragma2.nim new file mode 100644 index 000000000..c3f31cd5e --- /dev/null +++ b/tests/pragmas/tuserpragma2.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "can raise an unlisted exception: ref Exception" + file: "tuserpragma2.nim" + line: 11 +""" +{.push warningAsError[Effect]: on.} +# bug #7216 +{.pragma: my_pragma, raises: [].} + +proc test1 {.my_pragma.} = + raise newException(Exception, "msg") +{.pop.} diff --git a/tests/pragmas/tuserpragmaargs.nim b/tests/pragmas/tuserpragmaargs.nim new file mode 100644 index 000000000..791d703ac --- /dev/null +++ b/tests/pragmas/tuserpragmaargs.nim @@ -0,0 +1,5 @@ +var foo {.exportc: "abc".} = 123 +{.pragma: importc2, importc.} +var bar {.importc2: "abc".}: int #[tt.Error + ^ user pragma cannot have arguments]# +echo bar diff --git a/tests/pragmas/tvar_macro.nim b/tests/pragmas/tvar_macro.nim new file mode 100644 index 000000000..3fb6e3e53 --- /dev/null +++ b/tests/pragmas/tvar_macro.nim @@ -0,0 +1,128 @@ +import macros + +block: # test usage + macro modify(sec) = + result = copy sec + result[0][0] = ident(repr(result[0][0]) & "Modified") + + block: + let foo {.modify.} = 3 + doAssert fooModified == 3 + + block: # in section + let + a = 1 + b {.modify.} = 2 + c = 3 + doAssert (a, bModified, c) == (1, 2, 3) + +block: # with single argument + macro appendToName(name: static string, sec) = + result = sec + result[0][0] = ident(repr(result[0][0]) & name) + + block: + let foo {.appendToName: "Bar".} = 3 + doAssert fooBar == 3 + + block: + let + a = 1 + b {.appendToName("").} = 2 + c = 3 + doAssert (a, b, c) == (1, 2, 3) + +macro appendToNameAndAdd(name: static string, incr: static int, sec) = + result = sec + result[0][0] = ident(repr(result[0][0]) & name) + result[0][2] = infix(result[0][2], "+", newLit(incr)) + +block: # with multiple arguments + block: + let foo {.appendToNameAndAdd("Bar", 5).} = 3 + doAssert fooBar == 8 + + block: + let + a = 1 + b {.appendToNameAndAdd("", 15).} = 2 + c = 3 + doAssert (a, b, c) == (1, 17, 3) + +block: # in other kinds of sections + block: + const + a = 1 + b {.appendToNameAndAdd("", 15).} = 2 + c = 3 + doAssert (a, b, c) == (1, 17, 3) + doAssert static(b) == b + + block: + var + a = 1 + b {.appendToNameAndAdd("", 15).} = 2 + c = 3 + doAssert (a, b, c) == (1, 17, 3) + b += a + c += b + doAssert (a, b, c) == (1, 18, 21) + +block: # with other pragmas + macro appendToNameAndAdd(name: static string, incr, sec) = + result = sec + result[0][0][0] = ident(repr(result[0][0][0]) & name) + result[0][0][1].add(ident"deprecated") + result[0][2] = infix(result[0][2], "+", incr) + + var + a = 1 + foo {.exportc: "exportedFooBar", appendToNameAndAdd("Bar", {'0'..'9'}), used.} = {'a'..'z', 'A'..'Z'} + b = 2 + + doAssert (a, b) == (1, 2) + + let importedFooBar {.importc: "exportedFooBar", nodecl.}: set[char] + + doAssert importedFooBar == fooBar #[tt.Warning + ^ fooBar is deprecated + ]# + + +block: # with stropping + macro `cast`(def) = + let def = def[0] + let + lhs = def[0] + typ = def[1] + ex = def[2] + addrTyp = if typ.kind == nnkEmpty: typ else: newTree(nnkPtrTy, typ) + result = quote do: + let tmp: `addrTyp` = unsafeAddr(`ex`) + template `lhs`: untyped = tmp[] + + macro assign(def) = + result = getAst(`cast`(def)) + + block: + let s = @["foo", "bar"] + let a {.`assign`.} = s[0] + doAssert a == "foo" + doAssert a[0].addr == s[0][0].addr + + block: + let + s = @["foo", "bar"] + a {.`cast`.} = s[0] + doAssert a == "foo" + doAssert a[0].addr == s[0][0].addr + +block: # bug #15920 + macro foo(def) = + result = def + proc fun1()= + let a {.foo.} = 1 + template fun2()= + let a {.foo.} = 1 + fun1() # ok + fun2() # BUG diff --git a/tests/pragmas/twarning_off.nim b/tests/pragmas/twarning_off.nim new file mode 100644 index 000000000..ccf07b9c4 --- /dev/null +++ b/tests/pragmas/twarning_off.nim @@ -0,0 +1,15 @@ +discard """ + nimout: ''' +compile start +warn_module.nim(6, 6) Hint: 'test' is declared but not used [XDeclaredButNotUsed] +compile end +''' +""" + +static: + echo "compile start" + +import warn_module + +static: + echo "compile end" diff --git a/tests/pragmas/warn_module.nim b/tests/pragmas/warn_module.nim new file mode 100644 index 000000000..0d1e5f419 --- /dev/null +++ b/tests/pragmas/warn_module.nim @@ -0,0 +1,7 @@ + +{.warning[UnusedImport]: off.} + +import hashes + +proc test(a: float): float = + a |