summary refs log tree commit diff stats
path: root/tests/effects
diff options
context:
space:
mode:
Diffstat (limited to 'tests/effects')
-rw-r--r--tests/effects/tdiagnostic_messages.nim37
-rw-r--r--tests/effects/teffects1.nim32
-rw-r--r--tests/effects/teffects11.nim21
-rw-r--r--tests/effects/teffects12.nim52
-rw-r--r--tests/effects/teffects13.nim19
-rw-r--r--tests/effects/teffects14.nim15
-rw-r--r--tests/effects/teffects15.nim18
-rw-r--r--tests/effects/teffects16.nim20
-rw-r--r--tests/effects/teffects17.nim17
-rw-r--r--tests/effects/teffects18.nim19
-rw-r--r--tests/effects/teffects19.nim23
-rw-r--r--tests/effects/teffects2.nim5
-rw-r--r--tests/effects/teffects3.nim2
-rw-r--r--tests/effects/teffects4.nim2
-rw-r--r--tests/effects/teffects6.nim22
-rw-r--r--tests/effects/teffects7.nim4
-rw-r--r--tests/effects/teffects8.nim3
-rw-r--r--tests/effects/teffectsmisc.nim39
-rw-r--r--tests/effects/tfuncs_cannot_mutate.nim10
-rw-r--r--tests/effects/tfuncs_cannot_mutate2.nim24
-rw-r--r--tests/effects/tfuncs_cannot_mutate3.nim35
-rw-r--r--tests/effects/tfuncs_cannot_mutate_simple.nim6
-rw-r--r--tests/effects/tgcsafe.nim4
-rw-r--r--tests/effects/tgcsafe2.nim2
-rw-r--r--tests/effects/tgcsafe3.nim2
-rw-r--r--tests/effects/thooks.nim16
-rw-r--r--tests/effects/tlaxeffects.nim11
-rw-r--r--tests/effects/tnestedprocs.nim63
-rw-r--r--tests/effects/tnosideeffect.nim2
-rw-r--r--tests/effects/toutparam.nim28
-rw-r--r--tests/effects/tstrict_caseobjects.nim47
-rw-r--r--tests/effects/tstrict_effects.nim27
-rw-r--r--tests/effects/tstrict_effects2.nim28
-rw-r--r--tests/effects/tstrict_effects3.nim57
-rw-r--r--tests/effects/tstrict_effects_sort.nim27
-rw-r--r--tests/effects/tstrict_funcs.nim17
-rw-r--r--tests/effects/tstrict_funcs_imports.nim21
-rw-r--r--tests/effects/tstrict_funcs_imports_js.nim1
-rw-r--r--tests/effects/tstrictfuncs_misc.nim65
39 files changed, 766 insertions, 77 deletions
diff --git a/tests/effects/tdiagnostic_messages.nim b/tests/effects/tdiagnostic_messages.nim
new file mode 100644
index 000000000..b1acf8c5c
--- /dev/null
+++ b/tests/effects/tdiagnostic_messages.nim
@@ -0,0 +1,37 @@
+discard """
+  nimoutFull: true
+  action: "reject"
+  cmd: "nim r --hint:Conf:off $file"
+  nimout: '''
+tdiagnostic_messages.nim(36, 6) Error: 'a' can have side effects
+> tdiagnostic_messages.nim(37, 30) Hint: 'a' calls `.sideEffect` 'callWithSideEffects'
+>> tdiagnostic_messages.nim(29, 6) Hint: 'callWithSideEffects' called by 'a'
+>>> tdiagnostic_messages.nim(31, 34) Hint: 'callWithSideEffects' calls `.sideEffect` 'indirectCallViaVarParam'
+>>>> tdiagnostic_messages.nim(25, 6) Hint: 'indirectCallViaVarParam' called by 'callWithSideEffects'
+>>>>> tdiagnostic_messages.nim(26, 7) Hint: 'indirectCallViaVarParam' calls routine via hidden pointer indirection
+>>> tdiagnostic_messages.nim(32, 33) Hint: 'callWithSideEffects' calls `.sideEffect` 'indirectCallViaPointer'
+>>>> tdiagnostic_messages.nim(27, 6) Hint: 'indirectCallViaPointer' called by 'callWithSideEffects'
+>>>>> tdiagnostic_messages.nim(28, 32) Hint: 'indirectCallViaPointer' calls routine via pointer indirection
+>>> tdiagnostic_messages.nim(33, 3) Hint: 'callWithSideEffects' calls `.sideEffect` 'myEcho'
+>>>> tdiagnostic_messages.nim(24, 6) Hint: 'myEcho' called by 'callWithSideEffects'
+>>> tdiagnostic_messages.nim(34, 3) Hint: 'callWithSideEffects' accesses global state 'globalVar'
+>>>> tdiagnostic_messages.nim(23, 5) Hint: 'globalVar' accessed by 'callWithSideEffects'
+
+'''
+"""
+
+var globalVar = 0
+proc myEcho(a: string) {.sideEffect.} = discard
+proc indirectCallViaVarParam(call: var proc(): int {.nimcall.}): int =
+  call()
+proc indirectCallViaPointer(call: pointer): int =
+  cast[ptr proc(): int](call)[]()
+proc callWithSideEffects(): int =
+  var p = proc (): int {.nimcall.} = 0
+  discard indirectCallViaVarParam(p)
+  discard indirectCallViaPointer(addr p)
+  myEcho ""
+  globalVar
+
+func a: int =
+  discard callWithSideEffects()
diff --git a/tests/effects/teffects1.nim b/tests/effects/teffects1.nim
index 66d6a3518..1d267b5fa 100644
--- a/tests/effects/teffects1.nim
+++ b/tests/effects/teffects1.nim
@@ -1,12 +1,10 @@
 discard """
-  cmd: "nim check $file"
-  nimout: '''teffects1.nim(22, 28) template/generic instantiation from here
-teffects1.nim(23, 13) Error: can raise an unlisted exception: ref IOError
-teffects1.nim(22, 29) Hint: 'lier' cannot raise 'IO2Error' [XCannotRaiseY]
-teffects1.nim(38, 21) Error: type mismatch: got <proc (x: int): string{.noSideEffect, gcsafe, locks: 0.}> but expected 'MyProcType = proc (x: int): string{.closure.}'
-.raise effects differ'''
+  cmd: "nim check --hint:Conf:off --hint:XDeclaredButNotUsed:off $file"
+  nimout: '''
+teffects1.nim(17, 28) template/generic instantiation from here
+'''
 """
