Skip to content

Commit

Permalink
stricter var type conversions, subranges under preview define
Browse files Browse the repository at this point in the history
  • Loading branch information
metagn committed Aug 31, 2024
1 parent da7670c commit c83e48c
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 8 deletions.
15 changes: 15 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,21 @@
errors for ambiguous type symbols, and macros operating on generic proc AST
may encounter symchoice nodes instead of the arbitrarily resolved type symbol nodes.

- With `-d:nimPreviewStrictVarRange`, variables of range types do not match
`var` parameters of their base type. This is to prevent implicit operations
that can cause values to escape their range, i.e.:

```nim
type Foo = range[0..5]
var foo: Foo = 5
proc double(x: var int) =
x = x * 2
double(foo)
echo foo # 10
```

will give a type mismatch error.

## Standard library additions and changes

[//]: # "Changes:"
Expand Down
17 changes: 15 additions & 2 deletions compiler/sigmatch.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1017,9 +1017,22 @@ proc inferStaticsInRange(c: var TCandidate,
doInferStatic(lowerBound, getInt(upperBound) + 1 - lengthOrd(c.c.config, concrete))

template subtypeCheck() =
if result <= isSubrange and f.last.skipTypes(abstractInst).kind in {
tyRef, tyPtr, tyVar, tyLent, tyOwned}:
case result
of isIntConv:
result = isNone
of isSubrange:
if c.c.config.isDefined("nimPreviewStrictVarRange"):
result = isNone
of isConvertible:
if f.last.skipTypes(abstractInst).kind != tyOpenArray:
# exclude var openarray which compiler supports
result = isNone
of isSubtype:
if f.last.skipTypes(abstractInst).kind in {
tyRef, tyPtr, tyVar, tyLent, tyOwned}:
# compiler can't handle subtype conversions with pointer indirection
result = isNone
else: discard

proc isCovariantPtr(c: var TCandidate, f, a: PType): bool =
# this proc is always called for a pair of matching types
Expand Down
20 changes: 20 additions & 0 deletions lib/pure/json.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1094,6 +1094,8 @@ proc initFromJson[T](dst: var OrderedTable[string, T]; jsonNode: JsonNode; jsonP
proc initFromJson[T](dst: var ref T; jsonNode: JsonNode; jsonPath: var string)
proc initFromJson[T](dst: var Option[T]; jsonNode: JsonNode; jsonPath: var string)
proc initFromJson[T: distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string)
when defined(nimPreviewStrictVarRange):
proc initFromJson[T: range](dst: var T; jsonNode: JsonNode; jsonPath: var string)
proc initFromJson[T: object|tuple](dst: var T; jsonNode: JsonNode; jsonPath: var string)

# initFromJson definitions
Expand Down Expand Up @@ -1224,6 +1226,24 @@ macro assignDistinctImpl[T: distinct](dst: var T;jsonNode: JsonNode; jsonPath: v
proc initFromJson[T: distinct](dst: var T; jsonNode: JsonNode; jsonPath: var string) =
assignDistinctImpl(dst, jsonNode, jsonPath)

when defined(nimPreviewStrictVarRange):
# doesn't work without #24037
macro assignRangeImpl[T: range](dst: var T;jsonNode: JsonNode; jsonPath: var string) =
let typImpl = getTypeImpl(dst)
assert typImpl.kind == nnkBracketExpr and typImpl[0].eqIdent"range"
let lowNode =
if typImpl[^1].kind == nnkInfix:
typImpl[^1][1]
else:
typImpl[1]
let baseTyp = getType(lowNode)

result = quote do:
initFromJson(`baseTyp`(`dst`), `jsonNode`, `jsonPath`)

proc initFromJson[T: range](dst: var T; jsonNode: JsonNode; jsonPath: var string) =
assignRangeImpl(dst, jsonNode, jsonPath)

proc detectIncompatibleType(typeExpr, lineinfoNode: NimNode) =
if typeExpr.kind == nnkTupleConstr:
error("Use a named tuple instead of: " & typeExpr.repr, lineinfoNode)
Expand Down
2 changes: 1 addition & 1 deletion lib/pure/unicode.nim
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ proc runeOffset*(s: openArray[char], pos: Natural, start: Natural = 0): int =
i = 0
o = start
while i < pos:
o += runeLenAt(s, o)
inc o, runeLenAt(s, o)
if o >= s.len:
return -1
inc i
Expand Down
4 changes: 2 additions & 2 deletions tests/errmsgs/t22097.nim
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
discard """
errormsg: "for a 'var' type a variable needs to be passed; but 'uint16(x)' is immutable"
errormsg: "type mismatch: got <uint8>"
"""

proc toUInt16(x: var uint16) =
discard

var x = uint8(1)
toUInt16 x
toUInt16 x
16 changes: 16 additions & 0 deletions tests/int/twrongexplicitvarconv.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
discard """
action: reject
nimout: '''
but expression 'int(a)' is immutable, not 'var'
'''
"""

proc `++`(n: var int) =
n += 1

var a: int32 = 15

++int(a) #[tt.Error
^ type mismatch: got <int>]#

echo a
9 changes: 9 additions & 0 deletions tests/int/twrongvarconv.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
proc `++`(n: var int) =
n += 1

var a: int32 = 15

++a #[tt.Error
^ type mismatch: got <int32>]#

echo a
2 changes: 1 addition & 1 deletion tests/iter/titer12.nim
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ proc filter[T](it: (iterator : T), f: proc(x: T): bool): (iterator : T) =

proc len[T](it : iterator : T) : Natural =
for i in it():
result += 1
result.inc 1

proc simpleSeqIterator(s :seq[int]) : iterator : int =
iterator it: int {.closure.} =
Expand Down
4 changes: 2 additions & 2 deletions tests/overflow/trangechecks.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var expected: int
var x: range[1..10] = 10

try:
x += 1
inc x, 1
echo x
except OverflowDefect, RangeDefect:
expected += 1
Expand All @@ -27,7 +27,7 @@ except OverflowDefect, RangeDefect:

x = 1
try:
x -= 1
dec x, 1
echo x
except OverflowDefect, RangeDefect:
expected += 1
Expand Down
18 changes: 18 additions & 0 deletions tests/range/twrongvarconv.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
discard """
matrix: "-d:nimPreviewStrictVarRange"
"""

# issue #24032

proc `++`(n: var int) =
n += 1

type
r = range[ 0..15 ]

var a: r = 15

++a #[tt.Error
^ type mismatch: got <r>]#

echo a

0 comments on commit c83e48c

Please sign in to comment.