diff options
Diffstat (limited to 'tests/overload')
-rw-r--r-- | tests/overload/m19737.nim | 10 | ||||
-rw-r--r-- | tests/overload/mvaruintconv.nim | 145 | ||||
-rw-r--r-- | tests/overload/t19737.nim | 15 | ||||
-rw-r--r-- | tests/overload/t23755.nim | 62 | ||||
-rw-r--r-- | tests/overload/t8829.nim | 4 | ||||
-rw-r--r-- | tests/overload/tgenericalias.nim | 13 | ||||
-rw-r--r-- | tests/overload/tor_isnt_better.nim | 23 | ||||
-rw-r--r-- | tests/overload/toverload_issues.nim | 45 | ||||
-rw-r--r-- | tests/overload/toverload_various.nim | 60 | ||||
-rw-r--r-- | tests/overload/tuntypedarg.nim | 19 | ||||
-rw-r--r-- | tests/overload/tvaruintconv.nim | 207 |
11 files changed, 580 insertions, 23 deletions
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/t23755.nim b/tests/overload/t23755.nim new file mode 100644 index 000000000..de338a2ce --- /dev/null +++ b/tests/overload/t23755.nim @@ -0,0 +1,62 @@ +type + BigInt[bits: static int] = object + limbs: array[8, uint64] + +block: + proc view[N](a: array[N, uint64]) = + discard + + proc view[N](a: var array[N, uint64]) = + discard + + var r: BigInt[64] + r.limbs.view() + + +type Limbs[N: static int] = array[N, uint64] + +block: + proc view(a: Limbs) = + discard + + proc view(a: var Limbs) = + discard + + var r: BigInt[64] + r.limbs.view() + + +block: + type IntArray[N: static[int]] = array[N, int] + + proc p[T](a: IntArray[T]): bool= true + proc p(a: IntArray[5]): bool= false + + var s: IntArray[5] + doAssert s.p == false + +block: + type IntArray[N: static[int]] = array[N, int] + + proc `$`(a: IntArray): string = + return "test" + + var s: IntArray[5] = [1,1,1,1,1] + doAssert `$`(s) == "test" + +block: + proc p[n:static[int]](a: array[n, char]):bool=true + proc p[T, IDX](a: array[IDX, T]):bool=false + + var g: array[32, char] + doAssert p(g) + +block: # issue #23823 + func p[N,T](a, b: array[N,T]) = + discard + + func p[N: static int; T](x, y: array[N, T]) = + discard + + var a: array[5, int] + p(a,a) diff --git a/tests/overload/t8829.nim b/tests/overload/t8829.nim index fe0dbf2bf..85d87f136 100644 --- a/tests/overload/t8829.nim +++ b/tests/overload/t8829.nim @@ -2,7 +2,7 @@ block: let txt = "Hello World" template `[]`[T](p: ptr T, span: Slice[int]): untyped = - toOpenArray(cast[ptr array[0, T]](p)[], span.a, span.b) + toOpenArray(cast[ptr UncheckedArray[T]](p), span.a, span.b) doAssert $cast[ptr uint8](txt[0].addr)[0 ..< txt.len] == "[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]" @@ -12,7 +12,7 @@ block: let txt = "Hello World" template `[]`[T](p: ptr T, span: Slice[int]): untyped = - toOpenArray(cast[ptr array[0, T]](p)[], span.a, span.b) + toOpenArray(cast[ptr UncheckedArray[T]](p), span.a, span.b) doAssert $cast[ptr uint8](txt[0].addr)[0 ..< txt.len] == "[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]" diff --git a/tests/overload/tgenericalias.nim b/tests/overload/tgenericalias.nim new file mode 100644 index 000000000..50a44bd32 --- /dev/null +++ b/tests/overload/tgenericalias.nim @@ -0,0 +1,13 @@ +block: # issue #13799 + type + X[A, B] = object + a: A + b: B + + Y[A] = X[A, int] + template s(T: type X): X = T() + template t[A, B](T: type X[A, B]): X[A, B] = T() + proc works1(): Y[int] = s(X[int, int]) + proc works2(): Y[int] = t(X[int, int]) + proc works3(): Y[int] = t(Y[int]) + proc broken(): Y[int] = s(Y[int]) diff --git a/tests/overload/tor_isnt_better.nim b/tests/overload/tor_isnt_better.nim index be1ad67bf..bee125386 100644 --- a/tests/overload/tor_isnt_better.nim +++ b/tests/overload/tor_isnt_better.nim @@ -16,3 +16,26 @@ block: # bug #8568 proc g(a: D|E): string = "foo D|E" proc g(a: D): string = "foo D" doAssert g(D[int]()) == "foo D" + +type Obj1[T] = object + v: T +converter toObj1[T](t: T): Obj1[T] = return Obj1[T](v: t) +block: # issue #10019 + proc fun1[T](elements: seq[T]): string = "fun1 seq" + proc fun1(o: object|tuple): string = "fun1 object|tuple" + proc fun2[T](elements: openArray[T]): string = "fun2 openarray" + proc fun2(o: object): string = "fun2 object" + proc fun_bug[T](elements: openArray[T]): string = "fun_bug openarray" + proc fun_bug(o: object|tuple):string = "fun_bug object|tuple" + proc main() = + var x = @["hello", "world"] + block: + # no ambiguity error shown here even though this would compile if we remove either 1st or 2nd overload of fun1 + doAssert fun1(x) == "fun1 seq" + block: + # ditto + doAssert fun2(x) == "fun2 openarray" + block: + # Error: ambiguous call; both t0065.fun_bug(elements: openarray[T])[declared in t0065.nim(17, 5)] and t0065.fun_bug(o: object or tuple)[declared in t0065.nim(20, 5)] match for: (array[0..1, string]) + doAssert fun_bug(x) == "fun_bug openarray" + main() diff --git a/tests/overload/toverload_issues.nim b/tests/overload/toverload_issues.nim index 5db7b54fa..26bf89091 100644 --- a/tests/overload/toverload_issues.nim +++ b/tests/overload/toverload_issues.nim @@ -77,27 +77,30 @@ testPred(1) -# bug #6526 -type - BaseObj = ref object of RootObj - DerivedObj = ref object of BaseObj - OtherDerivate = ref object of BaseObj - -proc `==`*[T1, T2: BaseObj](a: T1, b: T2): bool = - echo "baseobj ==" - return true - -let a = DerivedObj() -let b = DerivedObj() -echo a == b - -proc `==`*[T1, T2: OtherDerivate](a: T1, b: T2): bool = - echo "even better! ==" - return true - -let a2 = OtherDerivate() -let b2 = OtherDerivate() -echo a2 == b2 +block: # bug #6526 + type + BaseObj = ref object of RootObj + DerivedObj = ref object of BaseObj + OtherDerivate = ref object of BaseObj + + proc p[T](a: T, b: T): bool = + assert false + + proc p[T1, T2: BaseObj](a: T1, b: T2): bool = + echo "baseobj ==" + return true + + let a = DerivedObj() + let b = DerivedObj() + echo p(a,b) + + proc p[T1, T2: OtherDerivate](a: T1, b: T2): bool = + echo "even better! ==" + return true + + let a2 = OtherDerivate() + let b2 = OtherDerivate() + echo p(a2, b2) diff --git a/tests/overload/toverload_various.nim b/tests/overload/toverload_various.nim index 0741fce60..d195a069d 100644 --- a/tests/overload/toverload_various.nim +++ b/tests/overload/toverload_various.nim @@ -506,3 +506,63 @@ block: doAssert(p2(F(float,1.0),F(float,2)) == 3.0) doAssert(p2(F(float,1.0),F(float,2.0)) == 3.0) #doAssert(p2(F(float,1),F(int,2.0)) == 3.0) + +block: # PR #23870 + type + A {.inheritable.} = object + B = object of A + C = object of B + + proc p[T: A](x: T): int = 0 + proc p[T: B](x: T): int = 1 + + proc d(x: A): int = 0 + proc d(x: B): int = 1 + + proc g[T:A](x: typedesc[T]): int = 0 + proc g[T: B](x: typedesc[T]): int = 1 + + proc f[T](x: typedesc[T]): int = 0 + proc f[T:B](x: typedesc[T]): int = 1 + + assert p(C()) == 1 + assert d(C()) == 1 + assert g(C) == 1 + assert f(C) == 1 + +block: # PR #23870 + type + A = object of RootObj + PT = proc(ev: A) {.closure.} + sdt = seq[(PT, PT)] + + proc encap() = + proc p(a: A) {.closure.} = + discard + + var s: sdt + s.add (p, nil) + + encap() + +block: # PR #23870 + type + A = object of RootObj + B = object of A + C = object of B + + proc p(a: B | RootObj): int = + 0 + + proc p(a: A | A): int = + 1 + + assert p(C()) == 0 + + proc d(a: RootObj | B): int = + 0 + + proc d(a: A | A): int = + 1 + + assert d(C()) == 0 diff --git a/tests/overload/tuntypedarg.nim b/tests/overload/tuntypedarg.nim new file mode 100644 index 000000000..9aa4fad3b --- /dev/null +++ b/tests/overload/tuntypedarg.nim @@ -0,0 +1,19 @@ +import macros + +block: # issue #7385 + type CustomSeq[T] = object + data: seq[T] + macro `[]`[T](s: CustomSeq[T], args: varargs[untyped]): untyped = + ## The end goal is to replace the joker "_" by something else + result = newIntLitNode(10) + proc foo1(): CustomSeq[int] = + result.data.newSeq(10) + # works since no overload matches first argument with type `CustomSeq` + # except magic `[]`, which always matches without checking arguments + doAssert result[_] == 10 + doAssert foo1() == CustomSeq[int](data: newSeq[int](10)) + proc foo2[T](): CustomSeq[T] = + result.data.newSeq(10) + # works fine with generic return type + doAssert result[_] == 10 + doAssert foo2[int]() == CustomSeq[int](data: newSeq[int](10)) diff --git a/tests/overload/tvaruintconv.nim b/tests/overload/tvaruintconv.nim new file mode 100644 index 000000000..87ebd285d --- /dev/null +++ b/tests/overload/tvaruintconv.nim @@ -0,0 +1,207 @@ +discard """ + action: compile +""" + +# https://github.com/status-im/nimbus-eth2/pull/6554#issuecomment-2354977102 +# failed with "for a 'var' type a variable needs to be passed; but 'uint64(result)' is immutable" + +import + std/[typetraits, macros] + +type + DefaultFlavor = object + +template serializationFormatImpl(Name: untyped) {.dirty.} = + type Name = object + +template serializationFormat(Name: untyped) = + serializationFormatImpl(Name) + +template setReader(Format, FormatReader: distinct type) = + when arity(FormatReader) > 1: + template Reader(T: type Format, F: distinct type = DefaultFlavor): type = FormatReader[F] + else: + template ReaderType(T: type Format): type = FormatReader + template Reader(T: type Format): type = FormatReader + +template useDefaultReaderIn(T: untyped, Flavor: type) = + mixin Reader + + template readValue(r: var Reader(Flavor), value: var T) = + mixin readRecordValue + readRecordValue(r, value) + +import mvaruintconv + +type + FieldTag[RecordType: object; fieldName: static string] = distinct void + +func declval*(T: type): T {.compileTime.} = + default(ptr T)[] + +macro enumAllSerializedFieldsImpl(T: type, body: untyped): untyped = + var typeAst = getType(T)[1] + var typeImpl: NimNode + let isSymbol = not typeAst.isTuple + + if not isSymbol: + typeImpl = typeAst + else: + typeImpl = getImpl(typeAst) + result = newStmtList() + + var i = 0 + for field in recordFields(typeImpl): + let + fieldIdent = field.name + realFieldName = newLit($fieldIdent.skipPragma) + fieldName = realFieldName + fieldIndex = newLit(i) + + let fieldNameDefs = + if isSymbol: + quote: + const fieldName {.inject, used.} = `fieldName` + const realFieldName {.inject, used.} = `realFieldName` + else: + quote: + const fieldName {.inject, used.} = $`fieldIndex` + const realFieldName {.inject, used.} = $`fieldIndex` + + let field = + if isSymbol: + quote do: declval(`T`).`fieldIdent` + else: + quote do: declval(`T`)[`fieldIndex`] + + result.add quote do: + block: + `fieldNameDefs` + + template FieldType: untyped {.inject, used.} = typeof(`field`) + + `body` + + # echo repr(result) + +template enumAllSerializedFields(T: type, body): untyped = + enumAllSerializedFieldsImpl(T, body) + +type + FieldReader[RecordType, Reader] = tuple[ + fieldName: string, + reader: proc (rec: var RecordType, reader: var Reader) + {.gcsafe, nimcall.} + ] + +proc totalSerializedFieldsImpl(T: type): int = + mixin enumAllSerializedFields + enumAllSerializedFields(T): inc result + +template totalSerializedFields(T: type): int = + (static(totalSerializedFieldsImpl(T))) + +template GetFieldType(FT: type FieldTag): type = + typeof field(declval(FT.RecordType), FT.fieldName) + +proc makeFieldReadersTable(RecordType, ReaderType: distinct type, + numFields: static[int]): + array[numFields, FieldReader[RecordType, ReaderType]] = + mixin enumAllSerializedFields, handleReadException + var idx = 0 + + enumAllSerializedFields(RecordType): + proc readField(obj: var RecordType, reader: var ReaderType) + {.gcsafe, nimcall.} = + + mixin readValue + + type F = FieldTag[RecordType, realFieldName] + field(obj, realFieldName) = reader.readValue(GetFieldType(F)) + + result[idx] = (fieldName, readField) + inc idx + +proc fieldReadersTable(RecordType, ReaderType: distinct type): auto = + mixin readValue + type T = RecordType + const numFields = totalSerializedFields(T) + var tbl {.threadvar.}: ref array[numFields, FieldReader[RecordType, ReaderType]] + if tbl == nil: + tbl = new typeof(tbl) + tbl[] = makeFieldReadersTable(RecordType, ReaderType, numFields) + return addr(tbl[]) + +proc readValue(reader: var auto, T: type): T = + mixin readValue + reader.readValue(result) + +template decode(Format: distinct type, + input: string, + RecordType: distinct type): auto = + mixin Reader + block: # https://github.com/nim-lang/Nim/issues/22874 + var reader: Reader(Format) + reader.readValue(RecordType) + +template readValue(Format: type, + ValueType: type): untyped = + mixin Reader, init, readValue + var reader: Reader(Format) + readValue reader, ValueType + +template parseArrayImpl(numElem: untyped, + actionValue: untyped) = + actionValue + +serializationFormat Json +template createJsonFlavor(FlavorName: untyped, + skipNullFields = false) {.dirty.} = + type FlavorName = object + + template Reader(T: type FlavorName): type = Reader(Json, FlavorName) +type + JsonReader[Flavor = DefaultFlavor] = object + +Json.setReader JsonReader + +template parseArray(r: var JsonReader; body: untyped) = + parseArrayImpl(idx): body + +template parseArray(r: var JsonReader; idx: untyped; body: untyped) = + parseArrayImpl(idx): body + +proc readRecordValue[T](r: var JsonReader, value: var T) = + type + ReaderType {.used.} = type r + T = type value + + discard T.fieldReadersTable(ReaderType) + +proc readValue[T](r: var JsonReader, value: var T) = + mixin readValue + + when value is seq: + r.parseArray: + readValue(r, value[0]) + + elif value is object: + readRecordValue(r, value) + +type + RemoteSignerInfo = object + id: uint32 + RemoteKeystore = object + +proc readValue(reader: var JsonReader, value: var RemoteKeystore) = + discard reader.readValue(seq[RemoteSignerInfo]) + +createJsonFlavor RestJson +useDefaultReaderIn(RemoteSignerInfo, RestJson) +proc readValue(reader: var JsonReader[RestJson], value: var uint64) = + discard reader.readValue(string) + +discard Json.decode("", RemoteKeystore) +block: # https://github.com/nim-lang/Nim/issues/22874 + var reader: Reader(RestJson) + discard reader.readValue(RemoteSignerInfo) |