-
+{.push warningAsError[Effect]: on.}
 type
   TObj {.pure, inheritable.} = object
   TObjB = object of TObj
@@ -16,28 +14,34 @@ type
 
 proc forw: int {. .}
 
-proc lier(): int {.raises: [IO2Error].} =
-  #[tt.Hint                 ^ 'lier' cannot raise 'IO2Error' [XCannotRaiseY] ]#
+proc lier(): int {.raises: [IO2Error].} = #[tt.Hint
+                            ^ 'lier' cannot raise 'IO2Error' [XCannotRaiseY] ]#
   writeLine stdout, "arg" #[tt.Error
-            ^  can raise an unlisted exception: ref IOError
-  ]#
+  ^ writeLine stdout, ["arg"] can raise an unlisted exception: ref IOError ]#
 
 proc forw: int =
   raise newException(IOError, "arg")
 
+block:
+  proc someProc(t: string) {.raises: [Defect].} =
+    discard
+  let vh: proc(topic: string) {.raises: [].} = someProc
+
 {.push raises: [Defect].}
 
 type
   MyProcType* = proc(x: int): string #{.raises: [ValueError, Defect].}
 
-proc foo(x: int): string {.raises: [ValueError].} =
+proc foo(x: int): string {.nimcall, raises: [ValueError].} =
   if x > 9:
     raise newException(ValueError, "Use single digit")
   $x
 
 var p: MyProcType = foo #[tt.Error
                     ^
-type mismatch: got <proc (x: int): string{.noSideEffect, gcsafe, locks: 0.}> but expected 'MyProcType = proc (x: int): string{.closure.}'
-
+type mismatch: got <proc (x: int): string{.nimcall, raises: [ValueError], noSideEffect, gcsafe.}> but expected 'MyProcType = proc (x: int): string{.closure.}'
+  Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'.
+.raise effects differ
 ]#
 {.pop.}
