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.
This commit is contained in:
Judd
2020-04-21 20:50:16 +08:00
committed by GitHub
parent 1a44b7e3ce
commit 04c326569b
2 changed files with 39 additions and 14 deletions

View File

@@ -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.

View File

@@ -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))