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
Add facility to support with-contexts #3017
Conversation
and some cleanup
# Conflicts: # numba/ir_utils.py
Codecov Report
@@ Coverage Diff @@
## master #3017 +/- ##
=========================================
+ Coverage 78.7% 81.1% +2.39%
=========================================
Files 384 386 +2
Lines 75091 75675 +584
Branches 8436 8488 +52
=========================================
+ Hits 59098 61373 +2275
+ Misses 14740 13003 -1737
- Partials 1253 1299 +46 |
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.
Thanks for the patch @sklam. Looks like a good start on this feature set. Only a few minor comments, I'll add more items directly to the ticket.
numba/dispatcher.py
Outdated
def get_call_template(self, args, kws): | ||
""" | ||
Get a typing.ConcreteTemplate for this dispatcher and the given | ||
*args* and *kws* types. This allows to resolve the return type. |
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.
Perhaps This enables the resolving of the return type.
?
numba/ir_utils.py
Outdated
|
||
def fill_callee_prologue(block, inputs, label_next): | ||
""" | ||
Fill a new block *block* that unwraps argument using names in *inputs* and |
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.
s/argument/arguments/
numba/ir_utils.py
Outdated
def fill_callee_prologue(block, inputs, label_next): | ||
""" | ||
Fill a new block *block* that unwraps argument using names in *inputs* and | ||
then jump to *label_next*. |
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.
s/jump/jumps/
numba/transforms.py
Outdated
return block | ||
entry_block = blocks[loopinfo.callfrom] | ||
scope = entry_block.scope | ||
loc = entry_block.loc | ||
|
||
def make_epilogue(): |
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.
Is this function now dead? Think ir_utils.fill_callee_epilogue
does the functional equivalent?
numba/transforms.py
Outdated
|
||
|
||
def _get_with_contextmanager(func_ir, blocks, blk_start): | ||
"""Get the global object used for as the context manager |
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.
s/as//
counters.pop(ir.Del, None) | ||
# There MUST NOT be any other statements | ||
if counters: | ||
raise errors.CompilerError( |
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.
Can a ref to loc
be easily supplied here such that the location will be pointed at by the error handlers?
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 loc
numba/transforms.py
Outdated
) | ||
|
||
|
||
def _cfg_nodes_in_region(cfg, region_begin, region_end): |
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.
Wonder whether this should perhaps go in ir_utils
or controlflow
?
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.
There are a number of things in transforms.py
that can go into other modules. I want to defer that task to later.
numba/transforms.py
Outdated
for s, e in withs: | ||
if s not in doms[e]: | ||
msg = "Entry of with-context not dominating the exit." | ||
raise errors.CompilerError(msg) |
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.
Can a loc
be supplied to these two errors?
numba/withcontexts.py
Outdated
|
||
def _bypass_with_context(blocks, blk_start, blk_end, forwardvars): | ||
"""Given the starting and ending block of the with-context, | ||
replaces a new head block that jumps to the end. |
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.
Should this be replaces the head block with a new block that jumps to the end
.?
numba/withcontexts.py
Outdated
|
||
|
||
class _CallContextType(WithContext): | ||
"""A simple context-manager that tells the compiler lift the body of the |
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.
s/compiler/compiler to/
Just done a bit of manual testing... some items for discussion
def objmode_with_objmode():
object()
with call_context:
object()
return 1
def lift():
with call_context:
pass
print(njit(parallel=True)(lift)()) gives:
which was somewhat unexpected as there's no stencil anywhere near the source function! Finally, is this to be documented in the developer documentation, or should that wait until more |
as per comments by @stuartarchibald
#3017 (comment) raised important concerns. Given how this patch is not adding any user facing feature yet, I am ok to delay the merge until some of the concerns are resolved even if it will not make it this release cycle. Particularly, the breaking of parfor features should be addressed first. As for the objectmode support, there were no support for contextmanager in objectmode before. It will fail in the bytecode analysis. I think it is acceptable to skip objectmode support for this PR and just do a better errmsg for it. Future patches should implement the objectmode support. |
@sklam the Parfor-related issue was a simple bug that I just fixed. |
# Conflicts: # numba/ir.py # numba/ir_utils.py
Oh, looks like I need to resolve the |
This is ready for review now |
contextmanager : IR value | ||
begin, end : int | ||
The beginning and the ending offset of the with-body. | ||
loc : int |
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.
loc
is a ir.Loc
instance?
njit(liftcall4)() | ||
# Known error. We only support one context manager per function | ||
# for body that are lifted. | ||
self.assertIn("re-entrant", str(raises.exception)) |
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.
Any view on doing something with non-existent context managers? I just accidentally forgot to import the call_context
, but this equally applies to e.g.
from numba import njit
def bar():
with unknown_ctx:
pass
njit(bar)()
which gives the same fairly spectacular traceback (as the one if you forget the import) ending with:
<path>/numba/numba/transforms.py in with_lifting(func_ir, typingctx, targetctx, flags, locals)
293 _legalize_with_head(blocks[blk_start])
294 cmkind = _get_with_contextmanager(func_ir, blocks, blk_start)
--> 295 sub = cmkind.mutate_with_body(func_ir, blocks, blk_start, blk_end,
296 body_blocks, dispatcher_factory)
297 sub_irs.append(sub)
AttributeError: Failed at nopython (nopython frontend)
'object' object has no attribute 'mutate_with_body'
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 think this should be fixed in this PR
Thanks for the fixes @sklam I made a couple more comments but am of the view that this can be merged whilst acknowledging that there is more work to be done/this is experimental and incremental development is expected. |
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.
Thanks for the further fixes @sklam, one minor comment to resolve then this can be merged as convenient. Thanks again.
numba/transforms.py
Outdated
) | ||
if not hasattr(ctxobj, 'mutate_with_body'): | ||
raise errors.CompilerError( | ||
"Unsupported use of contextmanager", |
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.
Should that be Unsupported context manager in use
, I think at this point the context manager statement has been identified and this is just duck type testing if it has an attr specific to Numba and is therefore supported?
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.
Agree and fixed
@sklam tests are failing, think the error message update needs reflecting in the unit test catching the error. Thanks. |
oops |
Thanks for fixing. Merging. |
Adds pluggable facility to support
with
contexts. Two builtin contextmanagers are implemented for testing.