+{.pop.}
diff --git a/tests/effects/teffects11.nim b/tests/effects/teffects11.nim
new file mode 100644
index 000000000..20b7026ab
--- /dev/null
+++ b/tests/effects/teffects11.nim
@@ -0,0 +1,21 @@
+discard """
+action: compile
+errormsg: "type mismatch: got <proc (x: int){.gcsafe.}>"
+line: 21
+"""
+
+type
+  Effect1 = object
+  Effect2 = object
+  Effect3 = object
+
+proc test(fnc: proc(x: int): void {.forbids: [Effect2].}) {.tags: [Effect1, Effect3, RootEffect].} =
+  fnc(1)
+
+proc t1(x: int): void = echo $x
+proc t2(x: int): void {.tags: [Effect2].} = echo $x
+proc t3(x: int): void {.tags: [Effect3].} = echo $x
+
+test(t1)
+test(t3)
+test(t2)
diff --git a/tests/effects/teffects12.nim b/tests/effects/teffects12.nim
new file mode 100644
index 000000000..5f5499c38
--- /dev/null
+++ b/tests/effects/teffects12.nim
@@ -0,0 +1,52 @@
+discard """
+action: compile
+"""
+
+import std/locks
+
+type
+  Test2Effect* = object
+  Test2* = object
+    value2*: int
+  Test1Effect* = object
+  Test1* = object
+    value1*: int
+  Main* = object
+    test1Lock: Lock
+    test1: Test1
+    test2Lock: Lock
+    test2: Test2
+
+proc `=copy`(obj1: var Test2, obj2: Test2) {.error.}
+proc `=copy`(obj1: var Test1, obj2: Test1) {.error.}
+proc `=copy`(obj1: var Main, obj2: Main) {.error.}
+
+proc withTest1(main: var Main,
+               fn: proc(test1: var Test1) {.gcsafe, forbids: [Test1Effect].}) {.gcsafe, tags: [Test1Effect, RootEffect].} =
+  withLock(main.test1Lock):
+    fn(main.test1)
+
+proc withTest2(main: var Main,
+               fn: proc(test1: var Test2) {.gcsafe, forbids: [Test2Effect].}) {.gcsafe, tags: [Test2Effect, RootEffect].} =
+  withLock(main.test2Lock):
+    fn(main.test2)
+
+proc newMain(): Main =
+  var test1lock: Lock
+  initLock(test1Lock)
+  var test2lock: Lock
+  initLock(test2Lock)
+  var main = Main(test1Lock: move(test1Lock), test1: Test1(value1: 1),
+                  test2Lock: move(test2Lock), test2: Test2(value2: 2))
+  main.withTest1(proc(test1: var Test1) = test1.value1 += 1)
+  main.withTest2(proc(test2: var Test2) = test2.value2 += 1)
+  move main
+
+var main = newMain()
+main.withTest1(proc(test1: var Test1) =
+  test1.value1 += 1
+  main.withTest2(proc(test2: var Test2) = test2.value2 += 1)
+)
+
+main.withTest1(proc(test1: var Test1) {.tags: [].} = echo $test1.value1)
+main.withTest2(proc(test2: var Test2) {.tags: [].} = echo $test2.value2)
diff --git a/tests/effects/teffects13.nim b/tests/effects/teffects13.nim
new file mode 100644
index 000000000..73082f997
--- /dev/null
+++ b/tests/effects/teffects13.nim
@@ -0,0 +1,19 @@
+discard """
+action: compile
+errormsg: "writeSomething() has an illegal effect: WriteIO"
+line: 19
+"""
+
+type
+  IO = object of RootEffect ## input/output effect
+  ReadIO = object of IO     ## input effect
+  WriteIO = object of IO    ## output effect
+
+proc readSomething(): string {.tags: [ReadIO].} = ""
+proc writeSomething(): void {.tags: [WriteIO].} = echo "..."
+
+proc noWritesPlease() {.forbids: [WriteIO].} =
+  # this is OK:
+  echo readSomething()
+  # the compiler prevents this:
+  writeSomething()
diff --git a/tests/effects/teffects14.nim b/tests/effects/teffects14.nim
new file mode 100644
index 000000000..6291d9569
--- /dev/null
+++ b/tests/effects/teffects14.nim
@@ -0,0 +1,15 @@
+discard """
+action: compile
+errormsg: "func1() has an illegal effect: IO"
+line: 15
+"""
+
+type IO = object ## input/output effect
+proc func1(): string {.tags: [IO].} = discard
+proc func2(): string = discard
+
+proc no_IO_please() {.forbids: [IO].} =
+  # this is OK because it didn't define any tag:
+  discard func2()
+  # the compiler prevents this:
+  let y = func1()
diff --git a/tests/effects/teffects15.nim b/tests/effects/teffects15.nim
new file mode 100644
index 000000000..c3079cdbc
--- /dev/null
+++ b/tests/effects/teffects15.nim
@@ -0,0 +1,18 @@
+discard """
+action: compile
+errormsg: "method1(c) has an illegal effect: IO"
+line: 18
+"""
+
+type
+  IO = object ## input/output effect
+  CustomObject* = object of RootObj
+    text: string
+
+method method1(obj: var CustomObject): string {.tags: [IO].} = obj.text & "."
+method method2(obj: var CustomObject): string = obj.text & ":"
+
+proc noIO() {.forbids: [IO].} =
+  var c = CustomObject(text: "a")
+  echo c.method2()
+  echo c.method1()
diff --git a/tests/effects/teffects16.nim b/tests/effects/teffects16.nim
new file mode 100644
index 000000000..ee8f782a3
--- /dev/null
+++ b/tests/effects/teffects16.nim
@@ -0,0 +1,20 @@
+discard """
+action: compile
+errormsg: "writeSomething(\"a\") can have an unlisted effect: WriteIO"
+line: 20
+"""
+
+type
+  IO = object of RootEffect ## input/output effect
+  ReadIO = object of IO     ## input effect
+  WriteIO = object of IO    ## output effect
+  LogIO = object of IO      ## another output effect
+
+proc readSomething(): string {.tags: [ReadIO].} = ""
+proc writeSomething(msg: string): void {.tags: [WriteIO].} = echo msg
+proc logSomething(msg: string): void {.tags: [LogIo].} = echo msg
+
+proc noWritesPlease() {.forbids: [WriteIO], tags: [LogIO, ReadIO].} =
+  echo readSomething()
+  logSomething("a")
+  writeSomething("a")
diff --git a/tests/effects/teffects17.nim b/tests/effects/teffects17.nim
new file mode 100644
index 000000000..5e6b83896
--- /dev/null
+++ b/tests/effects/teffects17.nim
@@ -0,0 +1,17 @@
+discard """
+action: compile
+errormsg: "writeSomething(\"a\") has an illegal effect: WriteIO"
+line: 17
+"""
+
+type
+  IO = object of RootEffect ## input/output effect
+  ReadIO = object of IO     ## input effect
+  WriteIO = object of IO    ## output effect
+
+proc readSomething(): string {.tags: [ReadIO].} = ""
+proc writeSomething(msg: string): void {.tags: [WriteIO].} = echo msg
+
+proc illegalEffectNegation() {.forbids: [WriteIO], tags: [ReadIO, WriteIO].} =
+  echo readSomething()
+  writeSomething("a")
diff --git a/tests/effects/teffects18.nim b/tests/effects/teffects18.nim
new file mode 100644
index 000000000..576e76635
--- /dev/null
+++ b/tests/effects/teffects18.nim
@@ -0,0 +1,19 @@
+discard """
+action: compile
+errormsg: "type mismatch: got <ProcType2>"
+line: 19
+"""
+
+type MyEffect = object
+type ProcType1 = proc (i: int): void {.forbids: [MyEffect].}
+type ProcType2 = proc (i: int): void
+
+proc testFunc(p: ProcType1): void = p(1)
+
+proc toBeCalled(i: int): void {.tags: [MyEffect].} = echo $i
+
+let emptyTags = proc(i: int): void {.tags: [].} = echo $i
+let noTags: ProcType2 = proc(i: int): void = toBeCalled(i)
+
+testFunc(emptyTags)
+testFunc(noTags)
diff --git a/tests/effects/teffects19.nim b/tests/effects/teffects19.nim
new file mode 100644
index 000000000..6b4ab0819
--- /dev/null
+++ b/tests/effects/teffects19.nim
@@ -0,0 +1,23 @@
+discard """
+action: compile
+errormsg: "type mismatch: got <proc (i: int){.gcsafe.}>"
+line: 23
+"""
+
+type MyEffect = object
+type ProcType1 = proc (i: int): void {.forbids: [MyEffect].}
+type ProcType2 = proc (i: int): void
+
+proc caller1(p: ProcType1): void = p(1)
+proc caller2(p: ProcType2): void = p(1)
+
+proc effectful(i: int): void {.tags: [MyEffect].} = echo $i
+proc effectless(i: int): void {.forbids: [MyEffect].} = echo $i
+
+proc toBeCalled1(i: int): void = effectful(i)
+proc toBeCalled2(i: int): void = effectless(i)
+
+caller1(toBeCalled2)
+caller2(toBeCalled1)
+caller2(toBeCalled2)
+caller1(toBeCalled1)
diff --git a/tests/effects/teffects2.nim b/tests/effects/teffects2.nim
index e4b50aba5..777a4cebc 100644
--- a/tests/effects/teffects2.nim
+++ b/tests/effects/teffects2.nim
@@ -2,9 +2,9 @@ discard """
   errormsg: "can raise an unlisted exception: ref IOError"
   line: 19
 """
