1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
|
{.experimental: "openSym".}
block: # issue #24002
type Result[T, E] = object
func value[T, E](self: Result[T, E]): T {.inline.} =
discard
func value[T: not void, E](self: var Result[T, E]): var T {.inline.} =
discard
template unrecognizedFieldWarning =
doAssert value == 123
let x = value
doAssert value == x
proc readValue(value: var int) =
unrecognizedFieldWarning()
var foo: int = 123
readValue(foo)
block: # issue #22605 for templates, 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
template g(T: type): string =
var res = "ok"
let x = valueOr 123:
res = $error
"dummy"
res
doAssert g(int) == "good"
template g2(T: type): string =
bind error # use the bad version on purpose
var res = "ok"
let x = valueOr 123:
res = $error
"dummy"
res
doAssert g2(int) == "bad"
block: # issue #22605 for templates, 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
template g(T: type): string =
var res = "ok"
let x = 123.valueOr:
res = $error
"dummy"
res
doAssert g(int) == "good"
template g2(T: type): string =
bind error # use the bad version on purpose
var res = "ok"
let x = 123.valueOr:
res = $error
"dummy"
res
doAssert g2(int) == "bad"
block: # issue #22605 for templates, 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")
template g(T: type): string =
var res = "ok"
let x = f().valueOr:
res = $error
123
res
doAssert g(int) == "f"
template g2(T: type): string =
bind error # use the bad version on purpose
var res = "ok"
let x = f().valueOr:
res = $error
123
res
doAssert g2(int) == "error"
block: # issue #23865 for templates
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")
template g(T: type): string =
var res = "ok"
let x = f().valueOr:
res = $error
123
res
doAssert g(int) == "f"
import std/sequtils
block: # issue #15314
var it: string
var nums = @[1,2,3]
template doubleNums() =
nums.applyIt(it * 2)
doubleNums()
doAssert nums == @[2, 4, 6]
|