# HG changeset patch # User Paul Boddie # Date 1487527582 -3600 # Node ID adcdaeb19307f6771844963d1b4cd1cf5976c445 # Parent f92610e27e9250436e8d6508185795d5fe7574d2 Fixed the context test and set operation to replace the local context with any applicable attribute context. Added a test of method rebinding that requires this fix. diff -r f92610e27e92 -r adcdaeb19307 encoders.py --- a/encoders.py Sun Feb 19 18:39:11 2017 +0100 +++ b/encoders.py Sun Feb 19 19:06:22 2017 +0100 @@ -215,7 +215,7 @@ ) context_ops = ( - "", "", "", "", + "", "", "", "", ) reference_acting_ops = attribute_ops + checked_ops + typename_ops diff -r f92610e27e92 -r adcdaeb19307 optimiser.py --- a/optimiser.py Sun Feb 19 18:39:11 2017 +0100 +++ b/optimiser.py Sun Feb 19 19:06:22 2017 +0100 @@ -567,7 +567,7 @@ # immediately invoked attribute. elif final_method == "access-invoke": - emit(("", context_var, accessor)) + emit(("", context_var, accessor)) # Test the context and update the attribute details if # appropriate. diff -r f92610e27e92 -r adcdaeb19307 templates/ops.c --- a/templates/ops.c Sun Feb 19 18:39:11 2017 +0100 +++ b/templates/ops.c Sun Feb 19 19:06:22 2017 +0100 @@ -214,6 +214,10 @@ if (__is_instance(context)) { + /* Obtain the special class attribute position and code identifying the + attribute context's class, inspecting the context instance for + compatibility. */ + if (__test_common_instance(context, __TYPEPOS(attrcontext), __TYPECODE(attrcontext))) return 1; else diff -r f92610e27e92 -r adcdaeb19307 templates/ops.h --- a/templates/ops.h Sun Feb 19 18:39:11 2017 +0100 +++ b/templates/ops.h Sun Feb 19 19:06:22 2017 +0100 @@ -74,12 +74,20 @@ __attr __test_context(__ref context, __attr attr); __attr __update_context(__ref context, __attr attr); -#define __test_context_set(__TARGET, __CONTEXT, __ATTR) \ - (__test_context_update(__CONTEXT, __ATTR) ? (__set_context(__TARGET, (__attr) {.value=__CONTEXT}), __ATTR) : __ATTR) +/* Revert the local context to that employed by the attribute if the supplied + context is not appropriate. */ + +#define __test_context_revert(__TARGET, __CONTEXT, __ATTR) \ + (__test_context_update(__CONTEXT, __ATTR) \ + ? __ATTR \ + : (__set_context(__TARGET, __CONTEXT_AS_VALUE(__ATTR)), __ATTR)) + +/* Set the local context to the specified context if appropriate. */ #define __test_context_static(__TARGET, __CONTEXT, __REF) \ - (__test_context_update(__CONTEXT, (__attr) {.value=__REF}) ? \ - (__set_context(__TARGET, (__attr) {.value=__CONTEXT}), (__attr) {.value=__REF}) : (__attr) {.value=__REF}) + (__test_context_update(__CONTEXT, (__attr) {.value=__REF}) \ + ? (__set_context(__TARGET, (__attr) {.value=__CONTEXT}), (__attr) {.value=__REF}) \ + : (__attr) {.value=__REF}) #define __get_context(__TARGET) (__tmp_contexts[__TARGET]) #define __set_context(__TARGET, __ATTR) (__tmp_contexts[__TARGET] = (__ATTR).value) diff -r f92610e27e92 -r adcdaeb19307 tests/methods_rebound.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/methods_rebound.py Sun Feb 19 19:06:22 2017 +0100 @@ -0,0 +1,21 @@ +class C: + def f(self): + print self + return self.value() + + def value(self): + return 123 + +c = C() + +class D: + f = c.f + +d = D() + +print c.f.__name__ # f +print c.f() # <__main__.C instance> + # 123 +print d.f.__name__ # wrapper +print d.f() # <__main__.C instance> + # 123 diff -r f92610e27e92 -r adcdaeb19307 translator.py --- a/translator.py Sun Feb 19 18:39:11 2017 +0100 +++ b/translator.py Sun Feb 19 19:06:22 2017 +0100 @@ -789,7 +789,7 @@ # Mappings to be replaced by those given below. "" : "__tmp_contexts", - "" : "__tmp_contexts", + "" : "__tmp_contexts", "" : "__tmp_contexts", "" : "__tmp_contexts", "" : "__tmp_private_context", @@ -799,7 +799,7 @@ self.op_subs = { "" : "__get_context", - "" : "__test_context_set", + "" : "__test_context_revert", "" : "__test_context_static", "" : "__set_context", "" : "__set_private_context",