-
+{.push warningAsError[Effect]: on.}
 type
-  TObj = object {.pure, inheritable.}
+  TObj {.pure, inheritable.} = object
   TObjB = object of TObj
     a, b, c: string
 
@@ -17,3 +17,4 @@ proc lier(): int {.raises: [IOError].} =
 
 proc forw: int =
   raise newException(IOError, "arg")
+{.pop.}
diff --git a/tests/effects/teffects3.nim b/tests/effects/teffects3.nim
index ee5470c47..4c050510a 100644
--- a/tests/effects/teffects3.nim
+++ b/tests/effects/teffects3.nim
@@ -4,7 +4,7 @@ discard """
 """
 
 type
-  TObj = object {.pure, inheritable.}
+  TObj {.pure, inheritable.} = object
   TObjB = object of TObj
     a, b, c: string
     fn: proc (): int {.tags: [].}
diff --git a/tests/effects/teffects4.nim b/tests/effects/teffects4.nim
index 88cc0efa9..b875754b6 100644
--- a/tests/effects/teffects4.nim
+++ b/tests/effects/teffects4.nim
@@ -4,7 +4,7 @@ discard """
 """
 
 type
-  TObj = object {.pure, inheritable.}
+  TObj {.pure, inheritable.} = object
   TObjB = object of TObj
     a, b, c: string
     fn: proc (): int {.tags: [ReadIOEffect].}
diff --git a/tests/effects/teffects6.nim b/tests/effects/teffects6.nim
index 6a4eea155..d3af22434 100644
--- a/tests/effects/teffects6.nim
+++ b/tests/effects/teffects6.nim
@@ -21,7 +21,7 @@ createMenuItem(s, "Go to definition...",
 )
 
 
-proc noRaise(x: proc()) {.raises: [].} =
+proc noRaise(x: proc()) {.raises: [], effectsOf: x.} =
   # unknown call that might raise anything, but valid:
   x()
 
@@ -34,3 +34,23 @@ proc use*() =
 
 
 use()
+
+# bug #12642
+import os
+
+proc raises() {.raises: Exception.} = discard
+proc harmless() {.raises: [].} = discard
+
+let x = if paramStr(1) == "true": harmless else: raises
+
+let
+  choice = 0
+
+proc withoutSideEffects(): int = 0
+proc withSideEffects(): int = echo "foo" # the echo causes the side effect
+
+let procPtr = case choice
+              of 0: withoutSideEffects
+              else: withSideEffects
+
+echo procPtr.repr
diff --git a/tests/effects/teffects7.nim b/tests/effects/teffects7.nim
index 73865b18d..9b7fbf5f0 100644
--- a/tests/effects/teffects7.nim
+++ b/tests/effects/teffects7.nim
@@ -2,7 +2,7 @@ discard """
   errormsg: "can raise an unlisted exception: ref ValueError"
   line: 10
 """
-
+{.push warningAsError[Effect]: on.}
 proc foo() {.raises: [].} =
   try:
     discard
@@ -12,3 +12,5 @@ proc foo() {.raises: [].} =
     discard
 
 foo()
+
+{.pop.}
diff --git a/tests/effects/teffects8.nim b/tests/effects/teffects8.nim
index fb3c088d6..359b3a1df 100644
--- a/tests/effects/teffects8.nim
+++ b/tests/effects/teffects8.nim
@@ -2,7 +2,7 @@ discard """
   errormsg: "can raise an unlisted exception: Exception"
   line: 10
 """
-
+{.push warningAsError[Effect]: on.}
 proc foo() {.raises: [].} =
   try:
     discard
@@ -10,3 +10,4 @@ proc foo() {.raises: [].} =
     raise
 
 foo()
