Skip to content

Commit ceaa7fb

Browse files
authored
fixes #23949; cannot return lent expression from conditionals like case (#25190)
fixes #23949 It can also allow `endsInNoReturn` in branches later
1 parent d85c032 commit ceaa7fb

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

compiler/parampatterns.nim

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import ast, types, msgs, idents, renderer, wordrecg, trees,
1414
options
1515

16-
import std/strutils
16+
import std/[strutils, assertions]
1717

1818
# we precompile the pattern here for efficiency into some internal
1919
# stack based VM :-) Why? Because it's fun; I did no benchmarks to see if that
@@ -216,6 +216,11 @@ proc exprRoot*(n: PNode; allowCalls = true): PSym =
216216
else:
217217
break
218218

219+
proc isAssignable*(owner: PSym, n: PNode): TAssignableResult
220+
221+
proc isLentableBranch(owner: PSym, n: PNode): bool =
222+
result = isAssignable(owner, n) in {arLentValue, arAddressableConst, arLentValue}
223+
219224
proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
220225
## 'owner' can be nil!
221226
result = arNone
@@ -308,6 +313,35 @@ proc isAssignable*(owner: PSym, n: PNode): TAssignableResult =
308313
# nkVarTy denotes an lvalue, but the example above is the only
309314
# possible code which will get us here
310315
result = arLValue
316+
of nkIfExpr, nkIfStmt:
317+
# allow 'if' expressions to be lent if all branches are lentable
318+
for branch in n:
319+
if branch.len == 2:
320+
if not isLentableBranch(owner, branch[1]):
321+
return
322+
elif branch.len == 1:
323+
if not isLentableBranch(owner, branch[0]):
324+
return
325+
else:
326+
raiseAssert "Malformed `if` statement in isAssignable"
327+
result = arLentValue
328+
of nkCaseStmt:
329+
# allow 'case' expressions to be lent if all branches are lentable
330+
for i in 1 ..< n.len:
331+
let branch = n[i]
332+
case branch.kind
333+
of nkOfBranch:
334+
if not isLentableBranch(owner, branch[^1]):
335+
return
336+
of nkElifBranch:
337+
if not isLentableBranch(owner, branch[1]):
338+
return
339+
of nkElse:
340+
if not isLentableBranch(owner, branch[0]):
341+
return
342+
else:
343+
raiseAssert "Malformed `case` statement in isAssignable"
344+
result = arLentValue
311345
else:
312346
discard
313347

tests/lent/tlents.nim

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
discard """
2+
targets: "c cpp"
3+
"""
4+
5+
type A = object
6+
field: int
7+
8+
proc x(a: A): lent int =
9+
result = case true
10+
of true:
11+
a.field
12+
of false:
13+
a.field
14+
15+
proc y(a: A): lent int =
16+
result = if true:
17+
a.field
18+
else:
19+
a.field
20+
21+
block:
22+
var a = A(field: 1)
23+
doAssert x(a) == 1
24+
doAssert y(a) == 1
25+

0 commit comments

Comments
 (0)