summary refs log tree commit diff stats
path: root/tests/generics
diff options
context:
space:
mode:
authormetagn <metagngn@gmail.com>2023-12-22 10:49:51 +0300
committerGitHub <noreply@github.com>2023-12-22 08:49:51 +0100
commit4b1a84170786653f60313f7bdf56efa3928c2a3a (patch)
treedb7898a3be349b1b42cc4cb566d5a8587c6d37b2 /tests/generics
parentdf3c95d8af7bfd1e61e6b06eec21f57781dff9d5 (diff)
downloadNim-4b1a84170786653f60313f7bdf56efa3928c2a3a.tar.gz
add switch, warning, and `bind` support for new generic injection behavior (#23102)
refs #23091, especially post merge comments

Unsure if `experimental` and `bind` are the perfect constructs to use
but they seem to get the job done here. Symbol nodes do not get marked
`nfOpenSym` if the `bind` statement is used for their symbol, and
`nfOpenSym` nodes do not get replaced by new local symbols if the
experimental switch is not enabled in the local context (meaning it also
works with `push experimental`). However this incurs a warning as the
fact that the node is marked `nfOpenSym` means we did not `bind` it, so
we might want to do that or turn on the experimental switch if we didn't
intend to bind it.

The experimental switch name is arbitrary and could be changed.

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
Diffstat (limited to 'tests/generics')
-rw-r--r--tests/generics/tmacroinjectedsym.nim29
-rw-r--r--tests/generics/tmacroinjectedsymwarning.nim50
2 files changed, 79 insertions, 0 deletions
diff --git a/tests/generics/tmacroinjectedsym.nim b/tests/generics/tmacroinjectedsym.nim
index a98c1edb1..d36d34cdd 100644
--- a/tests/generics/tmacroinjectedsym.nim
+++ b/tests/generics/tmacroinjectedsym.nim
@@ -1,3 +1,5 @@
+{.experimental: "genericsOpenSym".}
+
 block: # issue #22605, normal call syntax
   const error = "bad"
 
@@ -16,6 +18,15 @@ block: # issue #22605, normal call syntax
 
   doAssert g(int) == "good"
 
+  proc g2(T: type): string =
+    bind error # use the bad version on purpose
+    let x = valueOr 123:
+      return $error
+
+    "ok"
+
+  doAssert g2(int) == "bad"
+
 block: # issue #22605, method call syntax
   const error = "bad"
 
@@ -34,6 +45,15 @@ block: # issue #22605, method call syntax
 
   doAssert g(int) == "good"
 
+  proc g2(T: type): string =
+    bind error # use the bad version on purpose
+    let x = 123.valueOr:
+      return $error
+
+    "ok"
+
+  doAssert g2(int) == "bad"
+
 block: # issue #22605, original complex example
   type Xxx = enum
     error
@@ -84,3 +104,12 @@ block: # issue #22605, original complex example
     "ok"
 
   doAssert g(int) == "f"
+
+  proc g2(T: type): string =
+    bind error # use the bad version on purpose
+    let x = f().valueOr:
+      return $error
+
+    "ok"
+
+  doAssert g2(int) == "error"
diff --git a/tests/generics/tmacroinjectedsymwarning.nim b/tests/generics/tmacroinjectedsymwarning.nim
new file mode 100644
index 000000000..7adb759e8
--- /dev/null
+++ b/tests/generics/tmacroinjectedsymwarning.nim
@@ -0,0 +1,50 @@
+type Xxx = enum
+  error
+  value
+
+type
+  Result[T, E] = object
+    when T is void:
+      when E is void:
+        oResultPrivate*: bool
+      else:
+        case oResultPrivate*: bool
+        of false:
+          eResultPrivate*: E
+        of true:
+          discard
+    else:
+      when E is void:
+        case oResultPrivate*: bool
+        of false:
+          discard
+        of true:
+          vResultPrivate*: T
+      else:
+        case oResultPrivate*: bool
+        of false:
+          eResultPrivate*: E
+        of true:
+          vResultPrivate*: T
+
+template valueOr[T: not void, E](self: Result[T, E], def: untyped): untyped =
+  let s = (self) # TODO avoid copy
+  case s.oResultPrivate
+  of true:
+    s.vResultPrivate
+  of false:
+    when E isnot void:
+      template error: untyped {.used, inject.} = s.eResultPrivate
+    def
+
+proc f(): Result[int, cstring] =
+  Result[int, cstring](oResultPrivate: false, eResultPrivate: "f")
+
+proc g(T: type): string =
+  let x = f().valueOr:
+    return $error #[tt.Warning
+            ^ a new symbol 'error' has been injected during instantiation of g, however 'error' [enumField declared in tmacroinjectedsymwarning.nim(2, 3)] captured at the proc declaration will be used instead; either enable --experimental:genericsOpenSym to use the injected symbol or `bind` this captured symbol explicitly [GenericsIgnoredInjection]]#
+
+  "ok"
+
+discard g(int)