+{.pop.}
diff --git a/tests/effects/teffectsmisc.nim b/tests/effects/teffectsmisc.nim
new file mode 100644
index 000000000..8fb95b275
--- /dev/null
+++ b/tests/effects/teffectsmisc.nim
@@ -0,0 +1,39 @@
+discard """
+  output: '''
+printing from adder
+'''
+"""
+
+import std/sugar
+
+block:
+  proc makeAdder(a: int): (int) -> void =
+    proc discard_adder(x: int) {.closure.} =
+      discard a + x
+
+    proc echo_adder(x: int) {.closure.} =
+      echo("printing from adder")
+
+    if a > 0:
+      discard_adder
+    else:
+      echo_adder
+
+  let newAdder = makeAdder(0)
+  newAdder(5)
+
+block:
+  proc makeAdder(a: int): (int) -> void =
+    proc discard_adder(x: int) {.closure.} =
+      discard a + x
+
+    proc echo_adder(x: int) {.closure.} =
+      echo("printing from adder")
+
+    if a > 0:
+      echo_adder
+    else:
+      discard_adder
+
+  let newAdder = makeAdder(0)
+  newAdder(5)
diff --git a/tests/effects/tfuncs_cannot_mutate.nim b/tests/effects/tfuncs_cannot_mutate.nim
index 4768af2b3..9934d27a7 100644
--- a/tests/effects/tfuncs_cannot_mutate.nim
+++ b/tests/effects/tfuncs_cannot_mutate.nim
@@ -1,9 +1,6 @@
 discard """
-  errormsg: "'mutate' can have side effects"
-  nimout: '''an object reachable from 'n' is potentially mutated
-tfuncs_cannot_mutate.nim(39, 15) the mutation is here
-tfuncs_cannot_mutate.nim(37, 7) is the statement that connected the mutation to the parameter'''
-  line: 33
+  errormsg: "cannot mutate location select(x, z).data within a strict func"
+  line: 35
 """
 
 {.experimental: "strictFuncs".}
@@ -25,8 +22,7 @@ func len(n: Node): int =
     it = it.ri
 
 func doNotDistract(n: Node) =
-  var m = Node()
-  m.data = "abc"
+  var m = Node(data: "abc")
 
 func select(a, b: Node): Node = b
 
diff --git a/tests/effects/tfuncs_cannot_mutate2.nim b/tests/effects/tfuncs_cannot_mutate2.nim
new file mode 100644
index 000000000..86f811017
--- /dev/null
+++ b/tests/effects/tfuncs_cannot_mutate2.nim
@@ -0,0 +1,24 @@
+discard """
+  errormsg: "cannot mutate location x[0].a within a strict func"
+  line: 12
+"""
+
+{.experimental: "strictFuncs".}
+
+func copy[T](x: var openArray[T]; y: openArray[T]) =
+  for i in 0..high(x):
+    x[i] = y[i]
+
+  x[0].a = nil
+
+type
+  R = ref object
+    a, b: R
+    data: string
+
+proc main =
+  var a, b: array[3, R]
+  b = [R(data: "a"), R(data: "b"), R(data: "c")]
+  copy a, b
+
+main()
diff --git a/tests/effects/tfuncs_cannot_mutate3.nim b/tests/effects/tfuncs_cannot_mutate3.nim
new file mode 100644
index 000000000..029152029
--- /dev/null
+++ b/tests/effects/tfuncs_cannot_mutate3.nim
@@ -0,0 +1,35 @@
+discard """
+  errormsg: "cannot mutate location kid.parent within a strict func"
+  line: 16
+"""
+
+{.experimental: "strictFuncs".}
+
+type
+  Node = ref object
+    name: string
+    kids: seq[Node]
+    parent: Node
+
+func initParents(tree: Node) =
+  for kid in tree.kids:
+    kid.parent = tree
+    initParents(kid)
+
+proc process(intro: Node): Node =
+  var tree = Node(name: "root", kids: @[
+    intro,
+    Node(name: "one", kids: @[
+      Node(name: "two"),
+      Node(name: "three"),
+    ]),
+    Node(name: "four"),
+  ])
+  initParents(tree)
+
+proc main() =
+  var intro = Node(name: "intro")
+  var tree = process(intro)
+  echo intro.parent.name
+
+main()
diff --git a/tests/effects/tfuncs_cannot_mutate_simple.nim b/tests/effects/tfuncs_cannot_mutate_simple.nim
index 9de20d1ec..0ae4a0db9 100644
--- a/tests/effects/tfuncs_cannot_mutate_simple.nim
+++ b/tests/effects/tfuncs_cannot_mutate_simple.nim
@@ -1,8 +1,6 @@
 discard """
-  errormsg: "'edit' can have side effects"
-  nimout: '''an object reachable from 'x' is potentially mutated
-tfuncs_cannot_mutate_simple.nim(17, 4) the mutation is here'''
-  line: 16
+  errormsg: '''cannot mutate location x.data within a strict func'''
+  line: 15
 """
 
 {.experimental: "strictFuncs".}
diff --git a/tests/effects/tgcsafe.nim b/tests/effects/tgcsafe.nim
index 363624f19..cfac3ddd8 100644
--- a/tests/effects/tgcsafe.nim
+++ b/tests/effects/tgcsafe.nim
@@ -1,5 +1,5 @@
 discard """
-  errormsg: "'mainUnsafe' is not GC-safe"
+  errormsg: "'mainUnsafe' is not GC-safe as it performs an indirect call here"
   line: 26
   cmd: "nim $target --hints:on --threads:on $options $file"
 """
@@ -13,7 +13,7 @@ proc myproc(i: int) {.gcsafe.} =
   if isNil(global_proc):
     return
 
-proc mymap(x: proc ()) =
+proc mymap(x: proc ()) {.effectsOf: x.} =
   x()
 
 var
diff --git a/tests/effects/tgcsafe2.nim b/tests/effects/tgcsafe2.nim
index 07da4e3f8..6268592a9 100644
--- a/tests/effects/tgcsafe2.nim
+++ b/tests/effects/tgcsafe2.nim
@@ -1,5 +1,5 @@
 discard """
-  errormsg: '''type mismatch: got <proc (s: string){.locks: 0.}>'''
+  errormsg: '''type mismatch: got <proc (s: string)>'''
   line: 11
 """
 #5620
