Skip to content
Prev Previous commit
Next Next commit
try destructor fix
  • Loading branch information
metagn committed Nov 10, 2024
commit 14f03fc7095ef85bc83cdca8dc58a17c50e622f4
4 changes: 4 additions & 0 deletions compiler/liftdestructors.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1276,6 +1276,10 @@ proc createTypeBoundOps(g: ModuleGraph; c: PContext; orig: PType; info: TLineInf
## The later 'injectdestructors' pass depends on it.
if orig == nil or {tfCheckedForDestructor, tfHasMeta} * orig.flags != {}: return
incl orig.flags, tfCheckedForDestructor
# for user defined generic destructors:
let origRoot = genericRoot(orig)
if origRoot != nil:
incl origRoot.flags, tfCheckedForDestructor

let skipped = orig.skipTypes({tyGenericInst, tyAlias, tySink})
if isEmptyContainer(skipped) or skipped.kind == tyStatic: return
Expand Down
31 changes: 22 additions & 9 deletions compiler/semstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2035,14 +2035,27 @@ proc canonType(c: PContext, t: PType): PType =
else:
result = t

proc prevDestructor(c: PContext; prevOp: PSym; obj: PType; info: TLineInfo) =
var msg = "cannot bind another '" & prevOp.name.s & "' to: " & typeToString(obj)
if sfOverridden notin prevOp.flags:
proc prevDestructor(c: PContext; op: TTypeAttachedOp; prevOp: PSym; obj: PType; info: TLineInfo) =
var msg = "cannot bind another '" & AttachedOpToStr[op] & "' to: " & typeToString(obj)
if prevOp == nil:
# happens if the destructor was implicitly constructed for a specific instance,
# not the entire generic type
msg.add "; previous declaration was constructed implicitly"
elif sfOverridden notin prevOp.flags:
msg.add "; previous declaration was constructed here implicitly: " & (c.config $ prevOp.info)
else:
msg.add "; previous declaration was here: " & (c.config $ prevOp.info)
localError(c.config, info, errGenerated, msg)

proc checkedForDestructor(t: PType): bool =
if tfCheckedForDestructor in t.flags:
return true
# maybe another instance was instantiated, marking the generic root:
let root = genericRoot(t)
if root != nil and tfCheckedForDestructor in root.flags:
return true
result = false

proc whereToBindTypeHook(c: PContext; t: PType): PType =
result = t
while true:
Expand Down Expand Up @@ -2076,10 +2089,10 @@ proc bindDupHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
let ao = getAttachedOp(c.graph, obj, op)
if ao == s:
discard "forward declared destructor"
elif ao.isNil and tfCheckedForDestructor notin obj.flags:
elif ao.isNil and not checkedForDestructor(obj):
setAttachedOp(c.graph, c.module.position, obj, op, s)
else:
prevDestructor(c, ao, obj, n.info)
prevDestructor(c, op, ao, obj, n.info)
noError = true
if obj.owner.getModule != s.getModule:
localError(c.config, n.info, errGenerated,
Expand Down Expand Up @@ -2123,10 +2136,10 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
let ao = getAttachedOp(c.graph, obj, op)
if ao == s:
discard "forward declared destructor"
elif ao.isNil and tfCheckedForDestructor notin obj.flags:
elif ao.isNil and not checkedForDestructor(obj):
setAttachedOp(c.graph, c.module.position, obj, op, s)
else:
prevDestructor(c, ao, obj, n.info)
prevDestructor(c, op, ao, obj, n.info)
noError = true
if obj.owner.getModule != s.getModule:
localError(c.config, n.info, errGenerated,
Expand Down Expand Up @@ -2217,10 +2230,10 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
let ao = getAttachedOp(c.graph, obj, k)
if ao == s:
discard "forward declared op"
elif ao.isNil and tfCheckedForDestructor notin obj.flags:
elif ao.isNil and not checkedForDestructor(obj):
setAttachedOp(c.graph, c.module.position, obj, k, s)
else:
prevDestructor(c, ao, obj, n.info)
prevDestructor(c, k, ao, obj, n.info)
if obj.owner.getModule != s.getModule:
localError(c.config, n.info, errGenerated,
"type bound operation `" & name & "` can be defined only in the same module with its type (" & obj.typeToString() & ")")
Expand Down
3 changes: 1 addition & 2 deletions tests/destructor/tinvalid_rebind.nim
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
discard """
disabled: true
joinable: false
cmd: "nim check $file"
errormsg: "cannot bind another '=destroy' to: Foo; previous declaration was constructed here implicitly: tinvalid_rebind.nim(12, 7)"
errormsg: "cannot bind another '=destroy' to: Foo; previous declaration was constructed implicitly"
line: 14
"""

Expand Down
5 changes: 2 additions & 3 deletions tests/destructor/tinvalid_rebind_nonempty.nim
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
discard """
disabled: true
joinable: false
cmd: "nim check $file"
errormsg: "cannot bind another '=destroy' to: Foo; previous declaration was constructed here implicitly: tinvalid_rebind.nim(12, 7)"
line: 14
errormsg: "cannot bind another '=destroy' to: Foo; previous declaration was constructed implicitly"
line: 15
"""

type
Expand Down
Loading