summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim8
-rw-r--r--compiler/semstmts.nim1
-rw-r--r--compiler/semtypinst.nim25
-rw-r--r--tests/generics/tgeneric_recursionlimit.nim123
4 files changed, 145 insertions, 12 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index d6e812f39..9e8d54432 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -232,7 +232,7 @@ type
   TNodeKinds* = set[TNodeKind]
 
 type
-  TSymFlag* = enum    # 48 flags!
+  TSymFlag* = enum    # 49 flags!
     sfUsed,           # read access of sym (for warnings) or simply used
     sfExported,       # symbol is exported from module
     sfFromGeneric,    # symbol is instantiation of a generic; this is needed
@@ -304,6 +304,12 @@ type
     sfSingleUsedTemp  # For temporaries that we know will only be used once
     sfNoalias         # 'noalias' annotation, means C's 'restrict'
     sfEffectsDelayed  # an 'effectsDelayed' parameter
+    sfGeneratedType   # A anonymous generic type that is generated by the compiler for
+                      # objects that do not have generic parameters in case one of the
+                      # object fields has one.
+                      #
+                      # This is disallowed but can cause the typechecking to go into
+                      # an infinite loop, this flag is used as a sentinel to stop it.
 
   TSymFlags* = set[TSymFlag]
 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 1e8930fc9..fd8f2180b 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1425,6 +1425,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
         excl(objTy.flags, tfFinal)
       let obj = newSym(skType, getIdent(c.cache, s.name.s & ":ObjectType"),
                        nextSymId c.idgen, getCurrOwner(c), s.info)
+      obj.flags.incl sfGeneratedType
       let symNode = newSymNode(obj)
       obj.ast = a.shallowCopy
       case a[0].kind
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 504b83b4c..945667a81 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -499,17 +499,20 @@ proc propagateFieldFlags(t: PType, n: PNode) =
 
 proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
   template bailout =
-    if cl.recursionLimit > 100:
-      # bail out, see bug #2509. But note this caching is in general wrong,
-      # look at this example where TwoVectors should not share the generic
-      # instantiations (bug #3112):
-
-      # type
-      #   Vector[N: static[int]] = array[N, float64]
-      #   TwoVectors[Na, Nb: static[int]] = (Vector[Na], Vector[Nb])
-      result = PType(idTableGet(cl.localCache, t))
-      if result != nil: return result
-    inc cl.recursionLimit
+    if t.sym != nil and sfGeneratedType in t.sym.flags:
+      # Only consider the recursion limit if the symbol is a type with generic
+      # parameters that have not been explicitly supplied, typechecking should
+      # terminate when generic parameters are explicitly supplied.
+      if cl.recursionLimit > 100:
+        # bail out, see bug #2509. But note this caching is in general wrong,
+        # look at this example where TwoVectors should not share the generic
+        # instantiations (bug #3112):
+        # type
+        #   Vector[N: static[int]] = array[N, float64]
+        #   TwoVectors[Na, Nb: static[int]] = (Vector[Na], Vector[Nb])
+        result = PType(idTableGet(cl.localCache, t))
+        if result != nil: return result
+      inc cl.recursionLimit
 
   result = t
   if t == nil: return
