summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorJason Beetham <beefers331@gmail.com>2021-09-06 12:11:21 -0600
committerGitHub <noreply@github.com>2021-09-06 20:11:21 +0200
commit30d28bcefcad0da8900cfa231be9d77bb98c5097 (patch)
tree81f3f1a8bdd0f3f4efb1be7580c433f5086c5ff2
parent34a53e804943ceaf3900feb6e89194aa03236c0a (diff)
downloadNim-30d28bcefcad0da8900cfa231be9d77bb98c5097.tar.gz
Fixes implicit and explicit generics in procedures (#18808)
* Fixes implicit and explicit generics

* moved block logic into 'maybeInstantiateGeneric'

* Added more tests

* Update compiler/semexprs.nim

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
-rw-r--r--compiler/semexprs.nim28
-rw-r--r--tests/generics/timplicit_and_explicit.nim45
2 files changed, 68 insertions, 5 deletions
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index c0a2a346a..0f6f71cc2 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1493,6 +1493,28 @@ proc semDeref(c: PContext, n: PNode): PNode =
   else: result = nil
   #GlobalError(n[0].info, errCircumNeedsPointer)
 
+proc maybeInstantiateGeneric(c: PContext, n: PNode, s: PSym): PNode =
+  ## Instantiates generic if not lacking implicit generics,
+  ## otherwise returns n.
+  let
+    neededGenParams = s.ast[genericParamsPos].len
+    heldGenParams = n.len - 1
+  var implicitParams = 0
+  for x in s.ast[genericParamsPos]:
+    if tfImplicitTypeParam in x.typ.flags:
+      inc implicitParams
+  if heldGenParams != neededGenParams and implicitParams + heldGenParams == neededGenParams:
+    # This is an implicit + explicit generic procedure without all args passed,
+    # kicking back the sem'd symbol fixes #17212
+    # Uncertain the hackiness of this solution.
+    result = n
+  else:
+    result = explicitGenericInstantiation(c, n, s)
+    if result == n:
+      n[0] = copyTree(result)
+    else:
+      n[0] = result
+
 proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
   ## returns nil if not a built-in subscript operator; also called for the
   ## checking of assignments
@@ -1568,11 +1590,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
       of skProc, skFunc, skMethod, skConverter, skIterator:
         # type parameters: partial generic specialization
         n[0] = semSymGenericInstantiation(c, n[0], s)
-        result = explicitGenericInstantiation(c, n, s)
-        if result == n:
-          n[0] = copyTree(result)
-        else:
-          n[0] = result
+        result = maybeInstantiateGeneric(c, n, s)
       of skMacro, skTemplate:
         if efInCall in flags:
           # We are processing macroOrTmpl[] in macroOrTmpl[](...) call.
diff --git a/tests/generics/timplicit_and_explicit.nim b/tests/generics/timplicit_and_explicit.nim
new file mode 100644
index 000000000..ba24b79e9
--- /dev/null
+++ b/tests/generics/timplicit_and_explicit.nim
@@ -0,0 +1,45 @@
+
+block: # basic test
+  proc doStuff[T](a: SomeInteger): T = discard
+  proc doStuff[T;Y](a: SomeInteger, b: Y): Y = discard
+  assert typeof(doStuff[int](100)) is int
+  assert typeof(doStuff[int](100, 1.0)) is float
+  assert typeof(doStuff[int](100, "Hello")) is string
+
+  proc t[T](x: T; z: int | float): seq[T] = result.add(x & $z)
+
+  assert t[string]("Hallo", 2.0) == @["Hallo" & $2.0]
+
+  proc t2[T](z: int | float): seq[T] = result.add($z)
+
+  assert t2[string](2.0) == @[$2.0]
+
+block: # template test
+  template someThing[T;Y](a: SomeFloat, b: SomeOrdinal): (T, Y) = (a, b)
+  assert typeof(someThing[float64, int](1.0, 100)) is (float64, int)
+
+block: # static test
+  proc t[T](s: static bool) = discard
+  proc t2[T](s: static string) = discard
+  t[string](true)
+  t2[int]("hello")
+  t2[string]("world")
+  t2[float]("test222222")
+
+block: #11152
+  proc f[T](X: typedesc) = discard
+  f[int](string)
+
+block: #15622
+  proc test1[T](a: T, b: static[string] = "") = discard
+  test1[int64](123)
+  proc test2[T](a: T, b: static[string] = "") = discard
+  test2[int64, static[string]](123)
+
+block: #4688
+  proc convertTo[T](v: int or float): T = (T)(v)
+  discard convertTo[float](1)
+
+block: #4164
+  proc printStr[T](s: static[string]): T = discard
+  discard printStr[int]("hello static")
\ No newline at end of file