fixes #19162; enable strictEffects for v2 (#19380)

* enable stricteffects
* add gcsafe
* fix tests
* use func
* fixes pegs tests
* explicitly mark repr related procs with noSideEffect
* add nimLegacyEffects
* change URL
* fixes docopt
* add `raises: []` to repr
* fixes weave
* fixes nimyaml
* fixes glob
* fixes parsetoml
* Apply suggestions from code review
* Update testament/important_packages.nim
* add legacy:laxEffects
This commit is contained in:
ringabout 2022-10-15 20:07:40 +08:00 • committed by GitHub
commit 1e15f975b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 38 additions and 39 deletions

View file

@ -89,6 +89,9 @@
- ORC is now the default memory management strategy. Use - ORC is now the default memory management strategy. Use
`--mm:refc` for a transition period. `--mm:refc` for a transition period.
- `strictEffects` are no longer experimental.
Use `legacy:laxEffects` to keep backward compatibility.
- The `gorge`/`staticExec` calls will now return a descriptive message in the output - The `gorge`/`staticExec` calls will now return a descriptive message in the output
if the execution fails for whatever reason. To get back legacy behaviour use `-d:nimLegacyGorgeErrors`. if the execution fails for whatever reason. To get back legacy behaviour use `-d:nimLegacyGorgeErrors`.

View file

@ -30,11 +30,6 @@ define:useStdoutAsStdmsg
warning[ObservableStores]: off warning[ObservableStores]: off
@end @end
@if nimHasEffectsOf:
experimental:strictEffects
warningAsError:Effect:on
@end
@if nimHasWarningAsError: @if nimHasWarningAsError:
warningAsError:GcUnsafe2:on warningAsError:GcUnsafe2:on
@end @end

View file

@ -228,6 +228,8 @@ type
## Historically and especially in version 1.0.0 of the language ## Historically and especially in version 1.0.0 of the language
## conversions to unsigned numbers were checked. In 1.0.4 they ## conversions to unsigned numbers were checked. In 1.0.4 they
## are not anymore. ## are not anymore.
laxEffects
## Lax effects system prior to Nim 2.0.
SymbolFilesOption* = enum SymbolFilesOption* = enum
disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest

View file

@ -495,7 +495,7 @@ proc isIndirectCall(tracked: PEffects; n: PNode): bool =
if n.kind != nkSym: if n.kind != nkSym:
result = true result = true
elif n.sym.kind == skParam: elif n.sym.kind == skParam:
if strictEffects in tracked.c.features: if laxEffects notin tracked.c.config.legacyFeatures:
if tracked.owner == n.sym.owner and sfEffectsDelayed in n.sym.flags: if tracked.owner == n.sym.owner and sfEffectsDelayed in n.sym.flags:
result = false # it is not a harmful call result = false # it is not a harmful call
else: else:
@ -581,7 +581,7 @@ proc isOwnedProcVar(tracked: PEffects; n: PNode): bool =
tracked.owner == n.sym.owner tracked.owner == n.sym.owner
#if result and sfPolymorphic notin n.sym.flags: #if result and sfPolymorphic notin n.sym.flags:
# echo tracked.config $ n.info, " different here!" # echo tracked.config $ n.info, " different here!"
if strictEffects in tracked.c.features: if laxEffects notin tracked.c.config.legacyFeatures:
result = result and sfEffectsDelayed in n.sym.flags result = result and sfEffectsDelayed in n.sym.flags
proc isNoEffectList(n: PNode): bool {.inline.} = proc isNoEffectList(n: PNode): bool {.inline.} =
@ -598,7 +598,7 @@ proc trackOperandForIndirectCall(tracked: PEffects, n: PNode, formals: PType; ar
# assume indirect calls are taken here: # assume indirect calls are taken here:
if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit and if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit and
not isTrival(caller) and not isTrival(caller) and
((param != nil and sfEffectsDelayed in param.flags) or strictEffects notin tracked.c.features): ((param != nil and sfEffectsDelayed in param.flags) or laxEffects in tracked.c.config.legacyFeatures):
internalAssert tracked.config, op.n[0].kind == nkEffectList internalAssert tracked.config, op.n[0].kind == nkEffectList
var effectList = op.n[0] var effectList = op.n[0]
@ -844,7 +844,7 @@ proc trackCall(tracked: PEffects; n: PNode) =
assumeTheWorst(tracked, n, op) assumeTheWorst(tracked, n, op)
gcsafeAndSideeffectCheck() gcsafeAndSideeffectCheck()
else: else:
if strictEffects in tracked.c.features and a.kind == nkSym and if laxEffects notin tracked.c.config.legacyFeatures and a.kind == nkSym and
a.sym.kind in routineKinds: a.sym.kind in routineKinds:
propagateEffects(tracked, n, a.sym) propagateEffects(tracked, n, a.sym)
else: else:

View file

@ -26,3 +26,4 @@ when defined(windows) and not defined(booting):
switch("define", "nimRawSetjmp") switch("define", "nimRawSetjmp")
switch("define", "nimVersion:" & NimVersion) switch("define", "nimVersion:" & NimVersion)

View file

@ -4952,8 +4952,7 @@ Effect system
============= =============
**Note**: The rules for effect tracking changed with the release of version **Note**: The rules for effect tracking changed with the release of version
1.6 of the Nim compiler. This section describes the new rules that are activated 1.6 of the Nim compiler.
via `--experimental:strictEffects`.
Exception tracking Exception tracking
@ -5073,7 +5072,6 @@ conservative in its effect analysis:
```nim test = "nim c $1" status = 1 ```nim test = "nim c $1" status = 1
{.push warningAsError[Effect]: on.} {.push warningAsError[Effect]: on.}
{.experimental: "strictEffects".}
import algorithm import algorithm

View file

@ -561,7 +561,7 @@ template matchOrParse(mopProc: untyped) =
# procs. For the former, *enter* and *leave* event handler code generators # procs. For the former, *enter* and *leave* event handler code generators
# are provided which just return *discard*. # are provided which just return *discard*.
proc mopProc(s: string, p: Peg, start: int, c: var Captures): int = proc mopProc(s: string, p: Peg, start: int, c: var Captures): int {.gcsafe.} =
proc matchBackRef(s: string, p: Peg, start: int, c: var Captures): int = proc matchBackRef(s: string, p: Peg, start: int, c: var Captures): int =
# Parse handler code must run in an *of* clause of its own for each # Parse handler code must run in an *of* clause of its own for each
# *PegKind*, so we encapsulate the identical clause body for # *PegKind*, so we encapsulate the identical clause body for

View file

@ -1701,7 +1701,7 @@ proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} =
result = s[L] result = s[L]
setLen(s, L) setLen(s, L)
proc `==`*[T: tuple|object](x, y: T): bool = func `==`*[T: tuple|object](x, y: T): bool =
## Generic `==` operator for tuples that is lifted from the components. ## Generic `==` operator for tuples that is lifted from the components.
## of `x` and `y`. ## of `x` and `y`.
for a, b in fields(x, y): for a, b in fields(x, y):

