1.1 --- a/deducer.py Sat Mar 25 21:58:51 2017 +0100
1.2 +++ b/deducer.py Sat Mar 25 22:00:14 2017 +0100
1.3 @@ -2908,7 +2908,10 @@
1.4 # Produce an advisory instruction regarding the context.
1.5
1.6 if context_var:
1.7 - emit(("<context_identity>", context_var))
1.8 + if context_test in ("ignore", "replace"):
1.9 + emit(("<context_identity_verified>", context_var))
1.10 + else:
1.11 + emit(("<context_identity>", context_var))
1.12
1.13 # Produce an advisory instruction regarding the final attribute.
1.14
2.1 --- a/results.py Sat Mar 25 21:58:51 2017 +0100
2.2 +++ b/results.py Sat Mar 25 22:00:14 2017 +0100
2.3 @@ -48,6 +48,9 @@
2.4 def context(self):
2.5 return None
2.6
2.7 + def context_verified(self):
2.8 + return None
2.9 +
2.10 def discards_temporary(self, test=True):
2.11 return None
2.12
3.1 --- a/templates/ops.c Sat Mar 25 21:58:51 2017 +0100
3.2 +++ b/templates/ops.c Sat Mar 25 22:00:14 2017 +0100
3.3 @@ -335,11 +335,16 @@
3.4 or type instance contexts for type methods. */
3.5
3.6 if (__ISNULL(context) || __is_instance(__VALUE(context)) || __type_method_invocation(context, target))
3.7 - return __load_via_object(__VALUE(target), __fn__).fn;
3.8 + return __get_function_member(target);
3.9 else
3.10 return __unbound_method;
3.11 }
3.12
3.13 +__attr (*__get_function_member(__attr target))()
3.14 +{
3.15 + return __load_via_object(__VALUE(target), __fn__).fn;
3.16 +}
3.17 +
3.18 __attr (*__check_and_get_function(__attr context, __attr target))()
3.19 {
3.20 return __check_and_get_function_unwrapped(context, __unwrap_callable(target));
4.1 --- a/templates/ops.h Sat Mar 25 21:58:51 2017 +0100
4.2 +++ b/templates/ops.h Sat Mar 25 22:00:14 2017 +0100
4.3 @@ -115,6 +115,7 @@
4.4 __attr (*__get_function_unchecked(__attr target))();
4.5 __attr (*__get_function(__attr context, __attr target))();
4.6 __attr (*__get_function_unwrapped(__attr context, __attr target))();
4.7 +__attr (*__get_function_member(__attr target))();
4.8 __attr (*__check_and_get_function(__attr context, __attr target))();
4.9 __attr (*__check_and_get_function_unwrapped(__attr context, __attr target))();
4.10
5.1 --- a/translator.py Sat Mar 25 21:58:51 2017 +0100
5.2 +++ b/translator.py Sat Mar 25 22:00:14 2017 +0100
5.3 @@ -557,6 +557,7 @@
5.4
5.5 context_index = self.function_target - 1
5.6 context_identity = None
5.7 + context_identity_verified = False
5.8 final_identity = None
5.9
5.10 # Obtain encoded versions of each instruction, accumulating temporary
5.11 @@ -566,14 +567,15 @@
5.12
5.13 # Intercept a special instruction identifying the context.
5.14
5.15 - if instruction[0] == "<context_identity>":
5.16 + if instruction[0] in ("<context_identity>", "<context_identity_verified>"):
5.17 context_identity, _substituted = encode_access_instruction_arg(instruction[1], subs, instruction[0], context_index)
5.18 + context_identity_verified = instruction[0] == "<context_identity_verified>"
5.19 continue
5.20
5.21 # Intercept a special instruction identifying the target. The value
5.22 # is not encoded since it is used internally.
5.23
5.24 - if instruction[0] == "<final_identity>":
5.25 + elif instruction[0] == "<final_identity>":
5.26 final_identity = instruction[1]
5.27 continue
5.28
5.29 @@ -597,7 +599,7 @@
5.30 refs = [ref]
5.31
5.32 del self.attrs[0]
5.33 - return AttrResult(output, refs, location, context_identity)
5.34 + return AttrResult(output, refs, location, context_identity, context_identity_verified)
5.35
5.36 def init_substitutions(self):
5.37
5.38 @@ -1065,6 +1067,7 @@
5.39 context_required = True
5.40 have_access_context = isinstance(expr, AttrResult)
5.41 context_identity = have_access_context and expr.context()
5.42 + context_verified = have_access_context and expr.context_verified()
5.43 parameters = None
5.44 num_parameters = None
5.45 num_defaults = None
5.46 @@ -1353,20 +1356,26 @@
5.47 elif function:
5.48 if context_required:
5.49 if have_access_context:
5.50 - stages.append("__get_function(%s, %s)" % (
5.51 - context_identity, target_var))
5.52 + if context_verified:
5.53 + stages.append("__get_function_member(%s)" % target_var)
5.54 + else:
5.55 + stages.append("__get_function(%s, %s)" % (
5.56 + context_identity, target_var))
5.57 else:
5.58 stages.append("__get_function(__CONTEXT_AS_VALUE(%s), %s)" % (
5.59 context_var, target_var))
5.60 else:
5.61 - stages.append("__load_via_object(__VALUE(%s), __fn__).fn" % target_var)
5.62 + stages.append("_get_function_member(%s)" % target_var)
5.63
5.64 # With known parameters, the target can be tested.
5.65
5.66 elif known_parameters:
5.67 context_arg = context_required and args[0] or "__NULL"
5.68 if self.always_callable(refs):
5.69 - stages.append("__get_function(%s, %s)" % (context_arg, target_var))
5.70 + if context_verified:
5.71 + stages.append("__get_function_member(%s)" % target_var)
5.72 + else:
5.73 + stages.append("__get_function(%s, %s)" % (context_arg, target_var))
5.74 else:
5.75 stages.append("__check_and_get_function(%s, %s)" % (context_arg, target_var))
5.76
6.1 --- a/transresults.py Sat Mar 25 21:58:51 2017 +0100
6.2 +++ b/transresults.py Sat Mar 25 22:00:14 2017 +0100
6.3 @@ -178,11 +178,12 @@
6.4
6.5 "A translation result for an attribute access."
6.6
6.7 - def __init__(self, instructions, refs, location, context_identity):
6.8 + def __init__(self, instructions, refs, location, context_identity, context_identity_verified):
6.9 InstructionSequence.__init__(self, instructions)
6.10 self.refs = refs
6.11 self.location = location
6.12 self.context_identity = context_identity
6.13 + self.context_identity_verified = context_identity_verified
6.14
6.15 def references(self):
6.16 return self.refs
6.17 @@ -193,6 +194,9 @@
6.18 def context(self):
6.19 return self.context_identity
6.20
6.21 + def context_verified(self):
6.22 + return self.context_identity_verified and self.context() or None
6.23 +
6.24 def get_origin(self):
6.25 return self.refs and len(self.refs) == 1 and first(self.refs).get_origin()
6.26