diff options
author | Jason Beetham <beefers331@gmail.com> | 2021-09-06 12:11:21 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-06 20:11:21 +0200 |
commit | 30d28bcefcad0da8900cfa231be9d77bb98c5097 (patch) | |
tree | 81f3f1a8bdd0f3f4efb1be7580c433f5086c5ff2 | |
parent | 34a53e804943ceaf3900feb6e89194aa03236c0a (diff) | |
download | Nim-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.nim | 28 | ||||
-rw-r--r-- | tests/generics/timplicit_and_explicit.nim | 45 |
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 |