mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-04 20:17:42 +00:00
make distinct conversions addressable in VM (#24124)
fixes #24097 For `nkConv` addresses where the conversion is between 2 types that are equal between backends, treat assignments the same as assignments to the argument of the conversion. In the VM this seems to be in `genAsgn` and `genAsgnPatch`, as evidenced by the special logic for `nkDerefExpr` etc. This doesn't handle ranges after #24037 because `sameBackendType` is used and not `sameBackendTypeIgnoreRange`. This is so this is backportable without #24037 and another PR can be opened that implements it for ranges and adds tests as well. We can also merge `sameBackendTypeIgnoreRange` with `sameBackendType` since it doesn't seem like anything that uses it would be affected (only cycle checks and the VM), but then we still have to add tests.
This commit is contained in:
@@ -697,6 +697,9 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
|
||||
let dest = c.genx(le, {gfNodeAddr})
|
||||
c.gABC(le, opcWrDeref, dest, 0, value)
|
||||
c.freeTemp(dest)
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
if sameBackendType(le.typ, le[1].typ):
|
||||
genAsgnPatch(c, le[1], value)
|
||||
else:
|
||||
discard
|
||||
|
||||
@@ -869,7 +872,7 @@ proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||
genBinaryABC(c, n, dest, opc)
|
||||
c.genNarrow(n, dest)
|
||||
|
||||
proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
|
||||
proc genConv(c: PCtx; n, arg: PNode; dest: var TDest, flags: TGenFlags = {}; opc=opcConv) =
|
||||
let t2 = n.typ.skipTypes({tyDistinct})
|
||||
let targ2 = arg.typ.skipTypes({tyDistinct})
|
||||
|
||||
@@ -883,7 +886,7 @@ proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
|
||||
result = false
|
||||
|
||||
if implicitConv():
|
||||
gen(c, arg, dest)
|
||||
gen(c, arg, dest, flags)
|
||||
return
|
||||
|
||||
let tmp = c.genx(arg)
|
||||
@@ -1051,7 +1054,7 @@ proc whichAsgnOpc(n: PNode; requiresCopy = true): TOpcode =
|
||||
else:
|
||||
(if requiresCopy: opcAsgnComplex else: opcFastAsgnComplex)
|
||||
|
||||
proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
proc genMagic(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}, m: TMagic) =
|
||||
case m
|
||||
of mAnd: c.genAndOr(n, opcFJmp, dest)
|
||||
of mOr: c.genAndOr(n, opcTJmp, dest)
|
||||
@@ -1190,7 +1193,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
|
||||
of mCharToStr, mBoolToStr, mCStrToStr, mStrToStr, mEnumToStr:
|
||||
genConv(c, n, n[1], dest)
|
||||
genConv(c, n, n[1], dest, flags)
|
||||
of mEqStr: genBinaryABC(c, n, dest, opcEqStr)
|
||||
of mEqCString: genBinaryABC(c, n, dest, opcEqCString)
|
||||
of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
|
||||
@@ -1657,6 +1660,9 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||
c.freeTemp(cc)
|
||||
else:
|
||||
gen(c, ri, dest)
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
if sameBackendType(le.typ, le[1].typ):
|
||||
genAsgn(c, le[1], ri, requiresCopy)
|
||||
else:
|
||||
let dest = c.genx(le, {gfNodeAddr})
|
||||
genAsgn(c, dest, ri, requiresCopy)
|
||||
@@ -2169,7 +2175,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
if n[0].kind == nkSym:
|
||||
let s = n[0].sym
|
||||
if s.magic != mNone:
|
||||
genMagic(c, n, dest, s.magic)
|
||||
genMagic(c, n, dest, flags, s.magic)
|
||||
elif s.kind == skMethod:
|
||||
localError(c.config, n.info, "cannot call method " & s.name.s &
|
||||
" at compile time")
|
||||
@@ -2226,11 +2232,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
unused(c, n, dest)
|
||||
gen(c, n[0])
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
genConv(c, n, n[1], dest)
|
||||
genConv(c, n, n[1], dest, flags)
|
||||
of nkObjDownConv:
|
||||
genConv(c, n, n[0], dest)
|
||||
genConv(c, n, n[0], dest, flags)
|
||||
of nkObjUpConv:
|
||||
genConv(c, n, n[0], dest)
|
||||
genConv(c, n, n[0], dest, flags)
|
||||
of nkVarSection, nkLetSection:
|
||||
unused(c, n, dest)
|
||||
genVarSection(c, n)
|
||||
@@ -2240,7 +2246,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
genLit(c, newSymNode(n[namePos].sym), dest)
|
||||
of nkChckRangeF, nkChckRange64, nkChckRange:
|
||||
if skipTypes(n.typ, abstractVar).kind in {tyUInt..tyUInt64}:
|
||||
genConv(c, n, n[0], dest)
|
||||
genConv(c, n, n[0], dest, flags)
|
||||
else:
|
||||
let
|
||||
tmp0 = c.genx(n[0])
|
||||
@@ -2266,7 +2272,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
|
||||
of nkPar, nkClosure, nkTupleConstr: genTupleConstr(c, n, dest)
|
||||
of nkCast:
|
||||
if allowCast in c.features:
|
||||
genConv(c, n, n[1], dest, opcCast)
|
||||
genConv(c, n, n[1], dest, flags, opcCast)
|
||||
else:
|
||||
genCastIntFloat(c, n, dest)
|
||||
of nkTypeOfExpr:
|
||||
|
||||
49
tests/vm/tconvaddr.nim
Normal file
49
tests/vm/tconvaddr.nim
Normal file
@@ -0,0 +1,49 @@
|
||||
block: # issue #24097
|
||||
type Foo = distinct int
|
||||
proc foo(x: var Foo) =
|
||||
int(x) += 1
|
||||
proc bar(x: var int) =
|
||||
x += 1
|
||||
static:
|
||||
var x = Foo(1)
|
||||
int(x) = int(x) + 1
|
||||
doAssert x.int == 2
|
||||
int(x) += 1
|
||||
doAssert x.int == 3
|
||||
foo(x)
|
||||
doAssert x.int == 4
|
||||
bar(int(x)) # need vmgen flags propagated for this
|
||||
doAssert x.int == 5
|
||||
type Bar = object
|
||||
x: Foo
|
||||
static:
|
||||
var obj = Bar(x: Foo(1))
|
||||
int(obj.x) = int(obj.x) + 1
|
||||
doAssert obj.x.int == 2
|
||||
int(obj.x) += 1
|
||||
doAssert obj.x.int == 3
|
||||
foo(obj.x)
|
||||
doAssert obj.x.int == 4
|
||||
bar(int(obj.x)) # need vmgen flags propagated for this
|
||||
doAssert obj.x.int == 5
|
||||
static:
|
||||
var arr = @[Foo(1)]
|
||||
int(arr[0]) = int(arr[0]) + 1
|
||||
doAssert arr[0].int == 2
|
||||
int(arr[0]) += 1
|
||||
doAssert arr[0].int == 3
|
||||
foo(arr[0])
|
||||
doAssert arr[0].int == 4
|
||||
bar(int(arr[0])) # need vmgen flags propagated for this
|
||||
doAssert arr[0].int == 5
|
||||
proc testResult(): Foo =
|
||||
result = Foo(1)
|
||||
int(result) = int(result) + 1
|
||||
doAssert result.int == 2
|
||||
int(result) += 1
|
||||
doAssert result.int == 3
|
||||
foo(result)
|
||||
doAssert result.int == 4
|
||||
bar(int(result)) # need vmgen flags propagated for this
|
||||
doAssert result.int == 5
|
||||
doAssert testResult().int == 5
|
||||
Reference in New Issue
Block a user