1.1 --- a/deducer.py Thu Jul 12 00:15:16 2018 +0200
1.2 +++ b/deducer.py Thu Jul 12 18:53:58 2018 +0200
1.3 @@ -2938,7 +2938,13 @@
1.4 # Produce an advisory instruction regarding the context.
1.5
1.6 if context_var:
1.7 - if context_test in ("ignore", "replace"):
1.8 +
1.9 + # Only verify the context for invocation purposes if a suitable
1.10 + # test has been performed.
1.11 +
1.12 + if context_test in ("ignore", "replace") or \
1.13 + final_method in ("access-invoke", "static-invoke"):
1.14 +
1.15 emit(("<context_identity_verified>", context_var))
1.16 else:
1.17 emit(("<context_identity>", context_var))
2.1 --- a/templates/ops.c Thu Jul 12 00:15:16 2018 +0200
2.2 +++ b/templates/ops.c Thu Jul 12 18:53:58 2018 +0200
2.3 @@ -231,7 +231,7 @@
2.4
2.5 /* Context-related operations. */
2.6
2.7 -int __test_context_update(__attr context, __attr attr)
2.8 +int __test_context_update(__attr context, __attr attr, int invoke)
2.9 {
2.10 /* Return whether the context should be updated for the attribute. */
2.11
2.12 @@ -258,6 +258,11 @@
2.13 __raise_type_error();
2.14 }
2.15
2.16 + /* Without a null or instance context, an invocation cannot be performed. */
2.17 +
2.18 + if (invoke)
2.19 + __raise_unbound_method_error();
2.20 +
2.21 /* Test for access to a type class attribute using a type instance. */
2.22
2.23 if (__test_specific_type(attrcontextvalue, &__TYPE_CLASS_TYPE) && __is_type_instance(__VALUE(context)))
2.24 @@ -272,7 +277,7 @@
2.25 {
2.26 /* Update the context or return the unchanged attribute. */
2.27
2.28 - if (__test_context_update(context, attr))
2.29 + if (__test_context_update(context, attr, 0))
2.30 return __update_context(context, attr);
2.31 else
2.32 return attr;
2.33 @@ -288,7 +293,7 @@
2.34 /* Revert the local context to that employed by the attribute if the
2.35 supplied context is not appropriate. */
2.36
2.37 - if (!__test_context_update(context, attr))
2.38 + if (!__test_context_update(context, attr, 1))
2.39 contexts[target] = __CONTEXT_AS_VALUE(attr);
2.40 return attr;
2.41 }
2.42 @@ -297,7 +302,7 @@
2.43 {
2.44 /* Set the local context to the specified context if appropriate. */
2.45
2.46 - if (__test_context_update(context, __ATTRVALUE(value)))
2.47 + if (__test_context_update(context, __ATTRVALUE(value), 1))
2.48 contexts[target] = context;
2.49 return __ATTRVALUE(value);
2.50 }
3.1 --- a/templates/ops.h Thu Jul 12 00:15:16 2018 +0200
3.2 +++ b/templates/ops.h Thu Jul 12 18:53:58 2018 +0200
3.3 @@ -101,7 +101,7 @@
3.4
3.5 /* Context-related operations. */
3.6
3.7 -int __test_context_update(__attr context, __attr attr);
3.8 +int __test_context_update(__attr context, __attr attr, int invoke);
3.9 __attr __test_context(__attr context, __attr attr);
3.10 __attr __update_context(__attr context, __attr attr);
3.11 __attr __test_context_revert(int target, __attr context, __attr attr, __attr contexts[]);
4.1 --- a/templates/progops.c Thu Jul 12 00:15:16 2018 +0200
4.2 +++ b/templates/progops.c Thu Jul 12 18:53:58 2018 +0200
4.3 @@ -151,6 +151,11 @@
4.4 __Raise(__new___builtins___core_OverflowError(__NULL));
4.5 }
4.6
4.7 +void __raise_unbound_method_error()
4.8 +{
4.9 + __Raise(__new___builtins___core_UnboundMethodInvocation(__NULL));
4.10 +}
4.11 +
4.12 void __raise_type_error()
4.13 {
4.14 __Raise(__new___builtins___core_TypeError(__NULL));
5.1 --- a/templates/progops.h Thu Jul 12 00:15:16 2018 +0200
5.2 +++ b/templates/progops.h Thu Jul 12 18:53:58 2018 +0200
5.3 @@ -52,6 +52,7 @@
5.4 void __raise_memory_error();
5.5 void __raise_os_error(__attr value, __attr arg);
5.6 void __raise_overflow_error();
5.7 +void __raise_unbound_method_error();
5.8 void __raise_underflow_error();
5.9 void __raise_zero_division_error();
5.10 void __raise_type_error();
6.1 --- a/tests/methods_rebound.py Thu Jul 12 00:15:16 2018 +0200
6.2 +++ b/tests/methods_rebound.py Thu Jul 12 18:53:58 2018 +0200
6.3 @@ -13,9 +13,32 @@
6.4
6.5 d = D()
6.6
6.7 +def fn():
6.8 + return 456
6.9 +
6.10 +class E:
6.11 + f = fn
6.12 + g = C.f
6.13 +
6.14 +e = E()
6.15 +
6.16 print c.f.__name__ # f
6.17 print c.f() # <__main__.C instance>
6.18 # 123
6.19 print d.f.__name__ # wrapper
6.20 print d.f() # <__main__.C instance>
6.21 # 123
6.22 +
6.23 +print e.f.__name__ # fn
6.24 +print e.f() # 456
6.25 +print e.g.__name__ # f
6.26 +
6.27 +try:
6.28 + print e.g()
6.29 +except TypeError:
6.30 + print "e.g(): e is an incompatible instance for E.g which is C.f"
6.31 +
6.32 +g = get_using(E.g, c)
6.33 +print g.__name__ # f
6.34 +print g() # <__main__.C instance>
6.35 + # 123
7.1 --- a/translator.py Thu Jul 12 00:15:16 2018 +0200
7.2 +++ b/translator.py Thu Jul 12 18:53:58 2018 +0200
7.3 @@ -1070,9 +1070,21 @@
7.4
7.5 context_required = True
7.6 have_access_context = isinstance(expr, AttrResult)
7.7 +
7.8 + # The context identity is merely the thing providing the context.
7.9 + # A verified context is one that does not need further testing for
7.10 + # suitability.
7.11 +
7.12 context_identity = have_access_context and expr.context()
7.13 context_verified = have_access_context and expr.context_verified()
7.14 +
7.15 + # The presence of any test operations in the accessor expression.
7.16 + # With such operations present, the expression cannot be eliminated.
7.17 +
7.18 tests_accessor = have_access_context and expr.tests_accessor()
7.19 +
7.20 + # Parameter details and parameter list dimensions.
7.21 +
7.22 parameters = None
7.23 num_parameters = None
7.24 num_defaults = None
7.25 @@ -1252,11 +1264,13 @@
7.26
7.27 if context_required:
7.28 if have_access_context:
7.29 - args = [context_identity]
7.30 + context_arg = context_identity
7.31 else:
7.32 - args = ["__CONTEXT_AS_VALUE(%s)" % target_var]
7.33 + context_arg = "__CONTEXT_AS_VALUE(%s)" % target_var
7.34 else:
7.35 - args = ["__NULL"]
7.36 + context_arg = "__NULL"
7.37 +
7.38 + args = [context_arg]
7.39
7.40 # Complete the array with null values, permitting tests for a complete
7.41 # set of arguments.
7.42 @@ -1398,25 +1412,23 @@
7.43 elif function:
7.44 if context_required:
7.45
7.46 - # With context_verified or context_identity...
7.47 -
7.48 - if have_access_context:
7.49 + # Avoid further context testing if appropriate.
7.50 +
7.51 + if have_access_context and context_verified:
7.52 emit("__get_function_member(%s)" % target_expr)
7.53
7.54 # Otherwise, test the context for the function/method.
7.55
7.56 else:
7.57 - emit("__get_function(__CONTEXT_AS_VALUE(%s), %s)" % (
7.58 - target_var, target_expr))
7.59 + emit("__get_function(%s, %s)" % (context_arg, target_expr))
7.60 else:
7.61 emit("_get_function_member(%s)" % target_expr)
7.62
7.63 # With known parameters, the target can be tested.
7.64
7.65 elif known_parameters:
7.66 - context_arg = context_required and args[0] or "__NULL"
7.67 if self.always_callable(refs):
7.68 - if context_verified or context_identity:
7.69 + if context_verified:
7.70 emit("__get_function_member(%s)" % target_expr)
7.71 else:
7.72 emit("__get_function(%s, %s)" % (context_arg, target_expr))