mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-04 12:07:51 +00:00
alternative to #24101
#23892 changed the opensym experimental switch so that it has to be
enabled in the context of the generic/template declarations capturing
the symbols, not the context of the instantiation of the
generics/templates. This was to be in line with where the compiler gives
the warnings and changes behavior in a potentially breaking way.
However `results` [depends on the old
behavior](71d404b314/results.nim (L1428)),
so that the callers of the macros provided by results always take
advantage of the opensym behavior. To accomodate this, we change the
behavior of the old experimental option that `results` uses,
`genericsOpenSym`, so that ignores the information of whether or not
symbols are intentionally opened and always gives the opensym behavior
as long as it's enabled at instantiation time. This should keep
`results` working as is. However this differs from the normal opensym
switch in that it doesn't generate `nnkOpenSym`.
Before it was just a generics-only version of `openSym` along with
`templateOpenSym` which was only for templates. So `templateOpenSym` is
removed along with this change, but no one appears to have used it.
187 lines
4.1 KiB
Nim
187 lines
4.1 KiB
Nim
{.experimental: "openSym".}
|
|
|
|
block: # issue #22605, normal call syntax
|
|
const error = "bad"
|
|
|
|
template valueOr(self: int, def: untyped): untyped =
|
|
case false
|
|
of true: ""
|
|
of false:
|
|
template error: untyped {.used, inject.} = "good"
|
|
def
|
|
|
|
proc g(T: type): string =
|
|
let x = valueOr 123:
|
|
return $error
|
|
|
|
"ok"
|
|
|
|
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"
|
|
|
|
template valueOr(self: int, def: untyped): untyped =
|
|
case false
|
|
of true: ""
|
|
of false:
|
|
template error: untyped {.used, inject.} = "good"
|
|
def
|
|
|
|
proc g(T: type): string =
|
|
let x = 123.valueOr:
|
|
return $error
|
|
|
|
"ok"
|
|
|
|
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
|
|
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
|
|
|
|
"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"
|
|
|
|
block: # issue #23865
|
|
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
|
|
|
|
func error[T, E](self: Result[T, E]): E =
|
|
## Fetch error of result if set, or raise Defect
|
|
case self.oResultPrivate
|
|
of true:
|
|
when T isnot void:
|
|
raiseResultDefect("Trying to access error when value is set", self.vResultPrivate)
|
|
else:
|
|
raiseResultDefect("Trying to access error when value is set")
|
|
of false:
|
|
when E isnot void:
|
|
self.eResultPrivate
|
|
|
|
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
|
|
"ok"
|
|
doAssert g(int) == "f"
|
|
|
|
import sequtils
|
|
|
|
block: # issue #12283
|
|
var b = 5
|
|
type Foo[T] = object
|
|
h, w: int
|
|
proc bar[T](foos: seq[Foo[T]]): T =
|
|
let w = foldl(foos, a + b.w, 0)
|
|
w
|
|
let foos = @[Foo[int](h: 3, w: 5), Foo[int](h: 4, w: 6)]
|
|
doAssert bar(foos) == 11
|