summary refs log tree commit diff stats
path: root/doc
diff options
context:
space:
mode:
authormetagn <metagngn@gmail.com>2024-08-28 21:51:13 +0300
committerGitHub <noreply@github.com>2024-08-28 20:51:13 +0200
commit770f8d551372893ed480550062a89e76c60ff4a8 (patch)
tree87f6e049aea09dfcd9bbed2fccb67f84d3172445 /doc
parentd3af51e3ce968076bb3331087806312c0faba054 (diff)
downloadNim-770f8d551372893ed480550062a89e76c60ff4a8.tar.gz
opensym for templates + move behavior of opensymchoice to itself (#24007)
fixes #15314, fixes #24002

The OpenSym behavior first added to generics in #23091 now also applies
to templates, since templates can also capture symbols that are meant to
be replaced by local symbols if the context imports symbols with the
same name, as in the issue #24002. The experimental switch
`templateOpenSym` is added to enable this behavior for templates only,
and the experimental switch `openSym` is added to enable it for both
templates and generics, and the documentation now mainly mentions this
switch.

Additionally the logic for `nkOpenSymChoice` nodes that were previously
wrapped in `nkOpenSym` now apply to all `nkOpenSymChoice` nodes, and so
these nodes aren't wrapped in `nkOpenSym` anymore. This means
`nkOpenSym` can only have children of kind `nkSym` again, so it is more
in line with the structure of symchoice nodes. As for why they aren't
merged with `nkOpenSymChoice` nodes yet, we need some way to signal that
the node shouldn't become ambiguous if other options exist at
instantiation time, we already captured a symbol at the beginning and
another symbol can only replace it if it's closer in scope and
unambiguous.
Diffstat (limited to 'doc')
-rw-r--r--doc/manual_experimental.md57
1 files changed, 39 insertions, 18 deletions
diff --git a/doc/manual_experimental.md b/doc/manual_experimental.md
index 34399e6f9..6998e313d 100644
--- a/doc/manual_experimental.md
+++ b/doc/manual_experimental.md
@@ -2522,33 +2522,40 @@ Notice we use the overload of `()` to have the same semantics in Nim, but on the
 This allows to easy interop with functions that accepts for example a `const` operator in its signature. 
 
 
-Injected symbols in generic procs
-=================================
+Injected symbols in generic procs and templates
+===============================================
 
-With the experimental option `genericsOpenSym`, captured symbols in generic
-routine bodies may be replaced by symbols injected locally by templates/macros
-at instantiation time. `bind` may be used to keep the captured symbols over
-the injected ones regardless of enabling the option, but other methods like
+With the experimental option `openSym`, captured symbols in generic routine and
+template bodies may be replaced by symbols injected locally by templates/macros
+at instantiation time. `bind` may be used to keep the captured symbols over the
+injected ones regardless of enabling the options, but other methods like
 renaming the captured symbols should be used instead so that the code is not
 affected by context changes.
-  
+
 Since this change may affect runtime behavior, the experimental switch
-`genericsOpenSym` needs to be enabled, and a warning is given in the case
-where an injected symbol would replace a captured symbol not bound by `bind`
-and the experimental switch isn't enabled.
+`openSym`, or `genericsOpenSym` and `templateOpenSym` for only the respective
+routines, needs to be enabled; and a warning is given in the case where an
+injected symbol would replace a captured symbol not bound by `bind` and
+the experimental switch isn't enabled.
 
 ```nim
 const value = "captured"
-template foo(x: int, body: untyped) =
+template foo(x: int, body: untyped): untyped =
   let value {.inject.} = "injected"
   body
 
 proc old[T](): string =
   foo(123):
-    return value # warning: a new `value` has been injected, use `bind` or turn on `experimental:genericsOpenSym`
+    return value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
 echo old[int]() # "captured"
 
-{.experimental: "genericsOpenSym".}
+template oldTempl(): string =
+  block:
+    foo(123):
+      value # warning: a new `value` has been injected, use `bind` or turn on `experimental:openSym`
+echo oldTempl() # "captured"
+
+{.experimental: "openSym".} # or {.experimental: "genericsOpenSym".} for just generic procs
 
 proc bar[T](): string =
   foo(123):
@@ -2560,14 +2567,28 @@ proc baz[T](): string =
   foo(123):
     return value
 assert baz[int]() == "captured"
+
+# {.experimental: "templateOpenSym".} would be needed here if genericsOpenSym was used
+
+template barTempl(): string =
+  block:
+    foo(123):
+      value
+assert barTempl() == "injected" # previously it would be "captured"
+
+template bazTempl(): string =
+  bind value
+  block:
+    foo(123):
+      value
+assert bazTempl() == "captured"
 ```
 
 This option also generates a new node kind `nnkOpenSym` which contains
-exactly 1 of either an `nnkSym` or an `nnkOpenSymChoice` node. In the future
-this might be merged with a slightly modified `nnkOpenSymChoice` node but
-macros that want to support the experimental feature should still handle
-`nnkOpenSym`, as the node kind would simply not be generated as opposed to
-being removed.
+exactly 1 `nnkSym` node. In the future this might be merged with a slightly
+modified `nnkOpenSymChoice` node but macros that want to support the
+experimental feature should still handle `nnkOpenSym`, as the node kind would
+simply not be generated as opposed to being removed.
 
 
 VTable for methods