diff --git a/tests/generics/tgeneric_recursionlimit.nim b/tests/generics/tgeneric_recursionlimit.nim
new file mode 100644
index 000000000..5fe9b43c6
--- /dev/null
+++ b/tests/generics/tgeneric_recursionlimit.nim
@@ -0,0 +1,123 @@
+discard """
+  action: "compile"
+"""
+
+# https://github.com/nim-lang/Nim/issues/20348
+
+type
+  Payload[T] = object
+    payload: T
+  Carrier[T] = object
+    val: T
+
+type
+  Payload0*[T] = object
+    payload: Payload[T]
+  Payload1*[T] = object
+    payload: Payload[T]
+  Payload2*[T] = object
+    payload: Payload[T]
+  Payload3*[T] = object
+    payload: Payload[T]
+  Payload4*[T] = object
+    payload: Payload[T]
+  Payload5*[T] = object
+    payload: Payload[T]
+  Payload6*[T] = object
+    payload: Payload[T]
+  Payload7*[T] = object
+    payload: Payload[T]
+  Payload8*[T] = object
+    payload: Payload[T]
+  Payload9*[T] = object
+    payload: Payload[T]
+  Payload10*[T] = object
+    payload: Payload[T]
+  Payload11*[T] = object
+    payload: Payload[T]
+  Payload12*[T] = object
+    payload: Payload[T]
+  Payload13*[T] = object
+    payload: Payload[T]
+  Payload14*[T] = object
+    payload: Payload[T]
+  Payload15*[T] = object
+    payload: Payload[T]
+  Payload16*[T] = object
+    payload: Payload[T]
+  Payload17*[T] = object
+    payload: Payload[T]
+  Payload18*[T] = object
+    payload: Payload[T]
+  Payload19*[T] = object
+    payload: Payload[T]
+  Payload20*[T] = object
+    payload: Payload[T]
+  Payload21*[T] = object
+    payload: Payload[T]
+  Payload22*[T] = object
+    payload: Payload[T]
+  Payload23*[T] = object
+    payload: Payload[T]
+  Payload24*[T] = object
+    payload: Payload[T]
+  Payload25*[T] = object
+    payload: Payload[T]
+  Payload26*[T] = object
+    payload: Payload[T]
+  Payload27*[T] = object
+    payload: Payload[T]
+  Payload28*[T] = object
+    payload: Payload[T]
+  Payload29*[T] = object
+    payload: Payload[T]
+  Payload30*[T] = object
+    payload: Payload[T]
+  Payload31*[T] = object
+    payload: Payload[T]
+  Payload32*[T] = object
+    payload: Payload[T]
+  Payload33*[T] = object
+    payload: Payload[T]
+
+type
+  Carriers*[T] = object
+    c0*: Carrier[Payload0[T]]
+    c1*: Carrier[Payload1[T]]
+    c2*: Carrier[Payload2[T]]
+    c3*: Carrier[Payload3[T]]
+    c4*: Carrier[Payload4[T]]
+    c5*: Carrier[Payload5[T]]
+    c6*: Carrier[Payload6[T]]
+    c7*: Carrier[Payload7[T]]
+    c8*: Carrier[Payload8[T]]
+    c9*: Carrier[Payload9[T]]
+    c10*: Carrier[Payload10[T]]
+    c11*: Carrier[Payload11[T]]
+    c12*: Carrier[Payload12[T]]
+    c13*: Carrier[Payload13[T]]
+    c14*: Carrier[Payload14[T]]
+    c15*: Carrier[Payload15[T]]
+    c16*: Carrier[Payload16[T]]
+    c17*: Carrier[Payload17[T]]
+    c18*: Carrier[Payload18[T]]
+    c19*: Carrier[Payload19[T]]
+    c20*: Carrier[Payload20[T]]
+    c21*: Carrier[Payload21[T]]
+    c22*: Carrier[Payload22[T]]
+    c23*: Carrier[Payload23[T]]
+    c24*: Carrier[Payload24[T]]
+    c25*: Carrier[Payload25[T]]
+    c26*: Carrier[Payload26[T]]
+    c27*: Carrier[Payload27[T]]
+    c28*: Carrier[Payload28[T]]
+    c29*: Carrier[Payload29[T]]
+    c30*: Carrier[Payload30[T]]
+    c31*: Carrier[Payload31[T]]
+    c32*: Carrier[Payload32[T]]
+    c33*: Carrier[Payload33[T]]
+
+var carriers : Carriers[int]
+
+static:
+  assert $(typeof(carriers.c33.val)) == "Payload33[system.int]"