summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/injectdestructors.nim4
-rw-r--r--compiler/liftdestructors.nim2
-rw-r--r--compiler/semstmts.nim2
-rw-r--r--doc/destructors.md37
-rw-r--r--doc/manual.md2
-rw-r--r--lib/system.nim2
-rw-r--r--tests/arc/tdup.nim2
7 files changed, 44 insertions, 7 deletions
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim
index 9745fee81..7183aac4e 100644
--- a/compiler/injectdestructors.nim
+++ b/compiler/injectdestructors.nim
@@ -431,7 +431,9 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
       let src = p(n, c, s, normal)
       result.add newTreeI(nkFastAsgn,
           src.info, tmp,
-          genOp(c, op, src)
+          newTreeIT(nkCall, src.info, src.typ,
+            newSymNode(op),
+            src)
       )
     elif typ.kind == tyRef:
       let src = p(n, c, s, normal)
diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim
index 85403586f..43e5baf08 100644
--- a/compiler/liftdestructors.nim
+++ b/compiler/liftdestructors.nim
@@ -8,7 +8,7 @@
 #
 
 ## This module implements lifting for type-bound operations
-## (``=sink``, ``=copy``, ``=destroy``, ``=deepCopy``).
+## (`=sink`, `=copy`, `=destroy`, `=deepCopy`, `=wasMoved`, `=dup`).
 
 import modulegraphs, lineinfos, idents, ast, renderer, semdata,
   sighashes, lowerings, options, types, msgs, magicsys, tables, ccgutils
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 126d1aa65..f81423915 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1819,7 +1819,7 @@ proc bindTypeHook(c: PContext; s: PSym; n: PNode; op: TTypeAttachedOp) =
              of {attachedDestructor, attachedWasMoved}:
                t.len == 2 and t[0] == nil and t[1].kind == tyVar
              of attachedDup:
-               t.len == 2 and t[0] != nil and t[1].kind == tyVar
+               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:
diff --git a/doc/destructors.md b/doc/destructors.md
index a37eade33..d924c7c4c 100644
--- a/doc/destructors.md
+++ b/doc/destructors.md
@@ -101,7 +101,7 @@ well as other standard collections is performed via so-called
 "Lifetime-tracking hooks", which are particular [type bound operators](
 manual.html#procedures-type-bound-operators).
 
-There are 4 different hooks for each (generic or concrete) object type `T` (`T` can also be a
+There are 6 different hooks for each (generic or concrete) object type `T` (`T` can also be a
 `distinct` type) that are called implicitly by the compiler.
 
 (Note: The word "hook" here does not imply any kind of dynamic binding
@@ -262,6 +262,41 @@ The general pattern in using `=destroy` with `=trace` looks like:
 **Note**: The `=trace` hooks (which are only used by `--mm:orc`) are currently more experimental and less refined
 than the other hooks.
 
+`=WasMoved` hook
+----------------
+
+A `wasMoved` hook resets the memory of an object to its initial (binary zero) value to signify it was "moved" and to signify its destructor should do nothing and ideally be optimized away.
+
+The prototype of this hook for a type `T` needs to be:
+
+  ```nim
+  proc `=wasMoved`(x: var T)
+  ```
+
+`=dup` hook
+-----------
+
+A `=dup` hook duplicates the memory of an object. `=dup(x)` can be regarded as an optimization replacing the `wasMoved(dest); =copy(dest, x)` operation.
+
+The prototype of this hook for a type `T` needs to be:
+
+  ```nim
+  proc `=dup`(x: T): T
+  ```
+
+The general pattern in implementing `=dup` looks like:
+
+  ```nim
+  type
+    Ref[T] = object
+      data: ptr T
+      rc: ptr int
+
+  proc `=dup`[T](x: Ref[T]): Ref[T] =
+    result = x
+    if x.rc != nil:
+      inc x.rc[]
+  ```
 
 Move semantics
 ==============
diff --git a/doc/manual.md b/doc/manual.md
index 7fe9923f4..f3fe62c49 100644
--- a/doc/manual.md
+++ b/doc/manual.md
@@ -4155,7 +4155,7 @@ the operator is in scope (including if it is private).
   ```
 
 Type bound operators are:
-`=destroy`, `=copy`, `=sink`, `=trace`, `=deepcopy`, `=wasMoved`.
+`=destroy`, `=copy`, `=sink`, `=trace`, `=deepcopy`, `=wasMoved`, `=dup`.
 
 These operations can be *overridden* instead of *overloaded*. This means that
 the implementation is automatically lifted to structured types. For instance,
diff --git a/lib/system.nim b/lib/system.nim
index e8664d7a4..e7b6ed7c3 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -350,7 +350,7 @@ proc `=destroy`*[T](x: var T) {.inline, magic: "Destroy".} =
 
 when defined(nimHasDup):
   proc `=dup`*[T](x: ref T): ref T {.inline, magic: "Dup".} =
-    ## Generic `dup` implementation that can be overridden.
+    ## Generic `dup`:idx: implementation that can be overridden.
     discard
 
 proc `=sink`*[T](x: var T; y: T) {.inline, nodestroy, magic: "Asgn".} =
diff --git a/tests/arc/tdup.nim b/tests/arc/tdup.nim
index 3f64061fb..b77f5c6eb 100644
--- a/tests/arc/tdup.nim
+++ b/tests/arc/tdup.nim
@@ -40,7 +40,7 @@ proc inc(x: sink Ref) =
 proc inc(x: sink RefCustom) =
   inc x.id[]
 
-proc `=dup`(x: var RefCustom): RefCustom =
+proc `=dup`(x: RefCustom): RefCustom =
   result.id = x.id
 
 proc foo =