summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorringabout <43030857+ringabout@users.noreply.github.com>2023-06-20 13:08:39 +0800
committerGitHub <noreply@github.com>2023-06-20 07:08:39 +0200
commit29a43124cf978d56021af7c37c75a5d92e48cc3f (patch)
tree84953dc60db73cb20c8b3adff881909ed614aa88
parent2054f1c3a9c78ac13593e90845807e9e64f22553 (diff)
downloadNim-29a43124cf978d56021af7c37c75a5d92e48cc3f.tar.gz
overhaul the error messages of `=dup` (#22129)
-rw-r--r--compiler/semstmts.nim47
1 files changed, 41 insertions, 6 deletions
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 95820c939..cf3c03039 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1828,14 +1828,52 @@ proc whereToBindTypeHook(c: PContext; t: PType): PType =
   if result.kind in {tyObject, tyDistinct, tySequence, tyString}:
     result = canonType(c, result)
 
+proc bindDupHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
+  let t = s.typ
+  var noError = false
+  let cond = t.len == 2 and t[0] != nil
+
+  if cond:
+    var obj = t[1]
+    while true:
+      incl(obj.flags, tfHasAsgn)
+      if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.lastSon
+      elif obj.kind == tyGenericInvocation: obj = obj[0]
+      else: break
+
+    var res = t[0]
+    while true:
+      if res.kind in {tyGenericBody, tyGenericInst}: res = res.lastSon
+      elif res.kind == tyGenericInvocation: res = res[0]
+      else: break
+
+    if obj.kind in {tyObject, tyDistinct, tySequence, tyString} and sameType(obj, res):
+      obj = canonType(c, obj)
+      let ao = getAttachedOp(c.graph, obj, op)
+      if ao == s:
+        discard "forward declared destructor"
+      elif ao.isNil and tfCheckedForDestructor notin obj.flags:
+        setAttachedOp(c.graph, c.module.position, obj, op, s)
+      else:
+        prevDestructor(c, ao, obj, n.info)
+      noError = true
+      if obj.owner.getModule != s.getModule:
+        localError(c.config, n.info, errGenerated,
+          "type bound operation `" & s.name.s & "` can be defined only in the same module with its type (" & obj.typeToString() & ")")
+
+  if not noError and sfSystemModule notin s.owner.flags:
+    localError(c.config, n.info, errGenerated,
+      "signature for '=dup' must be proc[T: object](x: T): T")
+
+  incl(s.flags, sfUsed)
+  incl(s.flags, sfOverridden)
+
 proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
   let t = s.typ
   var noError = false
   let cond = case op
              of {attachedDestructor, attachedWasMoved}:
                t.len == 2 and t[0] == nil and t[1].kind == tyVar
-             of attachedDup:
-               t.len == 2 and t[0] != nil
              of attachedTrace:
                t.len == 3 and t[0] == nil and t[1].kind == tyVar and t[2].kind == tyPointer
              else:
@@ -1866,9 +1904,6 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
     of attachedTrace:
       localError(c.config, n.info, errGenerated,
         "signature for '=trace' must be proc[T: object](x: var T; env: pointer)")
-    of attachedDup:
-      localError(c.config, n.info, errGenerated,
-        "signature for '=dup' must be proc[T: object](x: var T): T")
     else:
       localError(c.config, n.info, errGenerated,
         "signature for '" & s.name.s & "' must be proc[T: object](x: var T)")
@@ -1963,7 +1998,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
       bindTypeHook(c, s, n, attachedWasMoved)
   of "=dup":
     if s.magic != mDup:
-      bindTypeHook(c, s, n, attachedDup)
+      bindDupHook(c, s, n, attachedDup)
   else:
     if sfOverridden in s.flags:
       localError(c.config, n.info, errGenerated,