Here's a simple proof of concept: import macros type Mut = object proc messUpMySeq(s: var seq[int]) {.tags: [Mut].} = s.add(123) iterator foo[T](s: seq[T]): T = var i = 0 while i < s.len: yield s[i] inc i macro safeFor(binding, it, body): untyped = quote do: (proc() {.tags: [].} = for `binding` in `it`: `body`)() var s = @[1, 2, 3, 4, 5] safeFor t, foo(s): messUpMySeq(s) echo t
Unfortunately, this requires a custom `for`.