summary refs log tree commit diff stats
path: root/tests/casestmt
diff options
context:
space:
mode:
Diffstat (limited to 'tests/casestmt')
-rw-r--r--tests/casestmt/t18964.nim12
-rw-r--r--tests/casestmt/t7699.nim15
-rw-r--r--tests/casestmt/tcase_arrayconstr.nim19
-rw-r--r--tests/casestmt/tcase_emptyset_when.nim24
-rw-r--r--tests/casestmt/tcase_issues.nim7
-rw-r--r--tests/casestmt/tcase_setconstr.nim15
-rw-r--r--tests/casestmt/tcaseexpr1.nim23
-rw-r--r--tests/casestmt/tcaseoverlaprange.nim2
-rw-r--r--tests/casestmt/tcaseoverlaprange2.nim2
-rw-r--r--tests/casestmt/tcasestm.nim40
-rw-r--r--tests/casestmt/tcasestmt.nim319
-rw-r--r--tests/casestmt/tcomputedgoto.nim17
-rw-r--r--tests/casestmt/tcstring.nim52
-rw-r--r--tests/casestmt/tincompletecaseobject.nim115
-rw-r--r--tests/casestmt/tincompletecaseobject2.nim26
-rw-r--r--tests/casestmt/tlinearscanend.nim4
-rw-r--r--tests/casestmt/trangeexhaustiveness.nim7
17 files changed, 588 insertions, 111 deletions
diff --git a/tests/casestmt/t18964.nim b/tests/casestmt/t18964.nim
new file mode 100644
index 000000000..1d2de2bbc
--- /dev/null
+++ b/tests/casestmt/t18964.nim
@@ -0,0 +1,12 @@
+discard """
+errormsg: "invalid order of case branches"
+"""
+
+import macros
+
+macro genCase(val: string): untyped =
+  result = nnkCaseStmt.newTree(val,
+    nnkElse.newTree(quote do: echo "else"),
+    nnkOfBranch.newTree(newLit("miauz"), quote do: echo "first branch"))
+
+genCase("miauz")
diff --git a/tests/casestmt/t7699.nim b/tests/casestmt/t7699.nim
new file mode 100644
index 000000000..1354551c1
--- /dev/null
+++ b/tests/casestmt/t7699.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "case statement cannot work on enums with holes for computed goto"
+  line: 13
+"""
+
+type
+  X = enum
+    A = 0, B = 100
+
+var z = A
+while true:
+  {.computedGoto.}
+  case z
+  of A: discard
+  of B: discard
diff --git a/tests/casestmt/tcase_arrayconstr.nim b/tests/casestmt/tcase_arrayconstr.nim
deleted file mode 100644
index cd7156600..000000000
--- a/tests/casestmt/tcase_arrayconstr.nim
+++ /dev/null
@@ -1,19 +0,0 @@
-discard """
-  output: '''Not found!
-Found!'''
-"""
-
-const
-  md_extension = [".md", ".markdown"]
-
-proc test(ext: string) =
-  case ext
-  of ".txt", md_extension:
-    echo "Found!"
-  else:
-    echo "Not found!"
-
-test(".something")
-# ensure it's not evaluated at compile-time:
-var foo = ".markdown"
-test(foo)
diff --git a/tests/casestmt/tcase_emptyset_when.nim b/tests/casestmt/tcase_emptyset_when.nim
deleted file mode 100644
index e9b1ec2df..000000000
--- a/tests/casestmt/tcase_emptyset_when.nim
+++ /dev/null
@@ -1,24 +0,0 @@
-discard """
-  file: "tcaseofwhen.nim"
-  outputsub: "compiles for 1\ni am always two\ndefault for 3\nset is 4 not 5\narray is 6 not 7\ndefault for 8"
-  exitcode: "0"
-"""
-
-proc whenCase(a: int) =
-  case a
-  of (when compiles(whenCase(1)): 1 else: {}): echo "compiles for 1"
-  of {}: echo "me not fail"
-  of 2: echo "i am always two"
-  of []: echo "me neither"
-  of {4,5}: echo "set is 4 not 5"
-  of [6,7]: echo "array is 6 not 7"
-  of (when compiles(neverCompilesIBet()): 3 else: {}): echo "compiles for 3"
-  #of {},[]: echo "me neither"
-  else: echo "default for ", a
-
-whenCase(1)
-whenCase(2)
-whenCase(3)
-whenCase(4)
-whenCase(6)
-whenCase(8)
diff --git a/tests/casestmt/tcase_issues.nim b/tests/casestmt/tcase_issues.nim
new file mode 100644
index 000000000..20a79df2c
--- /dev/null
+++ b/tests/casestmt/tcase_issues.nim
@@ -0,0 +1,7 @@
+discard """
+  targets: "c js"
+"""
+
+block: # bug #24031
+  case 0
+  else: discard
\ No newline at end of file
diff --git a/tests/casestmt/tcase_setconstr.nim b/tests/casestmt/tcase_setconstr.nim
deleted file mode 100644
index 21f657c2b..000000000
--- a/tests/casestmt/tcase_setconstr.nim
+++ /dev/null
@@ -1,15 +0,0 @@
-discard """
-  output: "an identifier"
-"""
-
-const
-  SymChars: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
-
-proc classify(s: string) =
-  case s[0]
-  of SymChars, '_': echo "an identifier"
-  of {'0'..'9'}: echo "a number"
-  else: echo "other"
-
-classify("Hurra")
-
diff --git a/tests/casestmt/tcaseexpr1.nim b/tests/casestmt/tcaseexpr1.nim
index 56acbbc8a..4f5bbf100 100644
--- a/tests/casestmt/tcaseexpr1.nim
+++ b/tests/casestmt/tcaseexpr1.nim
@@ -1,13 +1,23 @@
 discard """
