diff options
-rw-r--r-- | compiler/varpartitions.nim | 39 | ||||
-rw-r--r-- | tests/views/t19986.nim | 42 |
2 files changed, 66 insertions, 15 deletions
diff --git a/compiler/varpartitions.nim b/compiler/varpartitions.nim index 4841a0c47..60eed5c78 100644 --- a/compiler/varpartitions.nim +++ b/compiler/varpartitions.nim @@ -580,24 +580,33 @@ proc borrowingAsgn(c: var Partitions; dest, src: PNode) = if dest.kind == nkSym: if directViewType(dest.typ) != noView: borrowFrom(c, dest.sym, src) - elif dest.kind in {nkHiddenDeref, nkDerefExpr, nkBracketExpr}: - case directViewType(dest[0].typ) - of mutableView, immutableView: - # we do not borrow, but we use the view to mutate the borrowed - # location: - let viewOrigin = pathExpr(dest, c.owner) - if viewOrigin.kind == nkSym: - let vid = variableId(c, viewOrigin.sym) + else: + let viewOrigin = pathExpr(dest, c.owner) + if viewOrigin != nil and viewOrigin.kind == nkSym: + let viewSym = viewOrigin.sym + let directView = directViewType(dest[0].typ) # check something like result[first] = toOpenArray(s, first, last-1) + # so we don't need to iterate the original type + let originSymbolView = directViewType(viewSym.typ) # find the original symbol which preserves the view type + # var foo: var Object = a + # foo.id = 777 # the type of foo is no view, so we need + # to check the original symbol + let viewSets = {directView, originSymbolView} + + if viewSets * {mutableView, immutableView} != {}: + # we do not borrow, but we use the view to mutate the borrowed + # location: + let vid = variableId(c, viewSym) if vid >= 0: c.s[vid].flags.incl viewDoesMutate - #[of immutableView: - if dest.kind == nkBracketExpr and dest[0].kind == nkHiddenDeref and - mutableParameter(dest[0][0]): - discard "remains a mutable location anyhow" + #[of immutableView: + if dest.kind == nkBracketExpr and dest[0].kind == nkHiddenDeref and + mutableParameter(dest[0][0]): + discard "remains a mutable location anyhow" + else: + localError(c.g.config, dest.info, "attempt to mutate a borrowed location from an immutable view") + ]# else: - localError(c.g.config, dest.info, "attempt to mutate a borrowed location from an immutable view") - ]# - of noView: discard "nothing to do" + discard "nothing to do" proc containsPointer(t: PType): bool = proc wrap(t: PType): bool {.nimcall.} = t.kind in {tyRef, tyPtr} diff --git a/tests/views/t19986.nim b/tests/views/t19986.nim new file mode 100644 index 000000000..85a7cf97d --- /dev/null +++ b/tests/views/t19986.nim @@ -0,0 +1,42 @@ +discard """ + cmd: '''nim check --hints:off $file''' + action: reject +nimout: ''' +t19986.nim(19, 7) Error: 'foo' borrows from the immutable location 'a' and attempts to mutate it +t19986.nim(28, 7) Error: 'foo' borrows from the immutable location 'a' and attempts to mutate it +t19986.nim(37, 7) Error: 'foo' borrows from the immutable location 'a' and attempts to mutate it +''' +""" + +{.experimental: "views".} + +type + Object = object + id: int + +proc foo() = + let a = Object(id: 3) + var foo: var Object = a + + foo.id = 777 + echo a + +foo() + +proc bar() = + let a = "123" + var foo: var string = a + + foo[0] = '7' + echo a + +bar() + +proc main() = + let a = 3 + var foo: var int = a + + foo = 777 + echo a + +main() |