View file

@ -31,7 +31,7 @@ proc repr*(x: bool): string {.magic: "BoolToStr", noSideEffect.}
## repr for a boolean argument. Returns `x` ## repr for a boolean argument. Returns `x`
## converted to the string "false" or "true". ## converted to the string "false" or "true".
proc repr*(x: char): string {.noSideEffect.} = proc repr*(x: char): string {.noSideEffect, raises: [].} =
## repr for a character argument. Returns `x` ## repr for a character argument. Returns `x`
## converted to an escaped string. ## converted to an escaped string.
## ##
@ -47,7 +47,7 @@ proc repr*(x: char): string {.noSideEffect.} =
result.add x result.add x
result.add '\'' result.add '\''
proc repr*(x: string | cstring): string {.noSideEffect.} = proc repr*(x: string | cstring): string {.noSideEffect, raises: [].} =
## repr for a string argument. Returns `x` ## repr for a string argument. Returns `x`
## converted to a quoted and escaped string. ## converted to a quoted and escaped string.
result.add '\"' result.add '\"'
@ -63,7 +63,7 @@ proc repr*(x: string | cstring): string {.noSideEffect.} =
result.add x[i] result.add x[i]
result.add '\"' result.add '\"'
proc repr*[Enum: enum](x: Enum): string {.magic: "EnumToStr", noSideEffect.} proc repr*[Enum: enum](x: Enum): string {.magic: "EnumToStr", noSideEffect, raises: [].}
## repr for an enumeration argument. This works for ## repr for an enumeration argument. This works for
## any enumeration type thanks to compiler magic. ## any enumeration type thanks to compiler magic.
## ##
@ -100,7 +100,7 @@ template repr*(x: distinct): string =
template repr*(t: typedesc): string = $t template repr*(t: typedesc): string = $t
proc reprObject[T: tuple|object](res: var string, x: T) = proc reprObject[T: tuple|object](res: var string, x: T) {.noSideEffect, raises: [].} =
res.add '(' res.add '('
var firstElement = true var firstElement = true
const isNamed = T is object or isNamedTuple(T) const isNamed = T is object or isNamedTuple(T)
@ -121,7 +121,7 @@ proc reprObject[T: tuple|object](res: var string, x: T) =
res.add(')') res.add(')')
proc repr*[T: tuple|object](x: T): string = proc repr*[T: tuple|object](x: T): string {.noSideEffect, raises: [].} =
## Generic `repr` operator for tuples that is lifted from the components ## Generic `repr` operator for tuples that is lifted from the components
## of `x`. Example: ## of `x`. Example:
## ##
@ -133,7 +133,7 @@ proc repr*[T: tuple|object](x: T): string =
result = $typeof(x) result = $typeof(x)
reprObject(result, x) reprObject(result, x)
proc repr*[T](x: ref T | ptr T): string = proc repr*[T](x: ref T | ptr T): string {.noSideEffect, raises: [].} =
if isNil(x): return "nil" if isNil(x): return "nil"
when T is object: when T is object:
result = $typeof(x) result = $typeof(x)
@ -142,7 +142,7 @@ proc repr*[T](x: ref T | ptr T): string =
result = when typeof(x) is ref: "ref " else: "ptr " result = when typeof(x) is ref: "ref " else: "ptr "
result.add repr(x[]) result.add repr(x[])
proc collectionToRepr[T](x: T, prefix, separator, suffix: string): string = proc collectionToRepr[T](x: T, prefix, separator, suffix: string): string {.noSideEffect, raises: [].} =
result = prefix result = prefix
var firstElement = true var firstElement = true
for value in items(x): for value in items(x):

