From e2e22e3d7e29985579b2c91c639c71229422f349 Mon Sep 17 00:00:00 2001
From: Damien George <damien.p.george@gmail.com>
Date: Tue, 10 Jul 2018 16:21:34 +1000
Subject: [PATCH] py/objgenerator: Implement __name__ with normal fun attr
 accessor code.

With the recent change b488a4a8480533a6a3c9468c2f8bd359c94d4d02, a
generating function now has the same layout in memory as a normal bytecode
function, and so can reuse the latter's attribute accessor code to
implement __name__.
---
 py/objfun.c                    |  4 ++--
 py/objfun.h                    |  2 ++
 py/objgenerator.c              |  3 +++
 tests/basics/generator_name.py | 16 ++++++++++++++++
 tests/run-tests                |  2 +-
 5 files changed, 24 insertions(+), 3 deletions(-)
 create mode 100644 tests/basics/generator_name.py

diff --git a/py/objfun.c b/py/objfun.c
index 8c51d92e0..b8657ec95 100644
--- a/py/objfun.c
+++ b/py/objfun.c
@@ -338,7 +338,7 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
 }
 
 #if MICROPY_PY_FUNCTION_ATTRS
-STATIC void fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+void mp_obj_fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
     if (dest[0] != MP_OBJ_NULL) {
         // not load attribute
         return;
@@ -358,7 +358,7 @@ const mp_obj_type_t mp_type_fun_bc = {
     .call = fun_bc_call,
     .unary_op = mp_generic_unary_op,
 #if MICROPY_PY_FUNCTION_ATTRS
-    .attr = fun_bc_attr,
+    .attr = mp_obj_fun_bc_attr,
 #endif
 };
 
diff --git a/py/objfun.h b/py/objfun.h
index fbb351626..257b8a65a 100644
--- a/py/objfun.h
+++ b/py/objfun.h
@@ -41,4 +41,6 @@ typedef struct _mp_obj_fun_bc_t {
     mp_obj_t extra_args[];
 } mp_obj_fun_bc_t;
 
+void mp_obj_fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest);
+
 #endif // MICROPY_INCLUDED_PY_OBJFUN_H
diff --git a/py/objgenerator.c b/py/objgenerator.c
index 8b898c937..c45bebacd 100644
--- a/py/objgenerator.c
+++ b/py/objgenerator.c
@@ -68,6 +68,9 @@ const mp_obj_type_t mp_type_gen_wrap = {
     .name = MP_QSTR_generator,
     .call = gen_wrap_call,
     .unary_op = mp_generic_unary_op,
+    #if MICROPY_PY_FUNCTION_ATTRS
+    .attr = mp_obj_fun_bc_attr,
+    #endif
 };
 
 /******************************************************************************/
diff --git a/tests/basics/generator_name.py b/tests/basics/generator_name.py
new file mode 100644
index 000000000..77259a821
--- /dev/null
+++ b/tests/basics/generator_name.py
@@ -0,0 +1,16 @@
+# test __name__ on generator functions
+
+def Fun():
+    yield
+
+class A:
+    def Fun(self):
+        yield
+
+try:
+    print(Fun.__name__)
+    print(A.Fun.__name__)
+    print(A().Fun.__name__)
+except AttributeError:
+    print('SKIP')
+    raise SystemExit
diff --git a/tests/run-tests b/tests/run-tests
index e1b594edf..e4a0e20ed 100755
--- a/tests/run-tests
+++ b/tests/run-tests
@@ -336,7 +336,7 @@ def run_tests(pyb, tests, args, base_path="."):
     # Some tests are known to fail with native emitter
     # Remove them from the below when they work
     if args.emit == 'native':
-        skip_tests.update({'basics/%s.py' % t for t in 'gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_executing gen_yield_from_iter gen_yield_from_send gen_yield_from_stopped gen_yield_from_throw gen_yield_from_throw2 gen_yield_from_throw3 generator1 generator2 generator_args generator_close generator_closure generator_exc generator_pend_throw generator_return generator_send'.split()}) # require yield
+        skip_tests.update({'basics/%s.py' % t for t in 'gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_executing gen_yield_from_iter gen_yield_from_send gen_yield_from_stopped gen_yield_from_throw gen_yield_from_throw2 gen_yield_from_throw3 generator1 generator2 generator_args generator_close generator_closure generator_exc generator_name generator_pend_throw generator_return generator_send'.split()}) # require yield
         skip_tests.update({'basics/%s.py' % t for t in 'bytes_gen class_store_class globals_del string_join'.split()}) # require yield
         skip_tests.update({'basics/async_%s.py' % t for t in 'def await await2 for for2 with with2 with_break with_return'.split()}) # require yield
         skip_tests.update({'basics/%s.py' % t for t in 'try_reraise try_reraise2'.split()}) # require raise_varargs
-- 
GitLab