diff --git a/tests/effects/tgcsafe3.nim b/tests/effects/tgcsafe3.nim
index 5137efe4c..36ea5112c 100644
--- a/tests/effects/tgcsafe3.nim
+++ b/tests/effects/tgcsafe3.nim
@@ -1,5 +1,5 @@
 discard """
-  errormsg: "'myproc' is not GC-safe as it accesses 'global_proc' which is a global using GC'ed memory"
+  errormsg: "'myproc' is not GC-safe as it calls 'global_proc'"
   line: 12
   cmd: "nim $target --hints:on --threads:on $options $file"
 """
diff --git a/tests/effects/thooks.nim b/tests/effects/thooks.nim
new file mode 100644
index 000000000..23cc005cd
--- /dev/null
+++ b/tests/effects/thooks.nim
@@ -0,0 +1,16 @@
+discard """
+  matrix: "--warningAsError:Effect"
+"""
+
+import std/isolation
+
+# bug #23129
+type
+  Thing = object
+    x: string
+
+proc send(x: string) =
+  let wrapper = Thing(x: x)
+  discard isolate(wrapper)
+
+send("la")
\ No newline at end of file
diff --git a/tests/effects/tlaxeffects.nim b/tests/effects/tlaxeffects.nim
new file mode 100644
index 000000000..7eedc372a
--- /dev/null
+++ b/tests/effects/tlaxeffects.nim
@@ -0,0 +1,11 @@
+discard """
+  cmd: "nim $target $options --legacy:laxEffects $file"
+"""
+
+
+type
+  Foo = object
+    bar: seq[Foo]
+
+proc `==`(a, b: Foo): bool =
+  a.bar == b.bar
diff --git a/tests/effects/tnestedprocs.nim b/tests/effects/tnestedprocs.nim
new file mode 100644
index 000000000..125896d44
--- /dev/null
+++ b/tests/effects/tnestedprocs.nim
@@ -0,0 +1,63 @@
+discard """
+  cmd: "nim check --hints:off $file"
+  nimout: '''tnestedprocs.nim(27, 8) Error: 'inner' can have side effects
+> tnestedprocs.nim(29, 13) Hint: 'inner' calls `.sideEffect` 'outer2'
+>> tnestedprocs.nim(26, 6) Hint: 'outer2' called by 'inner'
+
+tnestedprocs.nim(45, 8) Error: 'inner' can have side effects
+> tnestedprocs.nim(47, 13) Hint: 'inner' calls `.sideEffect` 'outer6'
+>> tnestedprocs.nim(44, 6) Hint: 'outer6' called by 'inner'
+
+tnestedprocs.nim(58, 41) Error: type mismatch: got <proc ()> but expected 'proc (){.closure, noSideEffect.}'
+  Pragma mismatch: got '{..}', but expected '{.noSideEffect.}'.
+'''
+  errormsg: "type mismatch: got <proc ()> but expected 'proc (){.closure, noSideEffect.}'"
+"""
+{.experimental: "strictEffects".}
+proc outer {.noSideEffect.} =
+  proc inner(p: int) =
+    if p == 0:
+      outer()
+
+  inner(4)
+
+outer()
+
+proc outer2 =
+  proc inner(p: int) {.noSideEffect.} =
+    if p == 0:
+      outer2()
+
+  inner(4)
+
+outer2()
+
+proc outer3(p: int) {.noSideEffect.} =
+  proc inner(p: int) {.noSideEffect.} =
+    if p == 0:
+      p.outer3()
+
+  inner(4)
+
+outer3(5)
+
+proc outer6 =
+  proc inner(p: int) {.noSideEffect.} =
+    if p == 0:
+      outer6()
+
+  inner(4)
+  echo "bad"
+
+outer6()
+
+
+proc outer4 =
+  proc inner(p: int) {.noSideEffect.} =
+    if p == 0:
+      let x: proc () {.noSideEffect.} = outer4
+      x()
+
+  inner(4)
+
+outer4()
diff --git a/tests/effects/tnosideeffect.nim b/tests/effects/tnosideeffect.nim
index 9cabb35a2..9fc2f74d4 100644
--- a/tests/effects/tnosideeffect.nim
+++ b/tests/effects/tnosideeffect.nim
@@ -1,5 +1,5 @@
 block: # `.noSideEffect`
-  func foo(bar: proc(): int): int = bar()
+  func foo(bar: proc(): int): int {.effectsOf: bar.} = bar()
   var count = 0
   proc fn1(): int = 1
   proc fn2(): int = (count.inc; count)
