diff options
author | Judd <foldl@outlook.com> | 2020-04-21 20:50:16 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-21 14:50:16 +0200 |
commit | 04c326569bdafa619d6596d2d674d3acbcc1ecf3 (patch) | |
tree | 82bc02bdb92dc2a60e9d5a3164489f0d5580b3d5 | |
parent | 1a44b7e3ced0e2d092f2c607d61a6b28c1ca339c (diff) | |
download | Nim-04c326569bdafa619d6596d2d674d3acbcc1ecf3.tar.gz |
fix mapIt issues #12625 & #12639 (#14041)
* fix mapIt issues #12625 & #12639: 1. fallback to call `map` when the result of `op` is a closure; 2. use `items(s)` in the for loop. * fix test errors. * add comments and InType is moved. * fix ident.
-rw-r--r-- | lib/pure/collections/sequtils.nim | 50 | ||||
-rw-r--r-- | tests/collections/tseq.nim | 3 |
2 files changed, 39 insertions, 14 deletions
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index ea02ff1fd..02d48973e 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -924,24 +924,46 @@ template mapIt*(s: typed, op: untyped): untyped = block: var it{.inject.}: type(items(s)); op)) - when compiles(s.len): - block: # using a block avoids https://github.com/nim-lang/Nim/issues/8580 + when OutType is not (proc): + # Here, we avoid to create closures in loops. + # This avoids https://github.com/nim-lang/Nim/issues/12625 + when compiles(s.len): + block: # using a block avoids https://github.com/nim-lang/Nim/issues/8580 - # BUG: `evalOnceAs(s2, s, false)` would lead to C compile errors - # (`error: use of undeclared identifier`) instead of Nim compile errors - evalOnceAs(s2, s, compiles((let _ = s))) + # BUG: `evalOnceAs(s2, s, false)` would lead to C compile errors + # (`error: use of undeclared identifier`) instead of Nim compile errors + evalOnceAs(s2, s, compiles((let _ = s))) - var i = 0 - var result = newSeq[OutType](s2.len) - for it {.inject.} in s2: - result[i] = op - i += 1 + var i = 0 + var result = newSeq[OutType](s2.len) + for it {.inject.} in s2: + result[i] = op + i += 1 + result + else: + var result: seq[OutType] = @[] + # use `items` to avoid https://github.com/nim-lang/Nim/issues/12639 + for it {.inject.} in items(s): + result.add(op) result else: - var result: seq[OutType] = @[] - for it {.inject.} in s: - result.add(op) - result + # `op` is going to create closures in loops, let's fallback to `map`. + # NOTE: Without this fallback, developers have to define a helper function and + # call `map`: + # [1, 2].map((it) => ((x: int) => it + x)) + # With this fallback, above code can be simplified to: + # [1, 2].mapIt((x: int) => it + x) + # In this case, `mapIt` is just syntax sugar for `map`. + + when defined(nimHasTypeof): + type InType = typeof(items(s), typeOfIter) + else: + type InType = type(items(s)) + # Use a help proc `f` to create closures for each element in `s` + let f = proc (x: InType): OutType = + let it {.inject.} = x + op + map(s, f) template applyIt*(varSeq, op: untyped) = ## Convenience template around the mutable ``apply`` proc to reduce typing. diff --git a/tests/collections/tseq.nim b/tests/collections/tseq.nim index 6a28bc8e6..ac68e5636 100644 --- a/tests/collections/tseq.nim +++ b/tests/collections/tseq.nim @@ -204,3 +204,6 @@ block ttoseq: var y: type("a b c".split) y = "xzy" stdout.write("\n") + +block tseqmapitchain: + doAssert @[101, 102] == [1, 2].mapIt(func (x: int): int = it + x).mapIt(it(100)) \ No newline at end of file |