Skip to content

Commit

Permalink
implemented strictCaseObjects (nim-lang#20608)
Browse files Browse the repository at this point in the history
* implemented strictCaseObjects

* changelog update
  • Loading branch information
Araq authored and capocasa committed Mar 31, 2023
1 parent d377ead commit 711ed05
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 8 deletions.
8 changes: 6 additions & 2 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -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`.
Expand Down Expand Up @@ -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
Expand Down
8 changes: 6 additions & 2 deletions compiler/guards.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 2 additions & 1 deletion compiler/options.nim
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,8 @@ type
strictEffects,
unicodeOperators, # deadcode
flexibleOptionalParams,
strictDefs
strictDefs,
strictCaseObjects

LegacyFeature* = enum
allowSemcheckedAstModification,
Expand Down
6 changes: 3 additions & 3 deletions compiler/sempass2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
36 changes: 36 additions & 0 deletions doc/manual_experimental.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 27 additions & 0 deletions tests/effects/tstrict_caseobjects.nim
Original file line number Diff line number Diff line change
@@ -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"

0 comments on commit 711ed05

Please sign in to comment.