summary refs log tree commit diff stats
path: root/tests/overload
diff options
context:
space:
mode:
Diffstat (limited to 'tests/overload')
-rw-r--r--tests/overload/issue22142/tfail_implicit_ambiguous.nim10
-rw-r--r--tests/overload/issue22142/tfail_nested_pointers.nim12
-rw-r--r--tests/overload/issue22142/tfail_object_is_generic.nim16
-rw-r--r--tests/overload/issue22142/tfail_typeclass_var_invar.nim9
-rw-r--r--tests/overload/issue22142/tissue22142_shouldpass.nim68
-rw-r--r--tests/overload/m19737.nim10
-rw-r--r--tests/overload/mvaruintconv.nim145
-rw-r--r--tests/overload/t19737.nim15
-rw-r--r--tests/overload/t23249.nim17
-rw-r--r--tests/overload/t23755.nim62
-rw-r--r--tests/overload/t7416.nim9
-rw-r--r--tests/overload/t8829.nim18
-rw-r--r--tests/overload/tgenericalias.nim13
-rw-r--r--tests/overload/tor_isnt_better.nim47
-rw-r--r--tests/overload/toverl4.nim26
-rw-r--r--tests/overload/toverload_issues.nim45
-rw-r--r--tests/overload/toverload_various.nim300
-rw-r--r--tests/overload/tproc_types_dont_like_subtypes.nim20
-rw-r--r--tests/overload/tselfderef.nim20
-rw-r--r--tests/overload/tstatic_with_converter.nim9
-rw-r--r--tests/overload/tuntypedarg.nim19
-rw-r--r--tests/overload/tvartypeclass.nim11
-rw-r--r--tests/overload/tvaruintconv.nim207
23 files changed, 1048 insertions, 60 deletions
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/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 5ef8bc7c4..bee125386 100644
--- a/tests/overload/tor_isnt_better.nim
+++ b/tests/overload/tor_isnt_better.nim
@@ -1,18 +1,41 @@
-discard """
-  errormsg: "ambiguous call;"
-  line: 16
-"""
-
-# bug #8568
-
 type
   D[T] = object
   E[T] = object
 
-proc g(a: D|E): string = "foo D|E"
-proc g(a: D): string = "foo D"
+block: # PR #22261
+  proc d(x: D):bool= false
+  proc d(x: int | D[SomeInteger]):bool= true
+  doAssert d(D[5]()) == false
 
-proc test() =
-  let x = g D[int]()
+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"
 
-test()
+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/toverl4.nim b/tests/overload/toverl4.nim
index 537925674..21cedaa96 100644
--- a/tests/overload/toverl4.nim
+++ b/tests/overload/toverl4.nim
@@ -1,5 +1,6 @@
 discard """
-  output: '''true'''
+  output: '''true
+5.0'''
 """
 
 #bug #592
@@ -75,3 +76,26 @@ proc add*[TKey, TData](root: var PElement[TKey, TData], key: TKey, data: TData)
 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
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 78497e607..d195a069d 100644
--- a/tests/overload/toverload_various.nim
+++ b/tests/overload/toverload_various.nim
@@ -264,9 +264,305 @@ 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]) =
+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/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/tselfderef.nim b/tests/overload/tselfderef.nim
deleted file mode 100644
index 96f1da42a..000000000
--- a/tests/overload/tselfderef.nim
+++ /dev/null
@@ -1,20 +0,0 @@
-discard """
-action: compile
-"""
-
-# bug #4671
-{.experimental.}
-{.this: self.}
-type
-  SomeObj = object
-    f: int
-
-proc f(num: int) =
-  discard
-
-var intptr: ptr int
-intptr.f() # compiles fine
-
-proc doSomething(self: var SomeObj) =
-  var pint: ptr int
-  pint.f() # Error: expression '.(pint, "f")' cannot be called
diff --git a/tests/overload/tstatic_with_converter.nim b/tests/overload/tstatic_with_converter.nim
index 2871744eb..2bc1dfaab 100644
--- a/tests/overload/tstatic_with_converter.nim
+++ b/tests/overload/tstatic_with_converter.nim
@@ -1,6 +1,7 @@
 discard """
 output: '''
-9.0'''
+9.0
+'''
 """
 
 ### bug #6773
@@ -37,11 +38,11 @@ proc `^`(x: vfloat, exp: static[float]): vfloat =
   when exp == 0.5:
     sqrt(x)
   else:
-   pow(x, exp)
+    pow(x, exp)
  
 proc `$`(x: vfloat): string =
-  let y = cast[ptr float](unsafeAddr x)
-  echo y[]
+  let y = cast[ptr float](addr x)
+  result = $y[]
  
 let x = set1(9.0)
 echo x^0.5
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)