-  file: "tcaseexpr1.nim"
+  cmd: "nim check $options $file"
+  action: "reject"
+  nimout: '''
+tcaseexpr1.nim(33, 10) Error: not all cases are covered; missing: {C}
+tcaseexpr1.nim(39, 12) Error: type mismatch: got <string> but expected 'int literal(10)'
+'''
+"""
+
+
+
+
 
-  line: 29
-  errormsg: "type mismatch: got (string) but expected 'int'"
 
-  line: 23
-  errormsg: "not all cases are covered"
-"""
 
+
+
+
+
+# line 20
 type
   E = enum A, B, C
 
@@ -27,4 +37,3 @@ var t1 = case x:
 var t2 = case x:
   of A: 10
   of B, C: "23"
-
diff --git a/tests/casestmt/tcaseoverlaprange.nim b/tests/casestmt/tcaseoverlaprange.nim
index 3527c9385..e9651c69f 100644
--- a/tests/casestmt/tcaseoverlaprange.nim
+++ b/tests/casestmt/tcaseoverlaprange.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 13
   errormsg: "duplicate case label"
+  line: 13
 """
 
 type
diff --git a/tests/casestmt/tcaseoverlaprange2.nim b/tests/casestmt/tcaseoverlaprange2.nim
index 4a9479a5f..4a1cb3ea6 100644
--- a/tests/casestmt/tcaseoverlaprange2.nim
+++ b/tests/casestmt/tcaseoverlaprange2.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 13
   errormsg: "duplicate case label"
+  line: 13
 """
 
 
