fixes #25464; infer =dup for distinct types

This commit is contained in:
ringabout
2026-02-04 18:35:56 +08:00
parent bfc2786718
commit ae2c155042
2 changed files with 60 additions and 10 deletions

View File

@@ -558,6 +558,21 @@ proc declareTempOf(c: var TLiftCtx; body: PNode; value: PNode): PNode =
v.addVar(result, value)
body.add v
proc considerInferDupFromCopy(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
## For `=dup`, if no explicit hook exists, try to infer from `=copy` hook
## to maintain backward compatibility. Returns true if inference was applied.
if c.kind == attachedDup:
var op2 = getAttachedOp(c.g, t, attachedAsgn)
if op2 != nil and sfOverridden in op2.flags:
#markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op2)
body.add newHookCall(c, t.assignment, x, y)
result = true
else:
result = false
else:
result = false
proc addIncStmt(c: var TLiftCtx; body, i: PNode) =
let incCall = genBuiltin(c, mInc, "inc", i)
incCall.add lowerings.newIntLit(c.g, c.info, 1)
@@ -1053,19 +1068,12 @@ proc fillBody(c: var TLiftCtx; t: PType; body, x, y: PNode) =
elif tfUnion in t.flags: # bug #25236
defaultOp(c, t, body, x, y)
else:
if c.kind == attachedDup:
var op2 = getAttachedOp(c.g, t, attachedAsgn)
if op2 != nil and sfOverridden in op2.flags:
#markUsed(c.g.config, c.info, op, c.g.usageSym)
onUse(c.info, op2)
body.add newHookCall(c, t.assignment, x, y)
else:
fillBodyObjT(c, t, body, x, y)
else:
if not considerInferDupFromCopy(c, t, body, x, y):
fillBodyObjT(c, t, body, x, y)
of tyDistinct:
if not considerUserDefinedOp(c, t, body, x, y):
fillBody(c, t.elementType, body, x, y)
if not considerInferDupFromCopy(c, t, body, x, y):
fillBody(c, t.elementType, body, x, y)
of tyTuple:
fillBodyTup(c, t, body, x, y)
of tyVarargs, tyOpenArray:

View File

@@ -0,0 +1,42 @@
discard """
output: '''
copy!
2
1'''
"""
type Foo = distinct int
var counter = 0
proc `=destroy`(pkt: var Foo) =
if cast[int](pkt) != 0:
echo cast[int](pkt)
proc `=copy`(a: var Foo, b: Foo) =
if cast[int](a) == cast[int](b):
return
`=destroy`(a)
if cast[int](b) == 0:
zeroMem(addr a, sizeof(Foo))
else:
counter += 1
copyMem(addr a, addr counter, sizeof(Foo))
echo "copy!"
proc makeFoo(): Foo =
counter += 1
cast[Foo](counter)
type Bar = object
val: Foo
proc consume(x: sink Bar) =
discard
let x = Bar(val: makeFoo())
consume(x)
discard x