Skip to content

Commit 9be3559

Browse files
metagnnarimiran
authored andcommitted
consider calls as complex openarray assignment to iterator params (#24333)
fixes #13417, fixes #19703 When passing an expression to an `openarray` iterator parameter: If the expression is a statement list (considered "complex"), it's assigned in a non-deep-copying way to a temporary variable first, then this variable is used as a parameter. If it's not a statement list, i.e. a call or a symbol, the parameter is substituted directly with the given expression. In the case of calls, this results in the call potentially being executed more than once, or can cause redefined variables in the codegen. To fix this, calls are also considered as "complex" assignments to openarrays, as long as the return type of the call is not `openarray` as the generated assignment in that case has issues/is unimplemented (caused a segfault [here in datamancer](https://github.com/SciNim/Datamancer/blob/47ba4d81bf240a7755b73bc48c1cec9b638d18ae/src/datamancer/dataframe.nim#L1580)). As for why creating a temporary isn't the default only with exceptions for things like `nkSym`, the "non-deep-copying" way of assignment apparently still causes arrays to be copied according to a comment in the code. I'm not sure to what extent this is true: if it still happens on ARC/ORC, if it happens for every array length, or if we can fix it by passing arrays by reference. Otherwise, a more general way to assign to openarrays might be needed, but I'm not sure if the compiler can easily do this. (cherry picked from commit d303c28)
1 parent f2a9765 commit 9be3559

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

compiler/transf.nim

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,12 @@ proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
637637
case arg.kind
638638
of nkStmtListExpr:
639639
return paComplexOpenarray
640+
of nkCall:
641+
if skipTypes(arg.typ, abstractInst).kind in {tyOpenArray, tyVarargs}:
642+
# XXX incorrect, causes #13417 when `arg` has side effects.
643+
return paDirectMapping
644+
else:
645+
return paComplexOpenarray
640646
of nkBracket:
641647
return paFastAsgnTakeTypeFromArg
642648
else:
@@ -803,7 +809,7 @@ proc transformFor(c: PTransf, n: PNode): PNode =
803809
stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, addrExp, true))
804810
newC.mapping[formal.itemId] = newDeref(temp)
805811
of paComplexOpenarray:
806-
# arrays will deep copy here (pretty bad).
812+
# XXX arrays will deep copy here (pretty bad).
807813
var temp = newTemp(c, arg.typ, formal.info)
808814
addVar(v, temp)
809815
stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg, true))

tests/iter/titeropenarray.nim

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
block: # issue #13417
2+
var s: seq[int] = @[]
3+
proc p1(): seq[int] =
4+
s.add(3)
5+
@[1,2]
6+
7+
iterator ip1(v: openArray[int]): auto =
8+
for x in v:
9+
yield x
10+
11+
for x in ip1(p1()):
12+
s.add(x)
13+
14+
doAssert s == @[3, 1, 2]
15+
16+
import std / sequtils
17+
18+
block: # issue #19703
19+
iterator combinations[T](s: seq[T], r: Positive): seq[T] =
20+
yield @[s[0], s[1]]
21+
22+
iterator pairwise[T](s: openArray[T]): seq[T] =
23+
yield @[s[0], s[0]]
24+
25+
proc checkSpecialSubset5(s: seq[int]): bool =
26+
toSeq(
27+
toSeq(
28+
s.combinations(2)
29+
).map(proc(a: auto): int = a[0]).pairwise()
30+
).any(proc(a: auto): bool = a == @[s[0], s[0]])
31+
32+
doAssert checkSpecialSubset5 @[1, 2]

0 commit comments

Comments
 (0)