diff options
Diffstat (limited to 'tests/overload')
31 files changed, 1893 insertions, 0 deletions
diff --git a/tests/overload/importA.nim b/tests/overload/importA.nim new file mode 100644 index 000000000..f045d11b4 --- /dev/null +++ b/tests/overload/importA.nim @@ -0,0 +1,5 @@ +type + Field* = object + elemSize*: int + +template `+`*(x: untyped, y: Field): untyped = x diff --git a/tests/overload/importB.nim b/tests/overload/importB.nim new file mode 100644 index 000000000..2dc3adf7a --- /dev/null +++ b/tests/overload/importB.nim @@ -0,0 +1,15 @@ +type + Foo*[T] = object + v*: T + +template `+`*(x: Foo, y: Foo): untyped = x + +template newvar*(r: untyped): untyped {.dirty.} = + var r: float + +template t1*(x: Foo): untyped = + newvar(y1) + x +template t2*(x: Foo): untyped = + newvar(y2) + x diff --git a/tests/overload/issue22142/tfail_implicit_ambiguous.nim b/tests/overload/issue22142/tfail_implicit_ambiguous.nim new file mode 100644 index 000000000..2586e0877 --- /dev/null +++ b/tests/overload/issue22142/tfail_implicit_ambiguous.nim @@ -0,0 +1,10 @@ +discard """ + errormsg: "ambiguous call" +""" +type + A[T] = object + C = object + +proc test[T: A](param: T): bool = false +proc test(param: A): bool = true +doAssert test(A[C]()) == true # previously would pass diff --git a/tests/overload/issue22142/tfail_nested_pointers.nim b/tests/overload/issue22142/tfail_nested_pointers.nim new file mode 100644 index 000000000..1603d98cb --- /dev/null +++ b/tests/overload/issue22142/tfail_nested_pointers.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "ambiguous call" +""" + +type + A[T] = object + C = object + x:int +proc p[T: A[ptr]](x:ptr[T]):bool = false +proc p(x: ptr[A[ptr]]):bool = true +var a: A[ptr[C]] +doAssert p(a.addr) == true diff --git a/tests/overload/issue22142/tfail_object_is_generic.nim b/tests/overload/issue22142/tfail_object_is_generic.nim new file mode 100644 index 000000000..b46795bd5 --- /dev/null +++ b/tests/overload/issue22142/tfail_object_is_generic.nim @@ -0,0 +1,16 @@ +discard """ + errormsg: "ambiguous call" +""" + +#[ +As of the time of writing `object` needs some special +treament in order to be considered "generic" in the right +context when used implicitly +]# + +type + C = object + +proc test[T: object](param: T): bool = false +proc test(param: object): bool = true +doAssert test(C()) == true # previously would pass diff --git a/tests/overload/issue22142/tfail_typeclass_var_invar.nim b/tests/overload/issue22142/tfail_typeclass_var_invar.nim new file mode 100644 index 000000000..07db65fef --- /dev/null +++ b/tests/overload/issue22142/tfail_typeclass_var_invar.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "ambiguous call" +""" + +type C = object +proc test[T: ptr](param: var T): bool = false +proc test(param: var ptr): bool = true +var d: ptr[C] +doAssert test(d) == true # previously would pass diff --git a/tests/overload/issue22142/tissue22142_shouldpass.nim b/tests/overload/issue22142/tissue22142_shouldpass.nim new file mode 100644 index 000000000..90d4efe51 --- /dev/null +++ b/tests/overload/issue22142/tissue22142_shouldpass.nim @@ -0,0 +1,68 @@ +type + A[T] = object of RootObj + B[T] = object + C = object + x:int + +# change (previously true) +block: + proc test[J;H: A[J];T: B[H]](param: T): bool = false + proc test[T](param: B[T]): bool = true + doAssert test(B[A[int]]()) == false +block: # object is more specific then `T` + proc p[H:object;T:ptr[H]](param:T):bool = false + proc p[T](param:ptr[T]):bool= true + var l: ptr[C] + doAssert p(l) == false +block: + proc p[T:A[object]](param:T):bool = false + proc p[T](param: A[T]):bool= true + doAssert p(A[C]()) == false +block: + proc test[H;T: A[H]](param: T): bool = false + proc test(param: A): bool = true + doAssert test(A[C]()) == false + +# change (previously ambiguous) +block: + proc p[T](a: A[T]): bool = false + proc p[T: object](a: T): bool = true + doAssert p(A[int]()) == false +block: # A is more specific than `object` + proc test[T: A](param: T): bool = false + proc test[T: object](param: T): bool = true + doAssert test(A[int]()) == false +block: + proc test[T: A](param: T): bool = false + proc test(param: object): bool = true + doAssert test(A[int]()) == false +block: + proc test[H;T: A[H]](param: T): bool = false + proc test(param: object): bool = true + doAssert test(A[C]()) == false +block: + proc test[H;T: A[B[H]]](param: T): bool = false + proc test[T: object](param: T): bool = true + doAssert test(A[B[int]]()) == false +block: + #[ + This was referenced in the nim compiler source (`sumGeneric`) as a case + that was supposed to not be ambiguous, yet it was + ]# + proc test[J;H:A[J]; T: A[H]](param: T): bool = false + proc test[H;T: A[H]](param: T): bool = true + doAssert test(A[A[C]]()) == false +block: + proc test[J;T:A[J]](param: A[T]): bool = false + proc test[T](param: A[T]): bool = true + doAssert test(A[A[C]]()) == false +block: + proc test[T](param: A[T]): bool = false + proc test[T: object](param: A[T]): bool = true + doAssert test(A[C]()) == true + + +block: #anti-regression (object is more specific then `T`) + proc test[J;T:A[J]](param: A[T]): bool = false + proc test(param: A[A[object]]): bool = true + doAssert test(A[A[C]]()) == true \ No newline at end of file diff --git a/tests/overload/m19737.nim b/tests/overload/m19737.nim new file mode 100644 index 000000000..7f7ac98e2 --- /dev/null +++ b/tests/overload/m19737.nim @@ -0,0 +1,10 @@ +type + UInt128* = object + lo, hi: uint64 + +func `<`*(x, y: UInt128): bool = + (x.hi < y.hi) or ((x.hi == y.hi) and (x.lo < y.lo)) + +when not defined(works): + func `>`*(x, y: UInt128): bool = + (x.hi > y.hi) or ((x.hi == y.hi) and (x.lo > y.lo)) diff --git a/tests/overload/mvaruintconv.nim b/tests/overload/mvaruintconv.nim new file mode 100644 index 000000000..b889c90cf --- /dev/null +++ b/tests/overload/mvaruintconv.nim @@ -0,0 +1,145 @@ +import + std/[macros, tables, hashes] + +export + macros + +type + FieldDescription* = object + name*: NimNode + isPublic*: bool + isDiscriminator*: bool + typ*: NimNode + pragmas*: NimNode + caseField*: NimNode + caseBranch*: NimNode + +{.push raises: [].} + +func isTuple*(t: NimNode): bool = + t.kind == nnkBracketExpr and t[0].kind == nnkSym and eqIdent(t[0], "tuple") + +macro isTuple*(T: type): untyped = + newLit(isTuple(getType(T)[1])) + +proc collectFieldsFromRecList(result: var seq[FieldDescription], + n: NimNode, + parentCaseField: NimNode = nil, + parentCaseBranch: NimNode = nil, + isDiscriminator = false) = + case n.kind + of nnkRecList: + for entry in n: + collectFieldsFromRecList result, entry, + parentCaseField, parentCaseBranch + of nnkRecWhen: + for branch in n: + case branch.kind: + of nnkElifBranch: + collectFieldsFromRecList result, branch[1], + parentCaseField, parentCaseBranch + of nnkElse: + collectFieldsFromRecList result, branch[0], + parentCaseField, parentCaseBranch + else: + doAssert false + + of nnkRecCase: + collectFieldsFromRecList result, n[0], + parentCaseField, + parentCaseBranch, + isDiscriminator = true + + for i in 1 ..< n.len: + let branch = n[i] + case branch.kind + of nnkOfBranch: + collectFieldsFromRecList result, branch[^1], n[0], branch + of nnkElse: + collectFieldsFromRecList result, branch[0], n[0], branch + else: + doAssert false + + of nnkIdentDefs: + let fieldType = n[^2] + for i in 0 ..< n.len - 2: + var field: FieldDescription + field.name = n[i] + field.typ = fieldType + field.caseField = parentCaseField + field.caseBranch = parentCaseBranch + field.isDiscriminator = isDiscriminator + + if field.name.kind == nnkPragmaExpr: + field.pragmas = field.name[1] + field.name = field.name[0] + + if field.name.kind == nnkPostfix: + field.isPublic = true + field.name = field.name[1] + + result.add field + + of nnkSym: + result.add FieldDescription( + name: n, + typ: getType(n), + caseField: parentCaseField, + caseBranch: parentCaseBranch, + isDiscriminator: isDiscriminator) + + of nnkNilLit, nnkDiscardStmt, nnkCommentStmt, nnkEmpty: + discard + + else: + doAssert false, "Unexpected nodes in recordFields:\n" & n.treeRepr + +proc collectFieldsInHierarchy(result: var seq[FieldDescription], + objectType: NimNode) = + var objectType = objectType + + objectType.expectKind {nnkObjectTy, nnkRefTy} + + if objectType.kind == nnkRefTy: + objectType = objectType[0] + + objectType.expectKind nnkObjectTy + + var baseType = objectType[1] + if baseType.kind != nnkEmpty: + baseType.expectKind nnkOfInherit + baseType = baseType[0] + baseType.expectKind nnkSym + baseType = getImpl(baseType) + baseType.expectKind nnkTypeDef + baseType = baseType[2] + baseType.expectKind {nnkObjectTy, nnkRefTy} + collectFieldsInHierarchy result, baseType + + let recList = objectType[2] + collectFieldsFromRecList result, recList + +proc recordFields*(typeImpl: NimNode): seq[FieldDescription] = + if typeImpl.isTuple: + for i in 1 ..< typeImpl.len: + result.add FieldDescription(typ: typeImpl[i], name: ident("Field" & $(i - 1))) + return + + let objectType = case typeImpl.kind + of nnkObjectTy: typeImpl + of nnkTypeDef: typeImpl[2] + else: + macros.error("object type expected", typeImpl) + return + + collectFieldsInHierarchy(result, objectType) + +macro field*(obj: typed, fieldName: static string): untyped = + newDotExpr(obj, ident fieldName) + +proc skipPragma*(n: NimNode): NimNode = + if n.kind == nnkPragmaExpr: n[0] + else: n + + +{.pop.} diff --git a/tests/overload/t19737.nim b/tests/overload/t19737.nim new file mode 100644 index 000000000..b33ba9d8b --- /dev/null +++ b/tests/overload/t19737.nim @@ -0,0 +1,15 @@ +# issue #19737 + +import ./m19737 + +var m: seq[uint64] + +proc foo(x: bool) = discard + +proc test[T: uint64|uint32](s: var seq[T]) = + var tmp = newSeq[T](1) + s = newSeq[T](1) + + foo s[0] > tmp[0] + +test(m) diff --git a/tests/overload/t23249.nim b/tests/overload/t23249.nim new file mode 100644 index 000000000..f4657833b --- /dev/null +++ b/tests/overload/t23249.nim @@ -0,0 +1,17 @@ +# issue #23249 + +type Control* = object +proc onAction*(c: Control, handler: proc(e: int) {.gcsafe.}) = discard +proc onAction*(c: Control, handler: proc() {.gcsafe.}) = discard + +template setControlHandlerBlock(c: Control, p: untyped, a: untyped) = + when compiles(c.p(nil)): + c.p() do() {.gcsafe.}: a + else: + c.p = proc() {.gcsafe.} = + a + +proc mkLayout() = + var b: Control + setControlHandlerBlock(b, onAction): + echo "hi" diff --git a/tests/overload/t23755.nim b/tests/overload/t23755.nim new file mode 100644 index 000000000..de338a2ce --- /dev/null +++ b/tests/overload/t23755.nim @@ -0,0 +1,62 @@ +type + BigInt[bits: static int] = object + limbs: array[8, uint64] + +block: + proc view[N](a: array[N, uint64]) = + discard + + proc view[N](a: var array[N, uint64]) = + discard + + var r: BigInt[64] + r.limbs.view() + + +type Limbs[N: static int] = array[N, uint64] + +block: + proc view(a: Limbs) = + discard + + proc view(a: var Limbs) = + discard + + var r: BigInt[64] + r.limbs.view() + + +block: + type IntArray[N: static[int]] = array[N, int] + + proc p[T](a: IntArray[T]): bool= true + proc p(a: IntArray[5]): bool= false + + var s: IntArray[5] + doAssert s.p == false + +block: + type IntArray[N: static[int]] = array[N, int] + + proc `$`(a: IntArray): string = + return "test" + + var s: IntArray[5] = [1,1,1,1,1] + doAssert `$`(s) == "test" + +block: + proc p[n:static[int]](a: array[n, char]):bool=true + proc p[T, IDX](a: array[IDX, T]):bool=false + + var g: array[32, char] + doAssert p(g) + +block: # issue #23823 + func p[N,T](a, b: array[N,T]) = + discard + + func p[N: static int; T](x, y: array[N, T]) = + discard + + var a: array[5, int] + p(a,a) diff --git a/tests/overload/t7416.nim b/tests/overload/t7416.nim new file mode 100644 index 000000000..4a9b2e7cb --- /dev/null +++ b/tests/overload/t7416.nim @@ -0,0 +1,9 @@ +type + Foo[T] = object + IntFoo = Foo[int] + +proc bar(b: object|tuple) = discard +proc bar(b: IntFoo) = discard + +var f: IntFoo +bar(f) \ No newline at end of file diff --git a/tests/overload/t8829.nim b/tests/overload/t8829.nim new file mode 100644 index 000000000..85d87f136 --- /dev/null +++ b/tests/overload/t8829.nim @@ -0,0 +1,18 @@ +block: + let txt = "Hello World" + + template `[]`[T](p: ptr T, span: Slice[int]): untyped = + toOpenArray(cast[ptr UncheckedArray[T]](p), span.a, span.b) + + doAssert $cast[ptr uint8](txt[0].addr)[0 ..< txt.len] == + "[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]" + + +block: + let txt = "Hello World" + + template `[]`[T](p: ptr T, span: Slice[int]): untyped = + toOpenArray(cast[ptr UncheckedArray[T]](p), span.a, span.b) + + doAssert $cast[ptr uint8](txt[0].addr)[0 ..< txt.len] == + "[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]" diff --git a/tests/overload/tconverter_to_string.nim b/tests/overload/tconverter_to_string.nim new file mode 100644 index 000000000..1960372d8 --- /dev/null +++ b/tests/overload/tconverter_to_string.nim @@ -0,0 +1,22 @@ +discard """ + output: '''123 +c is not nil''' +""" + +# bug #9149 + +type + Container = ref object + data: int + +converter containerToString*(x: Container): string = $x.data + +var c = Container(data: 123) +var str = string c +echo str + +if c == nil: # this line can compile on v0.18, but not on 0.19 + echo "c is nil" + +if not c.isNil: + echo "c is not nil" diff --git a/tests/overload/tgenericalias.nim b/tests/overload/tgenericalias.nim new file mode 100644 index 000000000..50a44bd32 --- /dev/null +++ b/tests/overload/tgenericalias.nim @@ -0,0 +1,13 @@ +block: # issue #13799 + type + X[A, B] = object + a: A + b: B + + Y[A] = X[A, int] + template s(T: type X): X = T() + template t[A, B](T: type X[A, B]): X[A, B] = T() + proc works1(): Y[int] = s(X[int, int]) + proc works2(): Y[int] = t(X[int, int]) + proc works3(): Y[int] = t(Y[int]) + proc broken(): Y[int] = s(Y[int]) diff --git a/tests/overload/tissue966.nim b/tests/overload/tissue966.nim new file mode 100644 index 000000000..d0a723875 --- /dev/null +++ b/tests/overload/tissue966.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "type mismatch: got <PTest>" +""" + +type + PTest = ref object + +proc test(x: PTest, y: int) = discard + +var buf: PTest +buf.test() + diff --git a/tests/overload/tnamedparamoverloading.nim b/tests/overload/tnamedparamoverloading.nim new file mode 100644 index 000000000..a7c37ba52 --- /dev/null +++ b/tests/overload/tnamedparamoverloading.nim @@ -0,0 +1,14 @@ +discard """ + output: ''' +Using x: 2 +Using y: 2 +''' +""" + +proc foo(x: int) = + echo "Using x: ", x +proc foo(y: int) = + echo "Using y: ", y + +foo(x = 2) +foo(y = 2) \ No newline at end of file diff --git a/tests/overload/tor_isnt_better.nim b/tests/overload/tor_isnt_better.nim new file mode 100644 index 000000000..bee125386 --- /dev/null +++ b/tests/overload/tor_isnt_better.nim @@ -0,0 +1,41 @@ +type + D[T] = object + E[T] = object + +block: # PR #22261 + proc d(x: D):bool= false + proc d(x: int | D[SomeInteger]):bool= true + doAssert d(D[5]()) == false + +block: # bug #8568 +#[ + Since PR #22261 and amendment has been made. Since D is a subset of D | E but + not the other way around `checkGeneric` should favor proc g(a: D) instead + of asserting ambiguity +]# + proc g(a: D|E): string = "foo D|E" + proc g(a: D): string = "foo D" + doAssert g(D[int]()) == "foo D" + +type Obj1[T] = object + v: T +converter toObj1[T](t: T): Obj1[T] = return Obj1[T](v: t) +block: # issue #10019 + proc fun1[T](elements: seq[T]): string = "fun1 seq" + proc fun1(o: object|tuple): string = "fun1 object|tuple" + proc fun2[T](elements: openArray[T]): string = "fun2 openarray" + proc fun2(o: object): string = "fun2 object" + proc fun_bug[T](elements: openArray[T]): string = "fun_bug openarray" + proc fun_bug(o: object|tuple):string = "fun_bug object|tuple" + proc main() = + var x = @["hello", "world"] + block: + # no ambiguity error shown here even though this would compile if we remove either 1st or 2nd overload of fun1 + doAssert fun1(x) == "fun1 seq" + block: + # ditto + doAssert fun2(x) == "fun2 openarray" + block: + # Error: ambiguous call; both t0065.fun_bug(elements: openarray[T])[declared in t0065.nim(17, 5)] and t0065.fun_bug(o: object or tuple)[declared in t0065.nim(20, 5)] match for: (array[0..1, string]) + doAssert fun_bug(x) == "fun_bug openarray" + main() diff --git a/tests/overload/toverl.nim b/tests/overload/toverl.nim new file mode 100644 index 000000000..64257be77 --- /dev/null +++ b/tests/overload/toverl.nim @@ -0,0 +1,11 @@ +discard """ + errormsg: "redefinition of \'TNone\'" + file: "toverl.nim" + line: 11 +""" +# Test for overloading + +type + TNone {.exportc: "_NONE", final.} = object + +proc TNone(a, b: int) = nil #ERROR_MSG attempt to redefine 'TNone' diff --git a/tests/overload/toverl4.nim b/tests/overload/toverl4.nim new file mode 100644 index 000000000..21cedaa96 --- /dev/null +++ b/tests/overload/toverl4.nim @@ -0,0 +1,101 @@ +discard """ + output: '''true +5.0''' +""" + +#bug #592 + +type + ElementKind = enum inner, leaf + TElement[TKey, TData] = object + case kind: ElementKind + of inner: + key: TKey + left, right: ref TElement[Tkey, TData] + of leaf: + data: TData + PElement[TKey, TData] = ref TElement[TKey, TData] + +proc newElement[Tkey, TData](other: PElement[TKey, TData]): PElement[Tkey, TData] = + case other.kind: + of inner: + PElement[TKey, TData](kind: ElementKind.inner, key: other.key, left: other.left, right: other.right) + of leaf: + PElement[TKey, TData](kind: ElementKind.leaf, data: other.data) + +proc newElement[TKey, TData](key: TKey, left: PElement[TKey, TData] = nil, right: PElement[TKey, TData] = nil) : PElement[TKey, TData] = + PElement[TKey, TData](kind: ElementKind.inner, key: key, left: left, right: right) + +proc newElement[Tkey, TData](key: Tkey, data: TData) : PElement[Tkey, TData] = + PElement[TKey, TData](kind: ElementKind.leaf, data: data) + +proc find*[TKey, TData](root: PElement[TKey, TData], key: TKey): TData {.raises: [KeyError].} = + if root.left == nil: + raise newException(KeyError, "key does not exist: " & key) + + var tmp_element = addr(root) + + while tmp_element.kind == inner and tmp_element.right != nil: + tmp_element = if tmp_element.key > key: + addr(tmp_element.left) + else: + addr(tmp_element.right) + + if tmp_element.key == key: + return tmp_element.left.data + else: + raise newException(KeyError, "key does not exist: " & key) + +proc add*[TKey, TData](root: var PElement[TKey, TData], key: TKey, data: TData) : bool = + if root.left == nil: + root.key = key + root.left = newElement[TKey, TData](key, data) + return true + + var tmp_element = addr(root) + + while tmp_element.kind == ElementKind.inner and tmp_element.right != nil: + tmp_element = if tmp_element.key > key: + addr(tmp_element.left) + else: + addr(tmp_element.right) + + if tmp_element.key == key: + return false + + var old_element = newElement[TKey, TData](tmp_element[]) + var new_element = newElement[TKey, TData](key, data) + + tmp_element[] = if tmp_element.key < key: + newElement(key, old_element, new_element) + else: + newElement(tmp_element.key, new_element, old_element) + + return true + +var tree = PElement[int, int](kind: ElementKind.inner, key: 0, left: nil, right: nil) +let result = add(tree, 1, 1) +echo(result) + +# bug #3748 +type + Foo = object + bar: int + +proc bar(cur: Foo, val: int, s:seq[string]) = + discard cur.bar + +proc does_fail(): Foo = + let a = @["a"] + result.bar(5, a) + +doAssert does_fail().bar == 0 + +# bug #20645 + +type Zzz[Gen] = object + +proc testZ(z: Zzz) = + echo z.Gen(5) + +testZ(Zzz[float]()) diff --git a/tests/overload/toverload_issues.nim b/tests/overload/toverload_issues.nim new file mode 100644 index 000000000..26bf89091 --- /dev/null +++ b/tests/overload/toverload_issues.nim @@ -0,0 +1,200 @@ +discard """ + output: ''' +Version 2 was called. +This has the highest precedence. +This has the second-highest precedence. +This has the lowest precedence. +baseobj == +true +even better! == +true +done extraI=0 +test 0 complete, loops=0 +done extraI=1 +test 1.0 complete, loops=1 +done extraI=0 +done extraI passed 0 +test no extra complete, loops=2 +1 +''' +""" + + +# issue 4675 +import importA # comment this out to make it work +import importB + +var x: Foo[float] +var y: Foo[float] +let r = t1(x) + t2(y) + + + +# Bug: https://github.com/nim-lang/Nim/issues/4475 +# Fix: https://github.com/nim-lang/Nim/pull/4477 +proc test(x: varargs[string], y: int) = discard +test(y = 1) + + + +# bug #2220 +when true: + type A[T] = object + type B = A[int] + + proc q[X](x: X) = + echo "Version 1 was called." + + proc q(x: B) = + echo "Version 2 was called." + + q(B()) # This call reported as ambiguous. + + + +# bug #2219 +template testPred(a: untyped) = + block: + type A = object of RootObj + type B = object of A + type SomeA = A|A # A hack to make "A" a typeclass. + + when a >= 3: + proc p[X: A](x: X) = + echo "This has the highest precedence." + when a == 2: + proc p[X: SomeA](x: X) = + echo "This has the second-highest precedence." + when a >= 1: + proc p[X](x: X) = + echo "This has the lowest precedence." + + p(B()) + +testPred(3) +testPred(2) +testPred(1) + + + +block: # bug #6526 + type + BaseObj = ref object of RootObj + DerivedObj = ref object of BaseObj + OtherDerivate = ref object of BaseObj + + proc p[T](a: T, b: T): bool = + assert false + + proc p[T1, T2: BaseObj](a: T1, b: T2): bool = + echo "baseobj ==" + return true + + let a = DerivedObj() + let b = DerivedObj() + echo p(a,b) + + proc p[T1, T2: OtherDerivate](a: T1, b: T2): bool = + echo "even better! ==" + return true + + let a2 = OtherDerivate() + let b2 = OtherDerivate() + echo p(a2, b2) + + + +# bug #2481 +import math + +template test(loopCount: int, extraI: int, testBody: untyped): typed = + block: + for i in 0..loopCount-1: + testBody + echo "done extraI=", extraI + +template test(loopCount: int, extraF: float, testBody: untyped): typed = + block: + test(loopCount, round(extraF).int, testBody) + +template test(loopCount: int, testBody: untyped): typed = + block: + test(loopCount, 0, testBody) + echo "done extraI passed 0" + +var + loops = 0 + +test 0, 0: + loops += 1 +echo "test 0 complete, loops=", loops + +test 1, 1.0: + loops += 1 +echo "test 1.0 complete, loops=", loops + +when true: + # when true we get the following compile time error: + # b.nim(35, 6) Error: expression 'loops += 1' has no type (or is ambiguous) + loops = 0 + test 2: + loops += 1 + echo "test no extra complete, loops=", loops + +# bug #2229 +type + Type1 = object + id: int + Type2 = object + id: int + +proc init(self: var Type1, a: int, b: ref Type2) = + echo "1" + +proc init(self: var Type2, a: int) = + echo """ + Works when this proc commented out + Otherwise error: + test.nim(14, 4) Error: ambiguous call; both test.init(self: var Type1, a: int, b: ref Type2) and test.init(self: var Type1, a: int, b: ref Type2) match for: (Type1, int literal(1), ref Type2) + """ + +var aa: Type1 +init(aa, 1, ( + var bb = new(Type2); + bb +)) + + + +# bug #4545 +type + SomeObject = object + a: int + AbstractObject = object + objet: ptr SomeObject + +proc convert(this: var SomeObject): AbstractObject = + AbstractObject(objet: this.addr) + +proc varargProc(args: varargs[AbstractObject, convert]): int = + for arg in args: + result += arg.objet.a + +var obj = SomeObject(a: 17) +discard varargProc(obj) + + + +# bug #11239 + +type MySeq*[T] = object + +proc foo(a: seq[int]): string = "foo: seq[int]" +proc foo[T](a: seq[T]): string = "foo: seq[T]" +proc foo(a: MySeq[int]): string = "foo: MySeq[int]" +proc foo[T](a: MySeq[T]): string = "foo: MySeq[T]" + +doAssert foo(@[1,2,3]) == "foo: seq[int]" +doAssert foo(@["WER"]) == "foo: seq[T]" +doAssert foo(MySeq[int]()) == "foo: MySeq[int]" +doAssert foo(MySeq[string]()) == "foo: MySeq[T]" diff --git a/tests/overload/toverload_various.nim b/tests/overload/toverload_various.nim new file mode 100644 index 000000000..d195a069d --- /dev/null +++ b/tests/overload/toverload_various.nim @@ -0,0 +1,568 @@ +discard """ + output: ''' +true012innertrue +m1 +tup1 +another number: 123 +yay +helloa 1 b 2 x @[3, 4, 5] y 6 z 7 +yay +12 +ref ref T ptr S +dynamic: let +dynamic: var +static: const +static: literal +static: constant folding +static: static string +foo1 +1 +''' +""" + + +import strutils, sequtils + + +block overl2: + # Test new overloading resolution rules + proc toverl2(x: int): string = return $x + proc toverl2(x: bool): string = return $x + + iterator toverl2(x: int): int = + var res = 0 + while res < x: + yield res + inc(res) + + var + pp: proc (x: bool): string {.nimcall.} = toverl2 + + stdout.write(pp(true)) + + for x in toverl2(3): + stdout.write(toverl2(x)) + + block: + proc toverl2(x: int): string = return "inner" + stdout.write(toverl2(5)) + stdout.write(true) + + stdout.write("\n") + #OUT true012innertrue + + + +block overl3: + # Tests more specific generic match: + proc m[T](x: T) = echo "m2" + proc m[T](x: var ref T) = echo "m1" + proc tup[S, T](x: tuple[a: S, b: ref T]) = echo "tup1" + proc tup[S, T](x: tuple[a: S, b: T]) = echo "tup2" + + var + obj: ref int + tu: tuple[a: int, b: ref bool] + + m(obj) + tup(tu) + + + +block toverprc: + # Test overloading of procs when used as function pointers + proc parseInt(x: float): int {.noSideEffect.} = discard + proc parseInt(x: bool): int {.noSideEffect.} = discard + proc parseInt(x: float32): int {.noSideEffect.} = discard + proc parseInt(x: int8): int {.noSideEffect.} = discard + proc parseInt(x: File): int {.noSideEffect.} = discard + proc parseInt(x: char): int {.noSideEffect.} = discard + proc parseInt(x: int16): int {.noSideEffect.} = discard + + proc parseInt[T](x: T): int = echo x; 34 + + type + TParseInt = proc (x: string): int {.noSideEffect.} + + var + q = TParseInt(parseInt) + p: TParseInt = parseInt + + proc takeParseInt(x: proc (y: string): int {.noSideEffect.}): int = + result = x("123") + + if false: + echo "Give a list of numbers (separated by spaces): " + var x = stdin.readline.split.map(parseInt).max + echo x, " is the maximum!" + echo "another number: ", takeParseInt(parseInt) + + + type + TFoo[a,b] = object + lorem: a + ipsum: b + + proc bar[a,b](f: TFoo[a,b], x: a) = echo(x, " ", f.lorem, f.ipsum) + proc bar[a,b](f: TFoo[a,b], x: b) = echo(x, " ", f.lorem, f.ipsum) + + discard parseInt[string]("yay") + + + +block toverwr: + # Test the overloading resolution in connection with a qualifier + proc write(t: File, s: string) = + discard # a nop + system.write(stdout, "hello") + #OUT hello + + + +block tparams_after_varargs: + proc test(a, b: int, x: varargs[int]; y, z: int) = + echo "a ", a, " b ", b, " x ", @x, " y ", y, " z ", z + + test 1, 2, 3, 4, 5, 6, 7 + + # XXX maybe this should also work with ``varargs[untyped]`` + template takesBlockA(a, b: untyped; x: varargs[typed]; blck: untyped): untyped = + blck + echo a, b + + takesBlockA 1, 2, "some", 0.90, "random stuff": + echo "yay" + + + +block tprefer_specialized_generic: + proc foo[T](x: T) = + echo "only T" + + proc foo[T](x: ref T) = + echo "ref T" + + proc foo[T, S](x: ref ref T; y: ptr S) = + echo "ref ref T ptr S" + + proc foo[T, S](x: ref T; y: ptr S) = + echo "ref T ptr S" + + proc foo[T](x: ref T; default = 0) = + echo "ref T; default" + + var x: ref ref int + var y: ptr ptr int + foo(x, y) + + + +block tstaticoverload: + proc foo(s: string) = + echo "dynamic: ", s + + proc foo(s: static[string]) = + echo "static: ", s + + let l = "let" + var v = "var" + const c = "const" + + type staticString = static[string] + + foo(l) + foo(v) + foo(c) + foo("literal") + foo("constant" & " " & "folding") + foo(staticString("static string")) + +# bug #8568 (2) + +proc goo(a: int): string = "int" +proc goo(a: static[int]): string = "static int" +proc goo(a: var int): string = "var int" +proc goo[T: int](a: T): string = "T: int" +#proc goo[T](a: T): string = "nur T" + +const tmp1 = 1 +let tmp2 = 1 +var tmp3 = 1 + +doAssert goo(1) == "static int" +doAssert goo(tmp1) == "static int" +doAssert goo(tmp2) == "int" +doAssert goo(tmp3) == "var int" + +doAssert goo[int](1) == "T: int" + +doAssert goo[int](tmp1) == "T: int" +doAssert goo[int](tmp2) == "T: int" +doAssert goo[int](tmp3) == "T: int" + +# bug #6076 + +type A[T] = object + +proc regr(a: A[void]) = echo "foo1" +proc regr[T](a: A[T]) = doAssert(false) + +regr(A[void]()) + + +type Foo[T] = object + +proc regr[T](p: Foo[T]): seq[T] = + discard + +proc regr(p: Foo[void]): seq[int] = + discard + + +discard regr(Foo[int]()) +discard regr(Foo[void]()) + + +type + Sha2Context*[bits: static[int], + bsize: static[int], + T: uint32|uint64] = object + count: array[2, T] + state: array[8, T] + buffer: array[bsize, byte] + + sha224* = Sha2Context[224, 64, uint32] + sha256* = Sha2Context[256, 64, uint32] + sha384* = Sha2Context[384, 128, uint64] + sha512* = Sha2Context[512, 128, uint64] + sha512_224* = Sha2Context[224, 128, uint64] + sha512_256* = Sha2Context[256, 128, uint64] + +type + RipemdContext*[bits: static[int]] = object + count: array[2, uint32] + state: array[bits div 32, uint32] + buffer: array[64, byte] + + ripemd128* = RipemdContext[128] + ripemd160* = RipemdContext[160] + ripemd256* = RipemdContext[256] + ripemd320* = RipemdContext[320] + +const + MaxHmacBlockSize = 256 + +type + HMAC*[HashType] = object + mdctx: HashType + opadctx: HashType + +template sizeBlock*(h: HMAC[Sha2Context]): uint = 1u +template sizeBlock*(h: HMAC[RipemdContext]): uint = 0u + +proc init*[T](hmctx: HMAC[T], key: ptr byte, ulen: uint) = + const sizeBlock = hmctx.sizeBlock + echo sizeBlock + +proc hmac*[A, B](HashType: typedesc, key: openArray[A], + data: openArray[B]) = + var ctx: HMAC[HashType] + ctx.init(nil, 0) + +sha256.hmac("", "") + + + +# nested generic types +block: + type + Foo[T] = object + f: T + Bar[T] = object + b: T + Baz[T] = object + z: T + FooBar[T] = Foo[Bar[T]] + FooBarBaz[T] = FooBar[Baz[T]] + #Int = int + Int = SomeInteger + FooBarBazInt = FooBarBaz[Int] + FooBarBazX = FooBarBaz[int] + + proc p00(x: Foo): auto = x.f + proc p01[T](x: Foo[T]): auto = x.f + proc p02[T:Foo](x: T): auto = x.f + + proc p10(x: FooBar): auto = x.f + proc p11[T](x: FooBar[T]): auto = x.f + proc p12[T:FooBar](x: T): auto = x.f + proc p13(x: Foo[Bar]): auto = x.f + proc p14[T](x: Foo[Bar[T]]): auto = x.f + proc p15[T:Bar](x: Foo[T]): auto = x.f + proc p16[T:Foo[Bar]](x: T): auto = x.f + + proc p20(x: FooBarBaz): auto = x.f + proc p21[T](x: FooBarBaz[T]): auto = x.f + proc p22[T:FooBarBaz](x: T): auto = x.f + proc p23(x: FooBar[Baz]): auto = x.f + proc p24[T](x: FooBar[Baz[T]]): auto = x.f + proc p25[T:Baz](x: FooBar[T]): auto = x.f + proc p26[T:FooBar[Baz]](x: T): auto = x.f + proc p27(x: Foo[Bar[Baz]]): auto = x.f + proc p28[T](x: Foo[Bar[Baz[T]]]): auto = x.f + proc p29[T:Baz](x: Foo[Bar[T]]): auto = x.f + proc p2A[T:Bar[Baz]](x: Foo[T]): auto = x.f + proc p2B[T:Foo[Bar[Baz]]](x: T): auto = x.f + + proc p30(x: FooBarBazInt): auto = x.f + proc p31[T:FooBarBazInt](x: T): auto = x.f + proc p32(x: FooBarBaz[Int]): auto = x.f + proc p33[T:Int](x: FooBarBaz[T]): auto = x.f + proc p34[T:FooBarBaz[Int]](x: T): auto = x.f + proc p35(x: FooBar[Baz[Int]]): auto = x.f + proc p36[T:Int](x: FooBar[Baz[T]]): auto = x.f + proc p37[T:Baz[Int]](x: FooBar[T]): auto = x.f + proc p38[T:FooBar[Baz[Int]]](x: T): auto = x.f + proc p39(x: Foo[Bar[Baz[Int]]]): auto = x.f + proc p3A[T:Int](x: Foo[Bar[Baz[T]]]): auto = x.f + proc p3B[T:Baz[Int]](x: Foo[Bar[T]]): auto = x.f + proc p3C[T:Bar[Baz[Int]]](x: Foo[T]): auto = x.f + proc p3D[T:Foo[Bar[Baz[Int]]]](x: T): auto = x.f + + template test(x: typed) = + let t00 = p00(x) + let t01 = p01(x) + let t02 = p02(x) + let t10 = p10(x) + let t11 = p11(x) + let t12 = p12(x) + #let t13 = p13(x) + let t14 = p14(x) + #let t15 = p15(x) + #let t16 = p16(x) + let t20 = p20(x) + let t21 = p21(x) + let t22 = p22(x) + #let t23 = p23(x) + let t24 = p24(x) + #let t25 = p25(x) + #let t26 = p26(x) + #let t27 = p27(x) + let t28 = p28(x) + #let t29 = p29(x) + #let t2A = p2A(x) + #let t2B = p2B(x) + let t30 = p30(x) + let t31 = p31(x) + let t32 = p32(x) + let t33 = p33(x) + let t34 = p34(x) + let t35 = p35(x) + let t36 = p36(x) + let t37 = p37(x) + let t38 = p38(x) + let t39 = p39(x) + let t3A = p3A(x) + let t3B = p3B(x) + let t3C = p3C(x) + let t3D = p3D(x) + + var a: Foo[Bar[Baz[int]]] + test(a) + var b: FooBar[Baz[int]] + test(b) + var c: FooBarBaz[int] + test(c) + var d: FooBarBazX + test(d) + + +# overloading on tuples with generic alias +block: + type + Foo[F,T] = object + exArgs: T + FooUn[F,T] = Foo[F,tuple[a:T]] + FooBi[F,T1,T2] = Foo[F,tuple[a:T1,b:T2]] + + proc foo1[F,T](x: Foo[F,tuple[a:T]]): int = 1 + proc foo1[F,T1,T2](x: Foo[F,tuple[a:T1,b:T2]]): int = 2 + proc foo2[F,T](x: FooUn[F,T]): int = 1 + proc foo2[F,T1,T2](x: FooBi[F,T1,T2]):int = 2 + + template bar1[F,T](x: Foo[F,tuple[a:T]]): int = 1 + template bar1[F,T1,T2](x: Foo[F,tuple[a:T1,b:T2]]): int = 2 + template bar2[F,T](x: FooUn[F,T]): int = 1 + template bar2[F,T1,T2](x: FooBi[F,T1,T2]): int = 2 + + proc test(x: auto, n: int) = + doAssert(foo1(x) == n) + doAssert(foo2(x) == n) + doAssert(bar1(x) == n) + doAssert(bar2(x) == n) + + var a: Foo[int, tuple[a:int]] + test(a, 1) + var b: FooUn[int, int] + test(b, 1) + var c: Foo[int, tuple[a:int,b:int]] + test(c, 2) + var d: FooBi[int, int, int] + test(d, 2) + + +# inheritance and generics +block: + type + Foo[T] = object of RootObj + x: T + Bar[T] = object of Foo[T] + y: T + Baz[T] = object of Bar[T] + z: T + + template t0(x: Foo[int]): int = 0 + template t0(x: Bar[int]): int = 1 + template t0(x: Foo[bool or int]): int = 10 + template t0(x: Bar[bool or int]): int = 11 + #template t0[T:bool or int](x: Bar[T]): int = 11 + template t0[T](x: Foo[T]): int = 20 + template t0[T](x: Bar[T]): int = 21 + proc p0(x: Foo[int]): int = 0 + proc p0(x: Bar[int]): int = 1 + #proc p0(x: Foo[bool or int]): int = 10 + #proc p0(x: Bar[bool or int]): int = 11 + proc p0[T](x: Foo[T]): int = 20 + proc p0[T](x: Bar[T]): int = 21 + + var a: Foo[int] + var b: Bar[int] + var c: Baz[int] + var d: Foo[bool] + var e: Bar[bool] + var f: Baz[bool] + var g: Foo[float] + var h: Bar[float] + var i: Baz[float] + doAssert(t0(a) == 0) + doAssert(t0(b) == 1) + doAssert(t0(c) == 1) + doAssert(t0(d) == 10) + doAssert(t0(e) == 11) + doAssert(t0(f) == 11) + doAssert(t0(g) == 20) + doAssert(t0(h) == 21) + #doAssert(t0(i) == 21) + doAssert(p0(a) == 0) + doAssert(p0(b) == 1) + doAssert(p0(c) == 1) + #doAssert(p0(d) == 10) + #doAssert(p0(e) == 11) + #doAssert(p0(f) == 11) + doAssert(p0(g) == 20) + doAssert(p0(h) == 21) + doAssert(p0(i) == 21) + + #type + # f0 = proc(x:Foo) + + +block: + type + TilesetCT[n: static[int]] = distinct int + TilesetRT = int + Tileset = TilesetCT | TilesetRT + + func prepareTileset(tileset: var Tileset) = discard + + func prepareTileset(tileset: Tileset): Tileset = + result = tileset + result.prepareTileset + + var parsedTileset: TilesetRT + prepareTileset(parsedTileset) + + +block: + proc p1[T,U: SomeInteger|SomeFloat](x: T, y: U): int|float = + when T is SomeInteger and U is SomeInteger: + result = int(x) + int(y) + else: + result = float(x) + float(y) + doAssert(p1(1,2) == 3) + doAssert(p1(1.0,2) == 3.0) + doAssert(p1(1,2.0) == 3.0) + doAssert(p1(1.0,2.0) == 3.0) + + type Foo[T,U] = U + template F[T,U](t: typedesc[T], x: U): untyped = Foo[T,U](x) + proc p2[T; U,V:Foo[T,SomeNumber]](x: U, y: V): T = + T(x) + T(y) + #proc p2[T; U:Foo[T,SomeNumber], V:Foo[not T,SomeNumber]](x: U, y: V): T = + # T(x) + T(y) + doAssert(p2(F(int,1),F(int,2)) == 3) + doAssert(p2(F(float,1),F(float,2)) == 3.0) + doAssert(p2(F(float,1),F(float,2.0)) == 3.0) + doAssert(p2(F(float,1.0),F(float,2)) == 3.0) + doAssert(p2(F(float,1.0),F(float,2.0)) == 3.0) + #doAssert(p2(F(float,1),F(int,2.0)) == 3.0) + +block: # PR #23870 + type + A {.inheritable.} = object + B = object of A + C = object of B + + proc p[T: A](x: T): int = 0 + proc p[T: B](x: T): int = 1 + + proc d(x: A): int = 0 + proc d(x: B): int = 1 + + proc g[T:A](x: typedesc[T]): int = 0 + proc g[T: B](x: typedesc[T]): int = 1 + + proc f[T](x: typedesc[T]): int = 0 + proc f[T:B](x: typedesc[T]): int = 1 + + assert p(C()) == 1 + assert d(C()) == 1 + assert g(C) == 1 + assert f(C) == 1 + +block: # PR #23870 + type + A = object of RootObj + PT = proc(ev: A) {.closure.} + sdt = seq[(PT, PT)] + + proc encap() = + proc p(a: A) {.closure.} = + discard + + var s: sdt + s.add (p, nil) + + encap() + +block: # PR #23870 + type + A = object of RootObj + B = object of A + C = object of B + + proc p(a: B | RootObj): int = + 0 + + proc p(a: A | A): int = + 1 + + assert p(C()) == 0 + + proc d(a: RootObj | B): int = + 0 + + proc d(a: A | A): int = + 1 + + assert d(C()) == 0 diff --git a/tests/overload/tparam_forwarding.nim b/tests/overload/tparam_forwarding.nim new file mode 100644 index 000000000..b0eea42c7 --- /dev/null +++ b/tests/overload/tparam_forwarding.nim @@ -0,0 +1,53 @@ +discard """ +output: '''baz +10 +100 +1000 +a +b +c +x: 1, y: test 1 +x: 2, y: test 2 +x: 10, y: test 3 +x: 4, y: test 4 +''' +""" + +type + Foo = object + x: int + +proc stringVarargs*(strings: varargs[string, `$`]): void = + for s in strings: echo s + +proc fooVarargs*(foos: varargs[Foo]) = + for f in foos: echo f.x + +template templateForwarding*(callable: untyped, + condition: bool, + forwarded: varargs[untyped]): untyped = + if condition: + callable(forwarded) + +proc procForwarding(args: varargs[string]) = + stringVarargs(args) + +templateForwarding stringVarargs, 17 + 4 < 21, "foo", "bar", 100 +templateForwarding stringVarargs, 10 < 21, "baz" + +templateForwarding fooVarargs, "test".len > 3, Foo(x: 10), Foo(x: 100), Foo(x: 1000) + +procForwarding "a", "b", "c" + +proc hasKeywordArgs(x = 10, y = "y") = + echo "x: ", x, ", y: ", y + +proc hasRegularArgs(x: int, y: string) = + echo "x: ", x, ", y: ", y + +templateForwarding(hasRegularArgs, true, 1, "test 1") +templateForwarding hasKeywordArgs, true, 2, "test 2" + +templateForwarding(hasKeywordArgs, true, y = "test 3") +templateForwarding hasKeywordArgs, true, y = "test 4", x = 4 + diff --git a/tests/overload/tproc_types_dont_like_subtypes.nim b/tests/overload/tproc_types_dont_like_subtypes.nim new file mode 100644 index 000000000..6774be156 --- /dev/null +++ b/tests/overload/tproc_types_dont_like_subtypes.nim @@ -0,0 +1,20 @@ +discard """ + errormsg: "got <B, proc (b: B){.closure, gcsafe.}>" + line: 20 +""" + +type + A = ref object of RootObj + B = ref object of A + + P = proc (a: A) + +# bug #16325 + +proc doThings(a: A, p: P) = + p(a) + +var x = proc (b: B) {.closure.} = + echo "B" + +doThings(B(), x) diff --git a/tests/overload/tspec.nim b/tests/overload/tspec.nim new file mode 100644 index 000000000..a84bac244 --- /dev/null +++ b/tests/overload/tspec.nim @@ -0,0 +1,118 @@ +discard """ + output: '''not a var +not a var +a var +B +int +T +int16 +T +ref T +123 +2 +1 +@[123, 2, 1] +Called! +merge with var +merge no var''' +""" + +# Things that's even in the spec now! + +proc byvar(x: var int) = echo "a var" +proc byvar(x: int) = echo "not a var" +byvar(89) + +let letSym = 0 +var varSym = 13 + +byvar(letSym) +byvar(varSym) + +type + A = object of RootObj + B = object of A + C = object of B + +proc p(obj: A) = + echo "A" + +proc p(obj: B) = + echo "B" + +var c = C() +# not ambiguous, calls 'B', not 'A' since B is a subtype of A +# but not vice versa: +p(c) + +proc pp(obj: A, obj2: B) = echo "A B" +proc pp(obj: B, obj2: A) = echo "B A" + +# but this is ambiguous: +#pp(c, c) + +proc takesInt(x: int) = echo "int" +proc takesInt[T](x: T) = echo "T" +proc takesInt(x: int16) = echo "int16" + +takesInt(4) # "int" +var x: int32 +takesInt(x) # "T" +var y: int16 +takesInt(y) # "int16" +var z: range[0..4] = 0 +takesInt(z) # "T" + +proc gen[T](x: ref ref T) = echo "ref ref T" +proc gen[T](x: ref T) = echo "ref T" +proc gen[T](x: T) = echo "T" + +var ri: ref int +gen(ri) # "ref T" + + +template rem(x) = discard +#proc rem[T](x: T) = discard + +rem unresolvedExpression(undeclaredIdentifier) + + +proc takeV[T](a: varargs[T]) = + for x in a: echo x + +takeV([123, 2, 1]) # takeV's T is "int", not "array of int" +echo(@[123, 2, 1]) + +# bug #2600 + +type + FutureBase* = ref object of RootObj ## Untyped future. + + Future*[T] = ref object of FutureBase ## Typed future. + value: T ## Stored value + + FutureVar*[T] = distinct Future[T] + +proc newFuture*[T](): Future[T] = + new(result) + +proc newFutureVar*[T](): FutureVar[T] = + result = FutureVar[T](newFuture[T]()) + +proc mget*[T](future: FutureVar[T]): var T = + Future[T](future).value + +proc reset*[T](future: FutureVar[T]) = + echo "Called!" + +proc merge[T](x: Future[T]) = echo "merge no var" +proc merge[T](x: var Future[T]) = echo "merge with var" + +when true: + var foo = newFutureVar[string]() + foo.mget() = "" + foo.mget.add("Foobar") + foo.reset() + var bar = newFuture[int]() + bar.merge # merge with var + merge(newFuture[int]()) # merge no var diff --git a/tests/overload/tstatic_with_converter.nim b/tests/overload/tstatic_with_converter.nim new file mode 100644 index 000000000..2bc1dfaab --- /dev/null +++ b/tests/overload/tstatic_with_converter.nim @@ -0,0 +1,48 @@ +discard """ +output: ''' +9.0 +''' +""" + +### bug #6773 + +{.emit: """ /*INCLUDESECTION*/ +typedef double cimported; + +cimported set1_imported(double x) { + return x; +} + +"""} + +type vfloat{.importc: "cimported".} = object + +proc set1(a: float): vfloat {.importc: "set1_imported".} + +converter scalar_to_vector(x: float): vfloat = + set1(x) + +proc sqrt(x: vfloat): vfloat = + x + +proc pow(x, y: vfloat): vfloat = + y + +proc `^`(x: vfloat, exp: static[int]): vfloat = + when exp == 0: + 1.0 + else: + x + +proc `^`(x: vfloat, exp: static[float]): vfloat = + when exp == 0.5: + sqrt(x) + else: + pow(x, exp) + +proc `$`(x: vfloat): string = + let y = cast[ptr float](addr x) + result = $y[] + +let x = set1(9.0) +echo x^0.5 diff --git a/tests/overload/tsystemcmp.nim b/tests/overload/tsystemcmp.nim new file mode 100644 index 000000000..aa761b759 --- /dev/null +++ b/tests/overload/tsystemcmp.nim @@ -0,0 +1,24 @@ +discard """ + cmd: r"nim c --hints:on $options --threads:on $file" + output: '''@["", "a", "ha", "hi", "ho", "huu"]''' +""" + +import algorithm + +# bug #1657 +var modules = @["hi", "ho", "", "a", "ha", "huu"] +sort(modules, system.cmp) +echo modules + +type + MyType = object + x: string + +proc cmp(a, b: MyType): int = cmp(a.x, b.x) + +var modulesB = @[MyType(x: "ho"), MyType(x: "ha")] +sort(modulesB, cmp) + +# bug #2397 + +proc f(x: (proc(a,b: string): int) = system.cmp) = discard diff --git a/tests/overload/tuntypedarg.nim b/tests/overload/tuntypedarg.nim new file mode 100644 index 000000000..9aa4fad3b --- /dev/null +++ b/tests/overload/tuntypedarg.nim @@ -0,0 +1,19 @@ +import macros + +block: # issue #7385 + type CustomSeq[T] = object + data: seq[T] + macro `[]`[T](s: CustomSeq[T], args: varargs[untyped]): untyped = + ## The end goal is to replace the joker "_" by something else + result = newIntLitNode(10) + proc foo1(): CustomSeq[int] = + result.data.newSeq(10) + # works since no overload matches first argument with type `CustomSeq` + # except magic `[]`, which always matches without checking arguments + doAssert result[_] == 10 + doAssert foo1() == CustomSeq[int](data: newSeq[int](10)) + proc foo2[T](): CustomSeq[T] = + result.data.newSeq(10) + # works fine with generic return type + doAssert result[_] == 10 + doAssert foo2[int]() == CustomSeq[int](data: newSeq[int](10)) diff --git a/tests/overload/tvartypeclass.nim b/tests/overload/tvartypeclass.nim new file mode 100644 index 000000000..04f3f5a91 --- /dev/null +++ b/tests/overload/tvartypeclass.nim @@ -0,0 +1,11 @@ +# issue #13302 + +proc foo(x: object): int = x.i*2 +proc foo(x: var object) = x.i*=2 +type Foo = object + i: int +let x = Foo(i: 3) +var y = Foo(i: 4) +doAssert foo(x) == 6 +foo(y) +doAssert y.i == 8 diff --git a/tests/overload/tvaruintconv.nim b/tests/overload/tvaruintconv.nim new file mode 100644 index 000000000..87ebd285d --- /dev/null +++ b/tests/overload/tvaruintconv.nim @@ -0,0 +1,207 @@ +discard """ + action: compile +""" + +# https://github.com/status-im/nimbus-eth2/pull/6554#issuecomment-2354977102 +# failed with "for a 'var' type a variable needs to be passed; but 'uint64(result)' is immutable" + +import + std/[typetraits, macros] + +type + DefaultFlavor = object + +template serializationFormatImpl(Name: untyped) {.dirty.} = + type Name = object + +template serializationFormat(Name: untyped) = + serializationFormatImpl(Name) + +template setReader(Format, FormatReader: distinct type) = + when arity(FormatReader) > 1: + template Reader(T: type Format, F: distinct type = DefaultFlavor): type = FormatReader[F] + else: + template ReaderType(T: type Format): type = FormatReader + template Reader(T: type Format): type = FormatReader + +template useDefaultReaderIn(T: untyped, Flavor: type) = + mixin Reader + + template readValue(r: var Reader(Flavor), value: var T) = + mixin readRecordValue + readRecordValue(r, value) + +import mvaruintconv + +type + FieldTag[RecordType: object; fieldName: static string] = distinct void + +func declval*(T: type): T {.compileTime.} = + default(ptr T)[] + +macro enumAllSerializedFieldsImpl(T: type, body: untyped): untyped = + var typeAst = getType(T)[1] + var typeImpl: NimNode + let isSymbol = not typeAst.isTuple + + if not isSymbol: + typeImpl = typeAst + else: + typeImpl = getImpl(typeAst) + result = newStmtList() + + var i = 0 + for field in recordFields(typeImpl): + let + fieldIdent = field.name + realFieldName = newLit($fieldIdent.skipPragma) + fieldName = realFieldName + fieldIndex = newLit(i) + + let fieldNameDefs = + if isSymbol: + quote: + const fieldName {.inject, used.} = `fieldName` + const realFieldName {.inject, used.} = `realFieldName` + else: + quote: + const fieldName {.inject, used.} = $`fieldIndex` + const realFieldName {.inject, used.} = $`fieldIndex` + + let field = + if isSymbol: + quote do: declval(`T`).`fieldIdent` + else: + quote do: declval(`T`)[`fieldIndex`] + + result.add quote do: + block: + `fieldNameDefs` + + template FieldType: untyped {.inject, used.} = typeof(`field`) + + `body` + + # echo repr(result) + +template enumAllSerializedFields(T: type, body): untyped = + enumAllSerializedFieldsImpl(T, body) + +type + FieldReader[RecordType, Reader] = tuple[ + fieldName: string, + reader: proc (rec: var RecordType, reader: var Reader) + {.gcsafe, nimcall.} + ] + +proc totalSerializedFieldsImpl(T: type): int = + mixin enumAllSerializedFields + enumAllSerializedFields(T): inc result + +template totalSerializedFields(T: type): int = + (static(totalSerializedFieldsImpl(T))) + +template GetFieldType(FT: type FieldTag): type = + typeof field(declval(FT.RecordType), FT.fieldName) + +proc makeFieldReadersTable(RecordType, ReaderType: distinct type, + numFields: static[int]): + array[numFields, FieldReader[RecordType, ReaderType]] = + mixin enumAllSerializedFields, handleReadException + var idx = 0 + + enumAllSerializedFields(RecordType): + proc readField(obj: var RecordType, reader: var ReaderType) + {.gcsafe, nimcall.} = + + mixin readValue + + type F = FieldTag[RecordType, realFieldName] + field(obj, realFieldName) = reader.readValue(GetFieldType(F)) + + result[idx] = (fieldName, readField) + inc idx + +proc fieldReadersTable(RecordType, ReaderType: distinct type): auto = + mixin readValue + type T = RecordType + const numFields = totalSerializedFields(T) + var tbl {.threadvar.}: ref array[numFields, FieldReader[RecordType, ReaderType]] + if tbl == nil: + tbl = new typeof(tbl) + tbl[] = makeFieldReadersTable(RecordType, ReaderType, numFields) + return addr(tbl[]) + +proc readValue(reader: var auto, T: type): T = + mixin readValue + reader.readValue(result) + +template decode(Format: distinct type, + input: string, + RecordType: distinct type): auto = + mixin Reader + block: # https://github.com/nim-lang/Nim/issues/22874 + var reader: Reader(Format) + reader.readValue(RecordType) + +template readValue(Format: type, + ValueType: type): untyped = + mixin Reader, init, readValue + var reader: Reader(Format) + readValue reader, ValueType + +template parseArrayImpl(numElem: untyped, + actionValue: untyped) = + actionValue + +serializationFormat Json +template createJsonFlavor(FlavorName: untyped, + skipNullFields = false) {.dirty.} = + type FlavorName = object + + template Reader(T: type FlavorName): type = Reader(Json, FlavorName) +type + JsonReader[Flavor = DefaultFlavor] = object + +Json.setReader JsonReader + +template parseArray(r: var JsonReader; body: untyped) = + parseArrayImpl(idx): body + +template parseArray(r: var JsonReader; idx: untyped; body: untyped) = + parseArrayImpl(idx): body + +proc readRecordValue[T](r: var JsonReader, value: var T) = + type + ReaderType {.used.} = type r + T = type value + + discard T.fieldReadersTable(ReaderType) + +proc readValue[T](r: var JsonReader, value: var T) = + mixin readValue + + when value is seq: + r.parseArray: + readValue(r, value[0]) + + elif value is object: + readRecordValue(r, value) + +type + RemoteSignerInfo = object + id: uint32 + RemoteKeystore = object + +proc readValue(reader: var JsonReader, value: var RemoteKeystore) = + discard reader.readValue(seq[RemoteSignerInfo]) + +createJsonFlavor RestJson +useDefaultReaderIn(RemoteSignerInfo, RestJson) +proc readValue(reader: var JsonReader[RestJson], value: var uint64) = + discard reader.readValue(string) + +discard Json.decode("", RemoteKeystore) +block: # https://github.com/nim-lang/Nim/issues/22874 + var reader: Reader(RestJson) + discard reader.readValue(RemoteSignerInfo) |