diff --git a/tests/casestmt/tcasestm.nim b/tests/casestmt/tcasestm.nim
deleted file mode 100644
index 7ac20bf2f..000000000
--- a/tests/casestmt/tcasestm.nim
+++ /dev/null
@@ -1,40 +0,0 @@
-discard """
-  file: "tcasestm.nim"
-  output: "ayyydd"
-"""
-# Test the case statement
-
-type
-  Tenum = enum eA, eB, eC
-
-var
-  x: string = "yyy"
-  y: Tenum = eA
-  i: int
-
-case y
-of eA: write(stdout, "a")
-of eB, eC: write(stdout, "b or c")
-
-case x
-of "Andreas", "Rumpf": write(stdout, "Hallo Meister!")
-of "aa", "bb": write(stdout, "Du bist nicht mein Meister")
-of "cc", "hash", "when": discard
-of "will", "it", "finally", "be", "generated": discard
-
-var z = case i
-  of 1..5, 8, 9: "aa"
-  of 6, 7: "bb"
-  elif x == "Ha":
-    "cc"
-  elif x == "yyy":
-    write(stdout, x)
-    "dd"
-  else:
-    "zz"
-
-echo z
-#OUT ayyy
-
-
-
diff --git a/tests/casestmt/tcasestmt.nim b/tests/casestmt/tcasestmt.nim
new file mode 100644
index 000000000..66de4183d
--- /dev/null
+++ b/tests/casestmt/tcasestmt.nim
@@ -0,0 +1,319 @@
+discard """
+output:
+'''
+Not found!
+Found!
+1
+compiles for 1
+i am always two
+default for 3
+set is 4 not 5
+array is 6 not 7
+default for 8
+an identifier
+OK
+OK
+OK
+ayyydd
+'''
+"""
+
+
+block arrayconstr:
+  const md_extension = [".md", ".markdown"]
+
+  proc test(ext: string) =
+    case ext
+    of ".txt", md_extension:
+      echo "Found!"
+    else:
+      echo "Not found!"
+
+  test(".something")
+  # ensure it's not evaluated at compile-time:
+  var foo = ".markdown"
+  test(foo)
+
+
+converter toInt(x: char): int =
+  x.int
+block t8333:
+  case 0
+  of 'a': echo 0
+  else: echo 1
+block: # issue #11422
+  var c: int = 5
+  case c
+  of 'a' .. 'c': discard
+  else: discard
+
+
+block emptyset_when:
+  proc whenCase(a: int) =
+    case a
+    of (when compiles(whenCase(1)): 1 else: {}): echo "compiles for 1"
+    of {}: echo "me not fail"
+    of 2: echo "i am always two"
+    of []: echo "me neither"
+    of {4,5}: echo "set is 4 not 5"
+    of [6,7]: echo "array is 6 not 7"
+    of (when compiles(neverCompilesIBet()): 3 else: {}): echo "compiles for 3"
+    #of {},[]: echo "me neither"
+    else: echo "default for ", a
+
+  whenCase(1)
+  whenCase(2)
+  whenCase(3)
+  whenCase(4)
+  whenCase(6)
+  whenCase(8)
+
+
+block setconstr:
+  const
+    SymChars: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
+
+  proc classify(s: string) =
+    case s[0]
+    of SymChars, '_': echo "an identifier"
+    of {'0'..'9'}: echo "a number"
+    else: echo "other"
+
+  classify("Hurra")
+
+
+
+block tduplicates:
+  type Kind = enum A, B
+  var k = A
+
+  template reject(b) =
+    static: doAssert(not compiles(b))
+
+  reject:
+      var i = 2
+      case i
+      of [1, 1]: discard
+      else: discard
+
+  reject:
+      var i = 2
+      case i
+      of 1, { 1..2 }: discard
+      else: discard
+
+  reject:
+      var i = 2
+      case i
+      of { 1, 1 }: discard
+      of { 1, 1 }: discard
+      else: discard
+
+  reject:
+      case k
+      of [A, A]: discard
+
+  var i = 2
+  case i
+  of { 1, 1 }: discard
+  of { 2, 2 }: echo "OK"
+  else: discard
+
+  case i
+  of { 10..30, 15..25, 5..15, 25..35 }: discard
+  else: echo "OK"
+
+  case k
+  of {A, A..A}: echo "OK"
+  of B: discard
+
+
+block tcasestm:
+  type
+    Tenum = enum eA, eB, eC
+
+  var
+    x: string = "yyy"
+    y: Tenum = eA
+    i: int
+
+  case y
+  of eA: write(stdout, "a")
+  of eB, eC: write(stdout, "b or c")
+
+  case x
+  of "Andreas", "Rumpf": write(stdout, "Hallo Meister!")
+  of "aa", "bb": write(stdout, "Du bist nicht mein Meister")
+  of "cc", "hash", "when": discard
+  of "will", "it", "finally", "be", "generated": discard
+
+  var z = case i
+    of 1..5, 8, 9: "aa"
+    of 6, 7: "bb"
+    elif x == "Ha":
+      "cc"
+    elif x == "yyy":
+      write(stdout, x)
+      "dd"
+    else:
+      "zz"
+
+  echo z
+  #OUT ayyy
+
+  let str1 = "Y"
+  let str2 = "NN"
+  let a = case str1:
+    of "Y": true
+    of "N": false
+    else:
+      echo "no good"
+      quit("quitting")
+
+  proc toBool(s: string): bool =
+    case s:
+    of "": raise newException(ValueError, "Invalid boolean")
+    elif s[0] == 'Y': true
+    elif s[0] == 'N': false
+    else: "error".quit(2)
+
+
+  let b = "NN".toBool()
+
+  doAssert(a == true)
+  doAssert(b == false)
+
+  static:
+    #bug #7407
+    let bstatic = "N".toBool()
+    doAssert(bstatic == false)
+
+  var bb: bool
+  doAssert(not compiles(
+    bb = case str2:
+      of "": raise newException(ValueError, "Invalid boolean")
+      elif str.startsWith("Y"): true
+      elif str.startsWith("N"): false
+  ))
+
+  doAssert(not compiles(
+    bb = case str2:
+      of "Y": true
+      of "N": false
+  ))
+
+  doAssert(not compiles(
+    bb = case str2:
+      of "Y": true
+      of "N": raise newException(ValueError, "N not allowed")
+  ))
+
+  doAssert(not compiles(
+    bb = case str2:
+      of "Y": raise newException(ValueError, "Invalid Y")
+      else: raise newException(ValueError, "Invalid N")
+  ))
+
+
+  doAssert(not compiles(
+    bb = case str2:
+      of "Y":
+        raise newException(ValueError, "Invalid Y")
+        true
+      else: raise newException(ValueError, "Invalid")
+  ))
+
+
+  doAssert(not compiles(
+    bb = case str2:
+      of "Y":
+        "invalid Y".quit(3)
+        true
+      else: raise newException(ValueError, "Invalid")
+  ))
+
+#issue #11552
+
+proc positiveOrNegative(num: int): string =
+  result = case num
+  of (low(int)+2) .. -1:
+    "negative"
+  of 0:
+    "zero"
+  else:
+    "impossible"
+
+#issue #11551
+
+proc negativeOrNot(num: int): string =
+    result = case num
+    of low(int) .. -1:
+      "negative"
+    else:
+      "zero or positive"
+
+doAssert negativeOrNot(-1) == "negative"
+doAssert negativeOrNot(10000000) == "zero or positive"
+doAssert negativeOrNot(0) == "zero or positive"
+
+########################################################
+# issue #13490
+import strutils
+func foo(input: string): int =
+  try:
+    parseInt(input)
+  except:
+    return
+
+func foo2(b, input: string): int =
+  case b:
+    of "Y":
+      for c in input:
+        result =  if c in '0'..'9': parseInt($c)
+                  else: break
+    of "N":
+      for c in input:
+        result =  if c in '0'..'9': parseInt($c)
+                  else: continue
+    else: return
+
+
+static:
+  doAssert(foo("3") == 3)
+  doAssert(foo("a") == 0)
+  doAssert(foo2("Y", "a2") == 0)
+  doAssert(foo2("Y", "2a") == 2)
+  doAssert(foo2("N", "a3") == 3)
+  doAssert(foo2("z", "2") == 0)
+
+doAssert(foo("3") == 3)
+doAssert(foo("a") == 0)
+doAssert(foo2("Y", "a2") == 0)
+doAssert(foo2("Y", "2a") == 2)
+doAssert(foo2("N", "a3") == 3)
+doAssert(foo2("z", "2") == 0)
+
+
+# bug #20031
+proc main(a: uint64) =
+  case a
+  else:
+    discard
+
+static:
+  main(10)
+main(10)
+
+block:
+  # Just needs to compile
+  proc bar(): int {.discardable.} = discard
+
+  proc foo() {.noreturn.} = discard
+
+  case "*"
+  of "*":
+    bar()
+  else:
+    # Make sure this noreturn doesn't
+    # cause the discardable to not discard
+    foo()
diff --git a/tests/casestmt/tcomputedgoto.nim b/tests/casestmt/tcomputedgoto.nim
index f567174af..f7603dac3 100644
--- a/tests/casestmt/tcomputedgoto.nim
+++ b/tests/casestmt/tcomputedgoto.nim
@@ -1,16 +1,24 @@
 discard """
-  output: '''yeah A enumB
+  output: '''
+yeah A enumB
+uneven
 yeah A enumB
 yeah CD enumD
+uneven
 yeah CD enumE
 yeah A enumB
+uneven
 yeah CD enumE
 yeah CD enumD
+uneven
 yeah A enumB
 yeah B enumC
+uneven
+yeah A enumB
 yeah A enumB
+uneven
 yeah A enumB
-yeah A enumB'''
+'''
 """
 
 type