diff --git a/tests/effects/toutparam.nim b/tests/effects/toutparam.nim
deleted file mode 100644
index 00572aa6b..000000000
--- a/tests/effects/toutparam.nim
+++ /dev/null
@@ -1,28 +0,0 @@
-discard """
-  cmd: '''nim c --warningAsError[Uninit]:on --skipCfg --skipParentCfg $file'''
-  errormsg: "use explicit initialization of 'x' for clarity [Uninit]"
-  line: 24
-  disabled: "true"
-"""
-
-proc gah[T](x: out T) =
-  x = 3
-
-proc main =
-  var a: array[2, int]
-  var x: int
-  gah(x)
-  a[0] = 3
-  a[x] = 3
-  echo x
-
-main()
-
-proc mainB =
-  var a: array[2, int]
-  var x: int
-  a[0] = 3
-  a[x] = 3
-  echo x
-
-mainB()
diff --git a/tests/effects/tstrict_caseobjects.nim b/tests/effects/tstrict_caseobjects.nim
new file mode 100644
index 000000000..20bc810e0
--- /dev/null
+++ b/tests/effects/tstrict_caseobjects.nim
@@ -0,0 +1,47 @@
+discard """
+  errormsg: "field access outside of valid case branch: x.x"
+  line: 45
+"""
+
+{.experimental: "strictCaseObjects".}
+
+type
+  NodeKind = enum
+    nkParent,
+    nkChild
+  
+  Node {.acyclic.} = ref object
+    case kind: NodeKind
+    of nkParent:
+      children: seq[Node]
+    of nkChild:
+      name: string
+
+let list = @[Node(kind: nkParent, children: @[]), Node(kind: nkChild, name: "hello")]
+for node in list:
+  case node.kind
+  of nkChild: 
+    echo $node.name # here this time there is a warning
+  else: discard
+
+
+type
+  Foo = object
+    case b: bool
+    of false:
+      s: string
+    of true:
+      x: int
+
+var x = Foo(b: true, x: 4)
+case x.b
+of true:
+  echo x.x
+of false:
+  echo "no"
+
+case x.b
+of false:
+  echo x.x
+of true:
+  echo "no"
diff --git a/tests/effects/tstrict_effects.nim b/tests/effects/tstrict_effects.nim
new file mode 100644
index 000000000..eee8fb71a
--- /dev/null
+++ b/tests/effects/tstrict_effects.nim
@@ -0,0 +1,27 @@
+discard """
+  errormsg: "s1 can raise an unlisted exception: CatchableError"
+  line: 27
+"""
+
+{.push warningAsError[Effect]: on.}
+{.experimental: "strictEffects".}
+
+# bug #18376
+
+{.push raises: [Defect].}
+type Call = proc (x: int): int {.gcsafe, raises: [Defect, CatchableError].}
+
+type Bar* = object
+  foo*: Call
+
+proc passOn*(x: Call) = discard
+
+proc barCal(b: var Bar, s: string, s1: Call) =
+  #compiler complains that his line can throw CatchableError
+  passOn s1
+
+
+proc passOnB*(x: Call) {.effectsOf: x.} = discard
+
+proc barCal2(b: var Bar, s: string, s1: Call) =
+  passOnB s1
diff --git a/tests/effects/tstrict_effects2.nim b/tests/effects/tstrict_effects2.nim
new file mode 100644
index 000000000..acc0a0540
--- /dev/null
+++ b/tests/effects/tstrict_effects2.nim
@@ -0,0 +1,28 @@
+discard """
+  errormsg: "can raise an unlisted exception: Exception"
+  line: 23
+"""
+
+{.push warningAsError[Effect]: on.}
+{.experimental: "strictEffects".}
+
+# bug #13905
+
+proc atoi(v: cstring): cint {.importc: "atoi", cdecl, raises: [].}
+
+type Conv = proc(v: cstring): cint {.cdecl, raises: [].}
+
+var x: Conv = atoi
+
+# bug #17475
+
+type
+  Callback = proc()
+
+proc f(callback: Callback) {.raises: [].} =
+  callback()
+
+proc main =
+  f(proc () = raise newException(IOError, "IO"))
+
+main()
diff --git a/tests/effects/tstrict_effects3.nim b/tests/effects/tstrict_effects3.nim
new file mode 100644
index 000000000..0d98a0343
--- /dev/null
+++ b/tests/effects/tstrict_effects3.nim
@@ -0,0 +1,57 @@
+discard """
+  action: compile
+"""
+
+{.push warningAsError[Effect]: on.}
+
+{.experimental: "strictEffects".}
+
+proc fn(a: int, p1, p2: proc()) {.effectsOf: p1.} =
+  if a == 7:
+    p1()
+  if a<0:
+    raise newException(ValueError, $a)
+
+proc main() {.raises: [ValueError].} =
+  fn(1, proc()=discard, proc() = raise newException(IOError, "foo"))
+main()
+
+# bug #19159
+
+import macros
+
+func mkEnter() =
+  template helper =
+    discard
+  when defined pass:
+    helper()
+  else:
+    let ast = getAst(helper())
+
+
+# bug #6559
+type
+  SafeFn = proc (): void {. raises: [] }
+
+proc ok() {. raises: [] .} = discard
+proc fail() {. raises: [] .}
+
+let f1 : SafeFn = ok
+let f2 : SafeFn = fail
+
+
+proc fail() = discard
+f1()
+f2()
+
+import std/json
+
+# bug #22254
+proc senri(a, b: seq[JsonNode]) {.raises: [].} = discard a == b
+
+# bug #22253
+proc serika() {.raises: [].} = discard default(JsonNode) == nil
+
+senri(@[newJBool(true)], @[newJBool(false)])
+serika()
+
diff --git a/tests/effects/tstrict_effects_sort.nim b/tests/effects/tstrict_effects_sort.nim
new file mode 100644
index 000000000..8928ed0d3
--- /dev/null
+++ b/tests/effects/tstrict_effects_sort.nim
@@ -0,0 +1,27 @@
+discard """
+  errormsg: "cmpE can raise an unlisted exception: Exception"
+  line: 27
+"""
+
+{.push warningAsError[Effect]: on.}
+
+{.experimental: "strictEffects".}
+
+import algorithm
+
+type
+  MyInt = distinct int
+
+var toSort = @[MyInt 1, MyInt 2, MyInt 3]
+
+proc cmpN(a, b: MyInt): int =
+  cmp(a.int, b.int)
+
+proc harmless {.raises: [].} =
+  toSort.sort cmpN
+
+proc cmpE(a, b: MyInt): int {.raises: [Exception].} =
+  cmp(a.int, b.int)
+
+proc harmfull {.raises: [].} =
+  toSort.sort cmpE
diff --git a/tests/effects/tstrict_funcs.nim b/tests/effects/tstrict_funcs.nim
index 044bc7ee1..9d20f5d7e 100644
--- a/tests/effects/tstrict_funcs.nim
+++ b/tests/effects/tstrict_funcs.nim
@@ -27,3 +27,20 @@ block:
 
   var x = @[0, 1]
   let z = x &&& 2
