Commit 5302558e authored by Kirill Smelkov's avatar Kirill Smelkov

golang: Make @func to be idempotent

i.e. make double call of func(func(f)) to return exactly the same as func(f).

This is correct to do as the first func call already returns a wrapper
that setups additional frame for defer. The second func call, if doing
the same, will wrap the thing just one more time and there will be two
frames for defer, but defer needs only one to work correctly.

So far we had no case when such double func calls would appear in
practice, because

    @func
    @func
    def f():
         ...

would immediately catch attention.

However in the next patch we will have this case to appear internally
when handling properties. So it is better to make sure beforehand no
waste of resources will happen.

/reviewed-by @levin.zimmermann
/reviewed-on nexedi/pygolang!31
parent 0c0f4b2a
......@@ -119,7 +119,11 @@ def _func(f):
# prepare function that runs f under separate frame, where defer will register calls
# keep all f attributes, like __name__, __doc__, etc on the wrapper
_ = decorator.decorate(f, _goframe)
# if f was already wrapped with _func - no need to wrap it again
_ = f
if getattr(f, '__go_wrapper__', None) is not _goframe:
_ = decorator.decorate(f, _goframe)
_.__go_wrapper__ = _goframe
# repack _ into e.g. @staticmethod if that was used on f.
if fclass is not None:
......
......@@ -1034,6 +1034,14 @@ def test_func():
assert MyClass.var.__module__ == __name__
assert MyClass.var.__name__ == 'var'
# test that func·func = func (double _func calls will be done internally for
# getter when handling @func(@MyClass.vproperty.setter)
def f(): pass
g = func(f)
h = func(g)
assert h is g
# @func overhead at def time.
def bench_def(b):
for i in xrange(b.N):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment