.forbids pragma: defining forbidden tags (#20050)
* .forbids pragma: defining illegal effects for proc types This patch intends to define the opposite of the .tags pragma: a way to define effects which are not allowed in a proc. * updated documentation and changelogs for the forbids pragma * renamed notTagEffects to forbiddenEffects * corrected issues of forbids pragma the forbids pragma didn't handle simple restrictions properly and it also had issues with subtyping * removed incorrect character from changelog * added test to cover the interaction of methods and the forbids pragma * covering the interaction of the tags and forbids pragmas * updated manual about the forbids pragma * removed useless statement * corrected the subtyping of proc types using the forbids pragma * updated manual for the forbids pragma * updated documentations for forbids pragma * updated nim docs * updated docs with rsttester.nim * regenerated documentation * updated rst docs * Update changelog.md Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> * updated changelog * corrected typo Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
This commit is contained in:
parent
62b81d7f10
commit
efd5c571bf
24 changed files with 405 additions and 71 deletions
21
tests/effects/teffects11.nim
Normal file
21
tests/effects/teffects11.nim
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
discard """
|
||||
action: compile
|
||||
errormsg: "type mismatch: got <proc (x: int){.gcsafe, locks: 0.}>"
|
||||
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)
|
||||
52
tests/effects/teffects12.nim
Normal file
52
tests/effects/teffects12.nim
Normal file
|
|
@ -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)
|
||||
19
tests/effects/teffects13.nim
Normal file
19
tests/effects/teffects13.nim
Normal file
|
|
@ -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()
|
||||
15
tests/effects/teffects14.nim
Normal file
15
tests/effects/teffects14.nim
Normal file
|
|
@ -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()
|
||||
18
tests/effects/teffects15.nim
Normal file
18
tests/effects/teffects15.nim
Normal file
|
|
@ -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()
|
||||
20
tests/effects/teffects16.nim
Normal file
20
tests/effects/teffects16.nim
Normal file
|
|
@ -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")
|
||||
17
tests/effects/teffects17.nim
Normal file
17
tests/effects/teffects17.nim
Normal file
|
|
@ -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")
|
||||
19
tests/effects/teffects18.nim
Normal file
19
tests/effects/teffects18.nim
Normal file
|
|
@ -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)
|
||||
23
tests/effects/teffects19.nim
Normal file
23
tests/effects/teffects19.nim
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
discard """
|
||||
action: compile
|
||||
errormsg: "type mismatch: got <proc (i: int){.gcsafe, locks: 0.}>"
|
||||
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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue