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_issues.nim7
-rw-r--r--tests/casestmt/tcaseexpr1.nim39
-rw-r--r--tests/casestmt/tcaseoverlaprange.nim15
-rw-r--r--tests/casestmt/tcaseoverlaprange2.nim18
-rw-r--r--tests/casestmt/tcasestmt.nim319
-rw-r--r--tests/casestmt/tcomputedgoto.nim59
-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.nim26
-rw-r--r--tests/casestmt/trangeexhaustiveness.nim7
13 files changed, 710 insertions, 0 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_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/tcaseexpr1.nim b/tests/casestmt/tcaseexpr1.nim
new file mode 100644
index 000000000..4f5bbf100
--- /dev/null
+++ b/tests/casestmt/tcaseexpr1.nim
@@ -0,0 +1,39 @@
+discard """
+  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 20
+type
+  E = enum A, B, C
+
+proc foo(x: int): auto =
+  return case x
+    of 1..9: "digit"
+    else: "number"
+
+var r = foo(10)
+
+var x = C
+
+var t1 = case x:
+  of A: "a"
+  of B: "b"
+
+var t2 = case x:
+  of A: 10
+  of B, C: "23"
diff --git a/tests/casestmt/tcaseoverlaprange.nim b/tests/casestmt/tcaseoverlaprange.nim
new file mode 100644
index 000000000..e9651c69f
--- /dev/null
+++ b/tests/casestmt/tcaseoverlaprange.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "duplicate case label"
+  line: 13
+"""
+
+type
+  TE = enum A, B, C, D
+
+var
+  e: TE
+
+case e
+of A..D, B..C:
+  echo "redundant"
+else: nil
diff --git a/tests/casestmt/tcaseoverlaprange2.nim b/tests/casestmt/tcaseoverlaprange2.nim
new file mode 100644
index 000000000..4a1cb3ea6
--- /dev/null
+++ b/tests/casestmt/tcaseoverlaprange2.nim
@@ -0,0 +1,18 @@
+discard """
+  errormsg: "duplicate case label"
+  line: 13
+"""
+
+
+
+
+proc checkDuplicates(myval: int32): bool =
+  case myval
+  of 0x7B:
+    echo "this should not compile"
+  of 0x78 .. 0x7D:
+    result = true
+  else:
+    nil
+
+echo checkDuplicates(0x7B)
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
new file mode 100644
index 000000000..f7603dac3
--- /dev/null
+++ b/tests/casestmt/tcomputedgoto.nim
@@ -0,0 +1,59 @@
+discard """
+  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
+'''
+"""
+
+type
+  MyEnum = enum
+    enumA, enumB, enumC, enumD, enumE, enumLast
+
+proc vm() =
+  var instructions: array[0..100, MyEnum]
+  instructions[2] = enumC
+  instructions[3] = enumD
+  instructions[4] = enumA
+  instructions[5] = enumD
+  instructions[6] = enumC
+  instructions[7] = enumA
+  instructions[8] = enumB
+
+  instructions[12] = enumE
+  var pc = 0
+  while true:
+    {.computedGoto.}
+    let instr = instructions[pc]
+    let ra = instr.succ # instr.regA
+    case instr
+    of enumA:
+      echo "yeah A ", ra
+    of enumC, enumD:
+      echo "yeah CD ", ra
+    of enumB:
+      echo "yeah B ", ra
+    of enumE:
+      break
+    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
new file mode 100644
index 000000000..96e3727d5
--- /dev/null
+++ b/tests/casestmt/tlinearscanend.nim
@@ -0,0 +1,26 @@
+discard """
+action: compile
+"""
+
+import strutils
+
+var x = 343
+
+case stdin.readline.parseInt
+of 0:
+  echo "most common case"
+of 1:
+  {.linearScanEnd.}
+  echo "second most common case"
+of 2: echo "unlikely: use branch table"
+else:
+  echo "unlikely too: use branch table"
+
+
+case x
+of 23: echo "23"
+of 343: echo "343"
+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