summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/semtypes.nim17
-rw-r--r--tests/generics/tgenericwhen.nim46
2 files changed, 58 insertions, 5 deletions
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 2b6a7b6a7..8d293a753 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -789,6 +789,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
   of nkRecWhen:
     var a = copyTree(n)
     var branch: PNode = nil   # the branch to take
+    var cannotResolve = false # no branch should be taken
     for i in 0..<a.len:
       var it = a[i]
       if it == nil: illFormedAst(n, c.config)
@@ -806,24 +807,30 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
           let e = semExprWithType(c, it[0], {efDetermineType})
           if e.typ.kind == tyFromExpr:
             it[0] = makeStaticExpr(c, e)
+            cannotResolve = true
           else:
             it[0] = forceBool(c, e)
+            let val = getConstExpr(c.module, it[0], c.idgen, c.graph)
+            if val == nil or val.kind != nkIntLit:
+              cannotResolve = true
+            elif not cannotResolve and val.intVal != 0 and branch == nil:
+              branch = it[1]
       of nkElse:
         checkSonsLen(it, 1, c.config)
-        if branch == nil: branch = it[0]
+        if branch == nil and not cannotResolve: branch = it[0]
         idx = 0
       else: illFormedAst(n, c.config)
-      if c.inGenericContext > 0:
+      if c.inGenericContext > 0 and cannotResolve:
         # use a new check intset here for each branch:
         var newCheck: IntSet = check
         var newPos = pos
         var newf = newNodeI(nkRecList, n.info)
         semRecordNodeAux(c, it[idx], newCheck, newPos, newf, rectype, hasCaseFields)
         it[idx] = if newf.len == 1: newf[0] else: newf
-    if c.inGenericContext > 0:
-      father.add a
-    elif branch != nil:
+    if branch != nil:
       semRecordNodeAux(c, branch, check, pos, father, rectype, hasCaseFields)
+    elif c.inGenericContext > 0:
+      father.add a
     elif father.kind in {nkElse, nkOfBranch}:
       father.add newNodeI(nkRecList, n.info)
   of nkRecCase:
diff --git a/tests/generics/tgenericwhen.nim b/tests/generics/tgenericwhen.nim
new file mode 100644
index 000000000..e1b23873b
--- /dev/null
+++ b/tests/generics/tgenericwhen.nim
@@ -0,0 +1,46 @@
+discard """
+  targets: "c js"
+"""
+
+block: # issue #24041
+  type ArrayBuf[N: static int, T = byte] = object
+    when sizeof(int) > sizeof(uint8):
+      when N <= int(uint8.high):
+        n: uint8
+      else:
+        when sizeof(int) > sizeof(uint16):
+          when N <= int(uint16.high):
+            n: uint16
+          else:
+            when sizeof(int) > sizeof(uint32):
+              when N <= int(uint32.high):
+                n: uint32
+              else:
+                n: int
+            else:
+              n: int
+        else:
+          n: int
+    else:
+      n: int
+
+  var x: ArrayBuf[8]
+  doAssert x.n is uint8
+  when sizeof(int) > sizeof(uint32):
+    var y: ArrayBuf[int(uint32.high) * 8]
+    doAssert y.n is int
+
+block: # constant condition after dynamic one
+  type Foo[T] = object
+    when T is int:
+      a: int
+    elif true:
+      a: string
+    else:
+      a: bool
+  var x: Foo[string]
+  doAssert x.a is string
+  var y: Foo[int]
+  doAssert y.a is int
+  var z: Foo[float]
+  doAssert z.a is string