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>
This commit is contained in:
Jason Beetham
2021-09-06 12:11:21 -06:00
committed by GitHub
parent 34a53e8049
commit 30d28bcefc
2 changed files with 68 additions and 5 deletions

View File

@@ -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.

View File

@@ -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")