implemented strictCaseObjects (#20608)

* implemented strictCaseObjects

* changelog update
This commit is contained in:
Andreas Rumpf
2022-10-21 06:55:52 +02:00
committed by GitHub
parent 4aa67ad7fd
commit 76763f51aa
6 changed files with 80 additions and 8 deletions

View File

@@ -1,8 +1,8 @@
# v1.8.x - yyyy-mm-dd
# v2.0.0 - yyyy-mm-dd
## Changes affecting backward compatibility
- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response, it followed Apache HttpClient(Java), http(go) and .Net HttpWebResponse(C#) behavior. Previously raise `ValueError`.
- `httpclient.contentLength` default to `-1` if the Content-Length header is not set in the response, it followed Apache HttpClient(Java), http(go) and .Net HttpWebResponse(C#) behavior. Previously it raised `ValueError`.
- `addr` is now available for all addressable locations,
`unsafeAddr` is now deprecated and an alias for `addr`.
@@ -216,6 +216,10 @@
need to convert to `string`. On the JS backend, this is translated directly
to a `switch` statement.
- Nim now supports `out` parameters and ["strict definitions"](https://nim-lang.github.io/Nim/manual_experimental.html#strict-definitions-and-nimout-parameters).
- Nim now offers a [strict mode](https://nim-lang.github.io/Nim/manual_experimental.html#strict-case-objects) for `case objects`.
## Compiler changes
- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the

View File

@@ -1054,8 +1054,12 @@ proc buildProperFieldCheck(access, check: PNode; o: Operators): PNode =
assert check.getMagic == mNot
result = buildProperFieldCheck(access, check[1], o).neg(o)
proc checkFieldAccess*(m: TModel, n: PNode; conf: ConfigRef) =
proc checkFieldAccess*(m: TModel, n: PNode; conf: ConfigRef; produceError: bool) =
for i in 1..<n.len:
let check = buildProperFieldCheck(n[0], n[i], m.g.operators)
if check != nil and m.doesImply(check) != impYes:
message(conf, n.info, warnProveField, renderTree(n[0])); break
if produceError:
localError(conf, n.info, "field access outside of valid case branch: " & renderTree(n[0]))
else:
message(conf, n.info, warnProveField, renderTree(n[0]))
break

View File

@@ -217,7 +217,8 @@ type
strictEffects,
unicodeOperators, # deadcode
flexibleOptionalParams,
strictDefs
strictDefs,
strictCaseObjects
LegacyFeature* = enum
allowSemcheckedAstModification,

View File

@@ -665,7 +665,7 @@ proc trackCase(tracked: PEffects, n: PNode) =
let stringCase = n[0].typ != nil and skipTypes(n[0].typ,
abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString, tyCstring}
let interesting = not stringCase and interestingCaseExpr(n[0]) and
tracked.config.hasWarn(warnProveField)
(tracked.config.hasWarn(warnProveField) or strictCaseObjects in tracked.c.features)
var inter: TIntersection = @[]
var toCover = 0
for i in 1..<n.len:
@@ -1049,8 +1049,8 @@ proc track(tracked: PEffects, n: PNode) =
for i in 0..<n.len: track(tracked, n[i])
of nkCheckedFieldExpr:
track(tracked, n[0])
if tracked.config.hasWarn(warnProveField):
checkFieldAccess(tracked.guards, n, tracked.config)
if tracked.config.hasWarn(warnProveField) or strictCaseObjects in tracked.c.features:
checkFieldAccess(tracked.guards, n, tracked.config, strictCaseObjects in tracked.c.features)
of nkTryStmt: trackTryStmt(tracked, n)
of nkPragma: trackPragmaStmt(tracked, n)
of nkAsgn, nkFastAsgn, nkSinkAsgn:

View File

@@ -1941,3 +1941,39 @@ constructors that take inheritance into account.
**Note**: The implementation of "strict definitions" and "out parameters" is experimental but the concept
is solid and it is expected that eventually this mode becomes the default in later versions.
Strict case objects
===================
With `experimental: "strictCaseObjects"` *every* field access is checked to be valid at compile-time.
The field is within a `case` section of an `object`.
```nim
{.experimental: "strictCaseObjects".}
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 # valid
of false:
echo "no"
case x.b
of false:
echo x.x # error: field access outside of valid case branch: x.x
of true:
echo "no"
```
**Note**: The implementation of "strict case objects" is experimental but the concept
is solid and it is expected that eventually this mode becomes the default in later versions.

View File

@@ -0,0 +1,27 @@
discard """
errormsg: "field access outside of valid case branch: x.x"
line: 25
"""
{.experimental: "strictCaseObjects".}
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"