diff options
author | metagn <metagngn@gmail.com> | 2024-08-28 21:51:13 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-28 20:51:13 +0200 |
commit | 770f8d551372893ed480550062a89e76c60ff4a8 (patch) | |
tree | 87f6e049aea09dfcd9bbed2fccb67f84d3172445 /changelog.md | |
parent | d3af51e3ce968076bb3331087806312c0faba054 (diff) | |
download | Nim-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 'changelog.md')
-rw-r--r-- | changelog.md | 56 |
1 files changed, 39 insertions, 17 deletions
diff --git a/changelog.md b/changelog.md index d98c34474..c5f30bbe2 100644 --- a/changelog.md +++ b/changelog.md @@ -82,30 +82,38 @@ is often an easy workaround. let (a, (b, c)): (byte, (float, cstring)) = (1, (2, "abc")) ``` -- An experimental option `genericsOpenSym` has been added to allow captured - symbols in generic routine bodies to 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 renaming the captured symbols should be used instead - so that the code is not affected by context changes. +- The experimental option `--experimental:openSym` has been added to allow + captured symbols in generic routine and template bodies respectively to 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 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): @@ -117,14 +125,28 @@ is often an easy workaround. 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. ## Compiler changes |