View file

@ -401,7 +401,7 @@ macro convertSexp*(x: untyped): untyped =
## `%` for every element. ## `%` for every element.
result = toSexp(x) result = toSexp(x)
proc `==`* (a, b: SexpNode): bool {.noSideEffect.} = func `==`* (a, b: SexpNode): bool =
## Check two nodes for equality ## Check two nodes for equality
if a.isNil: if a.isNil:
if b.isNil: return true if b.isNil: return true

View file

@ -60,15 +60,15 @@ pkg "criterion", allowFailure = true # pending https://github.com/disruptek/crit
pkg "datamancer" pkg "datamancer"
pkg "dashing", "nim c tests/functional.nim" pkg "dashing", "nim c tests/functional.nim"
pkg "delaunay", url = "https://github.com/nim-lang/DelaunayNim", useHead = true pkg "delaunay", url = "https://github.com/nim-lang/DelaunayNim", useHead = true
pkg "docopt" pkg "docopt", url = "https://github.com/nim-lang/docopt.nim", useHead = true
pkg "easygl", "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl" pkg "easygl", "nim c -o:egl -r src/easygl.nim", "https://github.com/jackmott/easygl"
pkg "elvis" pkg "elvis"
pkg "fidget" pkg "fidget"
pkg "fragments", "nim c -r fragments/dsl.nim", allowFailure = true # pending https://github.com/nim-lang/packages/issues/2115 pkg "fragments", "nim c -r fragments/dsl.nim", allowFailure = true # pending https://github.com/nim-lang/packages/issues/2115
pkg "fusion" pkg "fusion"
pkg "gara" pkg "gara"
pkg "glob" pkg "glob", url = "https://github.com/nim-lang/glob", useHead = true
pkg "ggplotnim", "nim c -d:noCairo -r tests/tests.nim" pkg "ggplotnim", "nim c -d:noCairo -r tests/tests.nim", url = "https://github.com/nim-lang/ggplotnim", useHead = true
pkg "gittyup", "nimble test", "https://github.com/disruptek/gittyup", allowFailure = true pkg "gittyup", "nimble test", "https://github.com/disruptek/gittyup", allowFailure = true
pkg "gnuplot", "nim c gnuplot.nim" pkg "gnuplot", "nim c gnuplot.nim"
# pkg "gram", "nim c -r --gc:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram" # pkg "gram", "nim c -r --gc:arc --define:danger tests/test.nim", "https://github.com/disruptek/gram"
@ -109,7 +109,7 @@ pkg "nimongo", "nimble test_ci", allowFailure = true
pkg "nimph", "nimble test", "https://github.com/disruptek/nimph", allowFailure = true pkg "nimph", "nimble test", "https://github.com/disruptek/nimph", allowFailure = true
pkg "nimPNG", useHead = true pkg "nimPNG", useHead = true
pkg "nimpy", "nim c -r tests/nimfrompy.nim" pkg "nimpy", "nim c -r tests/nimfrompy.nim"
pkg "nimquery" pkg "nimquery", url = "https://github.com/nim-lang/nimquery", useHead = true
pkg "nimsl" pkg "nimsl"
pkg "nimsvg" pkg "nimsvg"
pkg "nimterop", "nimble minitest" pkg "nimterop", "nimble minitest"
@ -121,7 +121,7 @@ pkg "npeg", "nimble testarc"
pkg "numericalnim", "nimble nimCI" pkg "numericalnim", "nimble nimCI"
pkg "optionsutils" pkg "optionsutils"
pkg "ormin", "nim c -o:orminn ormin.nim" pkg "ormin", "nim c -o:orminn ormin.nim"
pkg "parsetoml" pkg "parsetoml", url = "https://github.com/nim-lang/parsetoml", useHead = true
pkg "patty" pkg "patty"
pkg "pixie" pkg "pixie"
pkg "plotly", "nim c examples/all.nim" pkg "plotly", "nim c examples/all.nim"
@ -146,7 +146,7 @@ pkg "strslice"
pkg "strunicode", "nim c -r --mm:refc src/strunicode.nim" pkg "strunicode", "nim c -r --mm:refc src/strunicode.nim"
pkg "supersnappy" pkg "supersnappy"
pkg "synthesis" pkg "synthesis"
pkg "telebot", "nim c -o:tbot -r src/telebot.nim" pkg "telebot", "nim c -o:tbot -r src/telebot.nim", url = "https://github.com/nim-lang/telebot.nim", useHead = true
pkg "tempdir" pkg "tempdir"
pkg "templates" pkg "templates"
pkg "tensordsl", "nim c -r --mm:refc tests/tests.nim", "https://krux02@bitbucket.org/krux02/tensordslnim.git" pkg "tensordsl", "nim c -r --mm:refc tests/tests.nim", "https://krux02@bitbucket.org/krux02/tensordslnim.git"
@ -158,11 +158,11 @@ pkg "tiny_sqlite"
pkg "unicodedb", "nim c -d:release -r tests/tests.nim" pkg "unicodedb", "nim c -d:release -r tests/tests.nim"
pkg "unicodeplus", "nim c -d:release -r tests/tests.nim" pkg "unicodeplus", "nim c -d:release -r tests/tests.nim"
pkg "unpack" pkg "unpack"
pkg "weave", "nimble install -y cligen synthesis;nimble test_gc_arc" pkg "weave", "nimble install -y cligen synthesis;nimble test_gc_arc", url = "https://github.com/nim-lang/weave", useHead = true
pkg "websocket", "nim c websocket.nim" pkg "websocket", "nim c websocket.nim"
pkg "winim", "nim c winim.nim" pkg "winim", "nim c winim.nim"
pkg "with" pkg "with"
pkg "ws", allowFailure = true pkg "ws", allowFailure = true
pkg "yaml", "nim c -r test/tserialization.nim" pkg "yaml", "nim c -r test/tserialization.nim", url = "https://github.com/nim-lang/NimYAML", useHead = true
pkg "zero_functional", "nim c -r -d:nimNoLentIterators test.nim" pkg "zero_functional", "nim c -r -d:nimNoLentIterators test.nim"
pkg "zippy" pkg "zippy"