@@ -18,7 +26,7 @@ type
     enumA, enumB, enumC, enumD, enumE, enumLast
 
 proc vm() =
-  var instructions: array [0..100, MyEnum]
+  var instructions: array[0..100, MyEnum]
   instructions[2] = enumC
   instructions[3] = enumD
   instructions[4] = enumA
@@ -45,4 +53,7 @@ proc vm() =
     of enumLast: discard
     inc(pc)
 
+    if pc mod 2 == 1:
+      echo "uneven"
+
 vm()
diff --git a/tests/casestmt/tcstring.nim b/tests/casestmt/tcstring.nim
new file mode 100644
index 000000000..288373402
--- /dev/null
+++ b/tests/casestmt/tcstring.nim
@@ -0,0 +1,52 @@
+discard """
+  targets: "c cpp js"
+"""
+
+type Result = enum none, a, b, c, d, e, f
+
+proc foo1(x: cstring): Result =
+  const y = cstring"hash"
+  const arr = [cstring"it", cstring"finally"]
+  result = none
+  case x
+  of "Andreas", "Rumpf": result = a
+  of cstring"aa", "bb": result = b
+  of "cc", y, "when": result = c
+  of "will", arr, "be", "generated": result = d
+  of nil: result = f
+
+var results = [
+  foo1("Rumpf"), foo1("Andreas"),
+  foo1("aa"), foo1(cstring"bb"),
+  foo1("cc"), foo1("hash"),
+  foo1("finally"), foo1("generated"),
+  foo1("no"), foo1("another no"),
+  foo1(nil)]
+doAssert results == [a, a, b, b, c, c, d, d, none, none, f], $results
+
+proc foo2(x: cstring): Result =
+  const y = cstring"hash"
+  const arr = [cstring"it", cstring"finally"]
+  doAssert not (compiles do:
+    result = case x
+    of "Andreas", "Rumpf": a
+    of cstring"aa", "bb": b
+    of "cc", y, "when": c
+    of "will", arr, "be", "generated": d)
+  case x
+  of "Andreas", "Rumpf": a
+  of cstring"aa", "bb": b
+  of "cc", y, "when": c
+  of "will", arr, "be", "generated": d
+  of nil: f
+  else: e
+
+results = [
+  foo2("Rumpf"), foo2("Andreas"),
+  foo2("aa"), foo2(cstring"bb"),
+  foo2("cc"), foo2("hash"),
+  foo2("finally"), foo2("generated"),
+  foo2("no"), foo2("another no"),
+  foo2(nil)]
+
+doAssert results == [a, a, b, b, c, c, d, d, e, e, f], $results
diff --git a/tests/casestmt/tincompletecaseobject.nim b/tests/casestmt/tincompletecaseobject.nim
new file mode 100644
index 000000000..aa5deda7a
--- /dev/null
+++ b/tests/casestmt/tincompletecaseobject.nim
@@ -0,0 +1,115 @@
+discard """
+errormsg: '''
+not all cases are covered; missing: {nnkComesFrom, nnkDotCall, nnkHiddenCallConv, nnkVarTuple, nnkCurlyExpr, nnkRange, nnkCheckedFieldExpr, nnkDerefExpr, nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkBind, nnkClosedSymChoice, nnkHiddenSubConv, nnkConv, nnkStaticExpr, nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv, nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange, nnkStringToCString, nnkCStringToString, nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit, nnkImportAs, nnkConverterDef, nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch, nnkElifBranch, nnkExceptBranch, nnkElse, nnkAsmStmt, nnkTypeDef, nnkFinally, nnkContinueStmt, nnkImportStmt, nnkImportExceptStmt, nnkExportStmt, nnkExportExceptStmt, nnkFromStmt, nnkIncludeStmt, nnkUsingStmt, nnkBlockExpr, nnkStmtListType, nnkBlockType, nnkWith, nnkWithout, nnkTypeOfExpr, nnkObjectTy, nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy, nnkRecList, nnkRecCase, nnkRecWhen, nnkVarTy, nnkConstTy, nnkMutableTy, nnkDistinctTy, nnkProcTy, nnkIteratorTy, nnkSharedTy, nnkEnumTy, nnkEnumFieldDef, nnkArgList, nnkPattern, nnkReturnToken, nnkClosure, nnkGotoState, nnkState, nnkBreakState, nnkFuncDef, nnkTupleConstr}
+'''
+"""
+
+# this isn't imported from macros.nim to make it robust against possible changes in the ast.
+
+type
+  NimNodeKind* = enum
+    nnkNone, nnkEmpty, nnkIdent, nnkSym,
+    nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit,
+    nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkUIntLit, nnkUInt8Lit,
+    nnkUInt16Lit, nnkUInt32Lit, nnkUInt64Lit, nnkFloatLit,
+    nnkFloat32Lit, nnkFloat64Lit, nnkFloat128Lit, nnkStrLit, nnkRStrLit,
+    nnkTripleStrLit, nnkNilLit, nnkComesFrom, nnkDotCall,
+    nnkCommand, nnkCall, nnkCallStrLit, nnkInfix,
+    nnkPrefix, nnkPostfix, nnkHiddenCallConv,
+    nnkExprEqExpr,
+    nnkExprColonExpr, nnkIdentDefs, nnkVarTuple,
+    nnkPar, nnkObjConstr, nnkCurly, nnkCurlyExpr,
+    nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange,
+    nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr,
+    nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkAccQuoted,
+    nnkTableConstr, nnkBind,
+    nnkClosedSymChoice,
+    nnkOpenSymChoice,
+    nnkHiddenStdConv,
+    nnkHiddenSubConv, nnkConv, nnkCast, nnkStaticExpr,
+    nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv,
+    nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange,
+    nnkStringToCString, nnkCStringToString, nnkAsgn,
+    nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit,
+    nnkImportAs, nnkProcDef, nnkMethodDef, nnkConverterDef,
+    nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
+    nnkElifBranch, nnkExceptBranch, nnkElse,
+    nnkAsmStmt, nnkPragma, nnkPragmaBlock, nnkIfStmt, nnkWhenStmt,
+    nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkCaseStmt,
+    nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection,
+    nnkConstDef, nnkTypeDef,
+    nnkYieldStmt, nnkDefer, nnkTryStmt, nnkFinally, nnkRaiseStmt,
+    nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt,
+    nnkDiscardStmt, nnkStmtList,
+    nnkImportStmt = 1337, # make a hole just for fun
+    nnkImportExceptStmt,
+    nnkExportStmt,
+    nnkExportExceptStmt,
+    nnkFromStmt,
+    nnkIncludeStmt,
+    nnkBindStmt, nnkMixinStmt, nnkUsingStmt,
+    nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
+    nnkStmtListType, nnkBlockType,
+    nnkWith, nnkWithout,
+    nnkTypeOfExpr, nnkObjectTy,
+    nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy,
+    nnkRecList, nnkRecCase, nnkRecWhen,
+    nnkRefTy, nnkPtrTy, nnkVarTy,
+    nnkConstTy, nnkMutableTy,
+    nnkDistinctTy,
+    nnkProcTy,
+    nnkIteratorTy,         # iterator type
+    nnkSharedTy,           # 'shared T'
+    nnkEnumTy,
+    nnkEnumFieldDef,
+    nnkArgList, nnkPattern
+    nnkReturnToken,
+    nnkClosure,
+    nnkGotoState,
+    nnkState,
+    nnkBreakState,
+    nnkFuncDef,
+    nnkTupleConstr
+
+const
+  nnkLiterals* = {nnkCharLit..nnkNilLit}
+
+  nnkSomething* = {nnkStmtList, nnkStmtListExpr, nnkDiscardStmt, nnkVarSection, nnkLetSection,
+       nnkConstSection, nnkPar, nnkAccQuoted, nnkAsgn, nnkDefer, nnkCurly, nnkBracket,
+       nnkStaticStmt, nnkTableConstr, nnkExprColonExpr, nnkInfix, nnkPrefix,
+       nnkRaiseStmt, nnkYieldStmt, nnkBracketExpr, nnkDotExpr, nnkCast, nnkBlockStmt,
+       nnkExprEqExpr}
+
+type
+  MyFictionalType = object
+    a: int
+    case n: NimNodeKind
+    of nnkLiterals, nnkCommentStmt, nnkNone, nnkEmpty, nnkIdent, nnkSym,
+       nnkType, nnkBindStmt, nnkMixinStmt, nnkTypeSection, nnkPragmaBlock,
+       nnkPragmaExpr, nnkPragma, nnkBreakStmt, nnkCallStrLit, nnkPostfix,
+       nnkOpenSymChoice:
+      b: int
+    of nnkCall, nnkCommand:
+      c: int
+    of nnkReturnStmt:
+      d: int
+    of nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkProcDef, nnkMethodDef:
+      e: int
+    of nnkSomething, nnkRefTy, nnkPtrTy, nnkHiddenStdConv:
+      f: int
+    of nnkObjConstr:
+      g: int
+    of nnkIfStmt, nnkIfExpr, nnkWhenStmt:
+      # if when and case statements are branching statements. So a
+      # single function call is allowed to be in all of the braches and
+      # the entire expression can still be considered as a forwarding
+      # template.
+      h: int
+    of nnkCaseStmt:
+      i: int
+    of nnkTryStmt:
+      j: int
+    of nnkIdentDefs:
+      k: int
+    of nnkConstDef:
+      l: int
diff --git a/tests/casestmt/tincompletecaseobject2.nim b/tests/casestmt/tincompletecaseobject2.nim
new file mode 100644
index 000000000..bbeae1909
--- /dev/null
+++ b/tests/casestmt/tincompletecaseobject2.nim
@@ -0,0 +1,26 @@
+discard """
+cmd: "nim check $file"
+"""
+type
+  ABCD = enum A, B, C, D
+  AliasABCD = ABCD
+  RangeABC = range[A .. C]
+  AliasRangeABC = RangeABC
+  PrintableChars = range[' ' .. '~']
+
+case PrintableChars 'x': #[tt.Error
+^ not all cases are covered; missing: {' ', '!', '\"', '#', '$$', '%', '&', '\'', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~'}]#
+of '0'..'9', 'A'..'Z', 'a'..'z': discard
+of '(', ')': discard
+
+case AliasABCD A: #[tt.Error
+^ not all cases are covered; missing: {B, C, D}]#
+of A: discard
+
+case RangeABC A: #[tt.Error
+^ not all cases are covered; missing: {A, C}]#
+of B: discard
+
+case AliasRangeABC A: #[tt.Error
+^ not all cases are covered; missing: {A, B}]#
+of C: discard
diff --git a/tests/casestmt/tlinearscanend.nim b/tests/casestmt/tlinearscanend.nim
index 9a984e039..96e3727d5 100644
--- a/tests/casestmt/tlinearscanend.nim
+++ b/tests/casestmt/tlinearscanend.nim
@@ -1,3 +1,6 @@
+discard """
+action: compile
+"""
 
 import strutils
 
@@ -21,4 +24,3 @@ of 21: echo "21"
 else:
   {.linearScanEnd.}
   echo "default"
-
diff --git a/tests/casestmt/trangeexhaustiveness.nim b/tests/casestmt/trangeexhaustiveness.nim
new file mode 100644
index 000000000..2b7f3558e
--- /dev/null
+++ b/tests/casestmt/trangeexhaustiveness.nim
@@ -0,0 +1,7 @@
+block: # issue #22661
+  template foo(a: typed) =
+    a
+    
+  foo:
+    case false
+    of false..true: discard