mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-19 07:21:19 +00:00
implemented strictCaseObjects (#20608)
* implemented strictCaseObjects * changelog update
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -217,7 +217,8 @@ type
|
||||
strictEffects,
|
||||
unicodeOperators, # deadcode
|
||||
flexibleOptionalParams,
|
||||
strictDefs
|
||||
strictDefs,
|
||||
strictCaseObjects
|
||||
|
||||
LegacyFeature* = enum
|
||||
allowSemcheckedAstModification,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
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"
|
||||
Reference in New Issue
Block a user