View file

@ -33,7 +33,7 @@ py
py py
px px
6 6
proc (){.closure, gcsafe.} proc (){.closure, noSideEffect, gcsafe.}
''' '''
""" """

View file

@ -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: # unknown call that might raise anything, but valid:
x() x()

View file

@ -1,5 +1,5 @@
discard """ discard """
errormsg: "'mainUnsafe' is not GC-safe" errormsg: "'mainUnsafe' is not GC-safe as it performs an indirect call here"
line: 26 line: 26
cmd: "nim $target --hints:on --threads:on $options $file" cmd: "nim $target --hints:on --threads:on $options $file"
""" """
@ -13,7 +13,7 @@ proc myproc(i: int) {.gcsafe.} =
if isNil(global_proc): if isNil(global_proc):
return return
proc mymap(x: proc ()) = proc mymap(x: proc ()) {.effectsOf: x.} =
x() x()
var var

View file

@ -1,5 +1,5 @@
block: # `.noSideEffect` block: # `.noSideEffect`
func foo(bar: proc(): int): int = bar() func foo(bar: proc(): int): int {.effectsOf: bar.} = bar()
var count = 0 var count = 0
proc fn1(): int = 1 proc fn1(): int = 1
proc fn2(): int = (count.inc; count) proc fn2(): int = (count.inc; count)

View file

@ -106,9 +106,9 @@ block:
block: block:
var var
pStack: seq[string] = @[] pStack {.threadvar.}: seq[string]
valStack: seq[float] = @[] valStack {.threadvar.}: seq[float]
opStack = "" opStack {.threadvar.}: string
let let
parseArithExpr = pegAst.eventParser: parseArithExpr = pegAst.eventParser:
pkNonTerminal: pkNonTerminal: