implemented strictCaseObjects (#20608)
* implemented strictCaseObjects * changelog update
This commit is contained in:
parent
4aa67ad7fd
commit
76763f51aa
6 changed files with 80 additions and 8 deletions
|
|
@ -1,8 +1,8 @@
|
||||||
# v1.8.x - yyyy-mm-dd
|
# v2.0.0 - yyyy-mm-dd
|
||||||
|
|
||||||
|
|
||||||
## Changes affecting backward compatibility
|
## 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,
|
- `addr` is now available for all addressable locations,
|
||||||
`unsafeAddr` is now deprecated and an alias for `addr`.
|
`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
|
need to convert to `string`. On the JS backend, this is translated directly
|
||||||
to a `switch` statement.
|
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
|
## Compiler changes
|
||||||
|
|
||||||
- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the
|
- The `gc` switch has been renamed to `mm` ("memory management") in order to reflect the
|
||||||
|
|
|
||||||
|
|
@ -1054,8 +1054,12 @@ proc buildProperFieldCheck(access, check: PNode; o: Operators): PNode =
|
||||||
assert check.getMagic == mNot
|
assert check.getMagic == mNot
|
||||||
result = buildProperFieldCheck(access, check[1], o).neg(o)
|
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:
|
for i in 1..<n.len:
|
||||||
let check = buildProperFieldCheck(n[0], n[i], m.g.operators)
|
let check = buildProperFieldCheck(n[0], n[i], m.g.operators)
|
||||||
if check != nil and m.doesImply(check) != impYes:
|
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
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,8 @@ type
|
||||||
strictEffects,
|
strictEffects,
|
||||||
unicodeOperators, # deadcode
|
unicodeOperators, # deadcode
|
||||||
flexibleOptionalParams,
|
flexibleOptionalParams,
|
||||||
strictDefs
|
strictDefs,
|
||||||
|
strictCaseObjects
|
||||||
|
|
||||||
LegacyFeature* = enum
|
LegacyFeature* = enum
|
||||||
allowSemcheckedAstModification,
|
allowSemcheckedAstModification,
|
||||||
|
|
|
||||||
|
|
@ -665,7 +665,7 @@ proc trackCase(tracked: PEffects, n: PNode) =
|
||||||
let stringCase = n[0].typ != nil and skipTypes(n[0].typ,
|
let stringCase = n[0].typ != nil and skipTypes(n[0].typ,
|
||||||
abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString, tyCstring}
|
abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString, tyCstring}
|
||||||
let interesting = not stringCase and interestingCaseExpr(n[0]) and
|
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 inter: TIntersection = @[]
|
||||||
var toCover = 0
|
var toCover = 0
|
||||||
for i in 1..<n.len:
|
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])
|
for i in 0..<n.len: track(tracked, n[i])
|
||||||
of nkCheckedFieldExpr:
|
of nkCheckedFieldExpr:
|
||||||
track(tracked, n[0])
|
track(tracked, n[0])
|
||||||
if tracked.config.hasWarn(warnProveField):
|
if tracked.config.hasWarn(warnProveField) or strictCaseObjects in tracked.c.features:
|
||||||
checkFieldAccess(tracked.guards, n, tracked.config)
|
checkFieldAccess(tracked.guards, n, tracked.config, strictCaseObjects in tracked.c.features)
|
||||||
of nkTryStmt: trackTryStmt(tracked, n)
|
of nkTryStmt: trackTryStmt(tracked, n)
|
||||||
of nkPragma: trackPragmaStmt(tracked, n)
|
of nkPragma: trackPragmaStmt(tracked, n)
|
||||||
of nkAsgn, nkFastAsgn, nkSinkAsgn:
|
of nkAsgn, nkFastAsgn, nkSinkAsgn:
|
||||||
|
|
|
||||||
|
|
@ -1941,3 +1941,39 @@ constructors that take inheritance into account.
|
||||||
|
|
||||||
**Note**: The implementation of "strict definitions" and "out parameters" is experimental but the concept
|
**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.
|
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.
|
||||||
|
|
|
||||||
27
tests/effects/tstrict_caseobjects.nim
Normal file
27
tests/effects/tstrict_caseobjects.nim
Normal 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"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue