summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorJason Beetham <beefers331@gmail.com>2022-01-13 09:39:55 -0700
committerGitHub <noreply@github.com>2022-01-14 00:39:55 +0800
commita93f6e7acc9e02deb40a864d345e4c715346a98c (patch)
treee04b3ef68f3e0651a1c3ed18596f5777a71f251e
parent9b9ae8a487c6fbf77c8c72196e2b74f3371382b2 (diff)
downloadNim-a93f6e7acc9e02deb40a864d345e4c715346a98c.tar.gz
Generic parameters now can constrain statics in type definitions (#19362)
* Parameters now can constrain static in type definitions

resolved regression with generic procedures

* Update compiler/sigmatch.nim

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
-rw-r--r--compiler/sigmatch.nim14
-rw-r--r--tests/generics/tstatic_constrained.nim42
2 files changed, 54 insertions, 2 deletions
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 93be92676..4d8e03fe9 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1739,11 +1739,22 @@ proc typeRel(c: var TCandidate, f, aOrig: PType,
     let prev = PType(idTableGet(c.bindings, f))
     if prev == nil:
       if aOrig.kind == tyStatic:
-        if f.base.kind != tyNone:
+        if f.base.kind notin {tyNone, tyGenericParam}:
           result = typeRel(c, f.base, a, flags)
           if result != isNone and f.n != nil:
             if not exprStructuralEquivalent(f.n, aOrig.n):
               result = isNone
+        elif f.base.kind == tyGenericParam:
+          # Handling things like `type A[T; Y: static T] = object`
+          if f.base.len > 0: # There is a constraint, handle it
+            result = typeRel(c, f.base.lastSon, a, flags)
+          else:
+            # No constraint
+            if tfGenericTypeParam in f.flags:
+              result = isGeneric
+            else:
+              # for things like `proc fun[T](a: static[T])`
+              result = typeRel(c, f.base, a, flags)
         else:
           result = isGeneric
         if result != isNone: put(c, f, aOrig)
@@ -1993,7 +2004,6 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
     arg = argSemantized
     a = a
     c = m.c
-
   if tfHasStatic in fMaybeStatic.flags:
     # XXX: When implicit statics are the default
     # this will be done earlier - we just have to
diff --git a/tests/generics/tstatic_constrained.nim b/tests/generics/tstatic_constrained.nim
new file mode 100644
index 000000000..07318d1bd
--- /dev/null
+++ b/tests/generics/tstatic_constrained.nim
@@ -0,0 +1,42 @@
+discard """
+  cmd: "nim check --hints:off --warnings:off $file"
+  action: "reject"
+  nimout:'''
+tstatic_constrained.nim(41, 20) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(27, 3)]
+got: <typedesc[int], int literal(10)>
+but expected: <T: float or string, Y>
+tstatic_constrained.nim(41, 20) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(27, 3)]
+got: <typedesc[int], int literal(10)>
+but expected: <T: float or string, Y>
+tstatic_constrained.nim(41, 29) Error: object constructor needs an object type [proxy]
+tstatic_constrained.nim(41, 29) Error: expression '' has no type (or is ambiguous)
+tstatic_constrained.nim(42, 20) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(27, 3)]
+got: <typedesc[byte], uint8>
+but expected: <T: float or string, Y>
+tstatic_constrained.nim(42, 20) Error: cannot instantiate MyOtherType [type declared in tstatic_constrained.nim(27, 3)]
+got: <typedesc[byte], uint8>
+but expected: <T: float or string, Y>
+tstatic_constrained.nim(42, 32) Error: object constructor needs an object type [proxy]
+tstatic_constrained.nim(42, 32) Error: expression '' has no type (or is ambiguous)
+'''
+"""
+
+type 
+  MyType[T; X: static T] = object
+    data: T
+  MyOtherType[T: float or string, Y: static T] = object
+
+func f[T,X](a: MyType[T,X]): MyType[T,X] =
+  when T is string:
+    MyType[T,X](data: a.data & X)
+  else:
+    MyType[T,X](data: a.data + X)
+
+discard MyType[int, 2](data: 1)
+discard MyType[string, "Helelello"](data: "Hmmm")
+discard MyType[int, 2](data: 1).f()
+discard MyType[string, "Helelello"](data: "Hmmm").f()
+discard MyOtherType[float, 1.3]()
+discard MyOtherType[string, "Hello"]()
+discard MyOtherType[int, 10]()
+discard MyOtherType[byte, 10u8]()
\ No newline at end of file