+
+
+func copy[T](x: var openArray[T]; y: openArray[T]) =
+  for i in 0..high(x):
+    x[i] = y[i]
+
+type
+  R = ref object
+    a, b: R
+    data: string
+
+proc main =
+  var a, b: array[3, R]
+  b = [R(data: "a"), R(data: "b"), R(data: "c")]
+  copy a, b
+
+main()
diff --git a/tests/effects/tstrict_funcs_imports.nim b/tests/effects/tstrict_funcs_imports.nim
index 4e9b9fe66..bf68b61b2 100644
--- a/tests/effects/tstrict_funcs_imports.nim
+++ b/tests/effects/tstrict_funcs_imports.nim
@@ -7,11 +7,19 @@ discard """
 when defined(linux):
   import linenoise
 
+when defined(nimPreviewSlimSystem):
+  import std/[
+    assertions,
+    formatfloat,
+    objectdollar,
+    syncio,
+    widestrs,
+  ]
+
 import
   algorithm,
   asyncdispatch,
   asyncfile,
-  asyncftpclient,
   asyncfutures,
   asynchttpserver,
   asyncmacro,
@@ -31,11 +39,6 @@ import
   cpuload,
   critbits,
   cstrutils,
-  db_common,
-  db_mysql,
-  db_odbc,
-  db_postgres,
-  db_sqlite,
   deques,
   distros,
   dynlib,
@@ -63,7 +66,6 @@ import
   macros,
   marshal,
   math,
-  md5,
   memfiles,
   mersenne,
   mimetypes,
@@ -84,10 +86,9 @@ import
   parseutils,
   parsexml,
   pathnorm,
-  # pegs,
+  pegs,
   posix_utils,
   prelude,
-  punycode,
   random,
   rationals,
   rdstdin,
@@ -102,7 +103,6 @@ import
   sets,
   sharedlist,
   sharedtables,
-  smtp,
   ssl_certs,
   ssl_config,
   stats,
@@ -154,7 +154,6 @@ import std/[
   monotimes,
   packedsets,
   setutils,
-  sha1,
   socketstreams,
   stackframes,
   sums,
diff --git a/tests/effects/tstrict_funcs_imports_js.nim b/tests/effects/tstrict_funcs_imports_js.nim
index b7fcd343a..667887ff0 100644
--- a/tests/effects/tstrict_funcs_imports_js.nim
+++ b/tests/effects/tstrict_funcs_imports_js.nim
@@ -7,7 +7,6 @@ discard """
 import
   asyncjs,
   dom,
-  dom_extensions,
   jsconsole,
   jsffi,
   jsre
diff --git a/tests/effects/tstrictfuncs_misc.nim b/tests/effects/tstrictfuncs_misc.nim
new file mode 100644
index 000000000..8c573bb3a
--- /dev/null
+++ b/tests/effects/tstrictfuncs_misc.nim
@@ -0,0 +1,65 @@
+discard """
+  action: compile
+"""
+
+{.experimental: "strictFuncs".}
+
+func sortedFake1[T](a: openArray[T]): seq[T] =
+  for i in 0 .. a.high: result.add a[i]
+func sortedFake2[T](a: openArray[T]): seq[T] =
+  result = newSeq[T](a.len)
+  for i in 0 .. a.high: result[i] = a[i]
+type Foo1 = object
+type Foo2 = ref object
+block:
+  let a1 = sortedFake1([Foo1()]) # ok
+  let a2 = sortedFake1([Foo2()]) # ok
+block:
+  let a1 = sortedFake2([Foo1()]) # ok
+  let a2 = sortedFake2([Foo2()]) # error: Error: 'sortedFake2' can have side effects
+
+
+import std/sequtils
+type Foob = ref object
+  x: int
+let a1 = zip(@[1,2], @[1,2]) # ok
+let a2 = zip(@[Foob(x: 1)], @[Foob(x: 2)]) # error in 1.6.0 RC2, but not 1.4.x
+
+
+# bug #20863
+type
+  Fooc = ref object
+
+func twice(foo: Fooc) =
+  var a = newSeq[Fooc](2)
+  a[0] = foo # No error.
+  a[1] = foo # Error: 'twice' can have side effects.
+
+let foo = Fooc()
+twice(foo)
+
+# bug #17387
+import json
+
+func parseColumn(columnNode: JsonNode) =
+  let columnName = columnNode["name"].str
+
+parseColumn(%*{"a": "b"})
+
+type
+  MyTable = object
+    data: seq[int]
+
+  JsonNode3 = ref object
+    fields: MyTable
+
+proc `[]`(t: MyTable, key: string): int =
+  result = t.data[0]
+
+proc `[]`(x: JsonNode3, key: string): int =
+  result = x.fields[key]
+
+func parseColumn(columnNode: JsonNode3) =
+  var columnName = columnNode["test"]
+
+parseColumn(JsonNode3())