-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fixes #8577, #8580, other bug fixes #8584
Conversation
daf06f6
to
f3cfd04
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more failing test case:
[].mapIt(it)
lib/pure/collections/sequtils.nim
Outdated
when compiles(s.len): | ||
evalOnce(t, s) | ||
# using t_D20180808T211500 to avoid https://github.com/nim-lang/Nim/issues/8580 | ||
evalOnce(t_D20180808T211500, s, type(s) isnot openArray) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is nasty. Using a block:
is a somewhat cleaner workaround.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of checking whether s
is an openArray
I'd just add another compiles((let _ = s))
to the when
above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This usage of compiles
seems to be a hack... :-/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, but I can't think of a better way to shunt the bare openArray
literals into the other code path
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is nasty. Using a block: is a somewhat cleaner workaround.
used a block; much cleaner, thanks!
compiles((let _ = s))
had thought of that but will likely lead to other bugs and hide other issues
Yep, but I can't think of a better way to shunt the bare openArray literals into the other code path
not sure what you're suggesting besides compiles
; what could go wrong with type(s) isnot openArray
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as discussed here https://gitter.im/nim-lang/Nim?at=5b6c0cf3637ee66082c775e8, I changed to compiles((let _ = s))
(see comments in code)
illegal (just as PTAL (all comments addressed) |
89b36af
to
385be76
Compare
PTAL all comments addressed (after fix to |
lib/pure/collections/sequtils.nim
Outdated
doAssert foo([1,2,3]) == @[2,3,4] | ||
|
||
block: # mapIt with direct openArray | ||
# see https://github.com/_render_node/MDExOlB1bGxSZXF1ZXN0MjA3MTQ3MTIw/pull_requests/timeline#issuecomment-411614711 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the github.com/_render_node/..
link?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah... this URL doesn't load.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall the PR is fine. If I wasn't so picky and unfamiliar with this code I would have merged it :)
lib/pure/collections/sequtils.nim
Outdated
# literal would be substituted twice | ||
# BUG: `evalOnce(t, s, false)` would lead to C compile errors | ||
# (`error: use of undeclared identifier`) instead of Nim compile errors | ||
evalOnce(t, s, compiles((let _ = s))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
t
, s
I know that you didn't introduce these names but I really despise single character variable names. In reviewing this PR I had to go back and forth between various templates to work out what t
is meant to be here.
Perhaps they could be changed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Side note: this evalOnce
macro feels like a total hack to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The compiles
check should be moved above in the enclosing if
, you don't need the third parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
almost procs in this module use single char arg names so I don't wanna special case mapIt, feel free to change that in a subsequent PR.
change s to s2 to make it obvious it relates to s; also improved var names of evalOnce and added a bunch of documentation.
Side note: this evalOnce macro feels like a total hack to me.
feel free to improve that in a subsequent PR. It's there for a reason (avoid double evaluation bugs, handle openArray and other edge cases) and neither @LemonBoy nor I could come up with something better
lib/pure/collections/sequtils.nim
Outdated
doAssert foo([1,2,3]) == @[2,3,4] | ||
|
||
block: # mapIt with direct openArray | ||
# see https://github.com/_render_node/MDExOlB1bGxSZXF1ZXN0MjA3MTQ3MTIw/pull_requests/timeline#issuecomment-411614711 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah... this URL doesn't load.
lib/pure/collections/sequtils.nim
Outdated
|
||
block: # mapIt with direct openArray | ||
# see https://github.com/_render_node/MDExOlB1bGxSZXF1ZXN0MjA3MTQ3MTIw/pull_requests/timeline#issuecomment-411614711 | ||
doAssert openArray[int]([1,2]).mapIt(it) == @[1,2] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A better test would be to create a proc
that takes an openarray
. Pass it a list and call mapIt on the argument.
Frankly, I'm surprised this works. openArray
is a pseudo-type AFAIK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i already have a test for that, see "mapIt with openArray"
lib/pure/collections/sequtils.nim
Outdated
doAssert openArray[int]([1,2]).mapIt(it) == @[1,2] | ||
|
||
block: # mapIt test, see https://github.com/nim-lang/Nim/pull/8584#pullrequestreview-144723468 | ||
# NOTE: `[].mapIt(it)` is illegal, just as `let a = @[]` is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about
mapIt([], it)
mapIt(@[], it)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added a test doAssert: not compiles(mapIt(@[], it))
; it should indeed not compile as explained in comments (lacks type information)
PTAL. all comments addressed. |
|
||
# 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))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This compiles(...)
block should go with compiles(s.len)
.
If you don't do so and s
is a openArray[int](...)
the template expansion below will replicate s
two times like this:
...
var result = newSeq[outType](openArray[int](...).len)
for it {.inject.} in openArray[int](...):
...
This edge case is better handled (IMO) by the other code path even though we don't make use of the .len
, after all this is an edge case as you don't go and cast openarray
s.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know about this limitation (it's documented in the PR, see below) but I disagree with your proposed change:
- with your suggestion, it'll affect valid (non edge case) code paths, resulting in un-optimized code for these.
please try the PR with your suggestion and see what happens by inserting these echo statements:
when compiles(s.len) and compiles((let _ = s)):
block:
evalOnceAs(s2, s, true)
echo "optimized"
var i = 0
var result = newSeq[outType](s2.len)
for it {.inject.} in s2:
result[i] = op
i += 1
result
else:
echo "fallback"
var result: seq[outType] = @[]
for it {.inject.} in s:
result.add(op)
result
will print:
optimized
fallback
fallback
fallback
optimized
optimized
optimized
optimized
fallback
whereas with current PR it prints:
optimized
optimized
optimized
optimized
optimized
optimized
optimized
optimized
fallback
ie it does the correct thing (optimized code + no duplicate evaluation) in all cases except the in the very edge case of an openArray
constructor passed to a proc (template would be ok).
copying verbatim from PR:
block: # mapIt with direct openArray
proc foo1(x: openArray[int]): seq[int] = x.mapIt(it * 10)
counter = 0
doAssert foo1(openArray[int]([identity(1),identity(2)])) == @[10,20]
doAssert counter == 2
template foo2(x: openArray[int]): seq[int] = x.mapIt(it * 10)
counter = 0
doAssert foo2(openArray[int]([identity(1),identity(2)])) == @[10,20]
# TODO: this fails; not sure how to fix this case
# doAssert counter == 2
Note also that this edge case behavior is pre-existing to this PR, so I see now reason we can't merge this now; we can always do a subsequent PR later if we find a way that doesn't affect non-edge cases adversly while handling this edge case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see, that's fine by me then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cool. PR still marked as @LemonBoy requested changes though...
PTAL: can we please get this merged ASAP? it fixes pre-existing bugs |
And we're sure it doesn't introduce new bugs, right? Oh well, will clean this up later. |
thank you.
obviously no such guarantees, but it came with increased test coverage |
…rator twice (nim-lang#8586) * cleanups refs nim-lang#8584 * fixes nim-lang#7187
/c @Araq @LemonBoy more fixes coming after this PR, eg: #8586 (+ 2 others) which depend on this to be merged first ; so can we merge this sooner rather than later?
mapIt
still can't be used withopenArray
even after #8543, #8567: fails during bootstrap #8577let t=s.mapIt(it)
givesError: redefinition of 't'
#8580result
inmapIt