# HG changeset patch # User Paul Boddie # Date 1475183486 -7200 # Node ID 701a83e828a06486220a186e52e38b51b7d778d5 # Parent 263bb3a6e288c058de68ccd333c5831e9bb092e7 Record assignment accesses to produce appropriate operations in the plan. diff -r 263bb3a6e288 -r 701a83e828a0 deducer.py --- a/deducer.py Thu Sep 29 19:25:48 2016 +0200 +++ b/deducer.py Thu Sep 29 23:11:26 2016 +0200 @@ -25,6 +25,7 @@ from encoders import encode_attrnames, encode_access_location, \ encode_constrained, encode_location, encode_usage, \ get_kinds, test_for_kinds, test_for_type +from errors import DeduceError from os.path import join from referencing import combine_types, is_single_class_type, separate_types, \ Reference @@ -81,6 +82,10 @@ self.modified_attributes = {} + # Accesses that are assignments. + + self.reference_assignments = set() + # Map locations to types, constrained indicators and attributes. self.accessor_class_types = {} @@ -520,97 +525,98 @@ referenced_attrs = self.referenced_attrs[location] - if referenced_attrs: - - # Record attribute information for each name used on the - # accessor. - - attrname = get_attrname_from_location(location) - - all_accessed_attrs = set() - all_providers = set() - - # Obtain provider and attribute details for this kind of - # object. - - for attrtype, object_type, attr in referenced_attrs: - all_accessed_attrs.add(attr) - all_providers.add(object_type) - - all_general_providers = self.get_most_general_types(all_providers) - - # Determine which attributes would be provided by the - # accessor types upheld by a guard. - - if guarded: - guard_attrs = set() - for _attrtype, object_type, attr in \ - self._identify_reference_attribute(attrname, guard_class_types, guard_instance_types, guard_module_types): - guard_attrs.add(attr) + if not referenced_attrs: + raise DeduceError, location + + # Record attribute information for each name used on the + # accessor. + + attrname = get_attrname_from_location(location) + + all_accessed_attrs = set() + all_providers = set() + + # Obtain provider and attribute details for this kind of + # object. + + for attrtype, object_type, attr in referenced_attrs: + all_accessed_attrs.add(attr) + all_providers.add(object_type) + + all_general_providers = self.get_most_general_types(all_providers) + + # Determine which attributes would be provided by the + # accessor types upheld by a guard. + + if guarded: + guard_attrs = set() + for _attrtype, object_type, attr in \ + self._identify_reference_attribute(attrname, guard_class_types, guard_instance_types, guard_module_types): + guard_attrs.add(attr) + else: + guard_attrs = None + + self.reference_all_attrs[location] = all_accessed_attrs + + # Constrained accesses guarantee the nature of the accessor. + # However, there may still be many types involved. + + if constrained: + if single_accessor_type: + self.reference_test_types[location] = test_for_type("constrained-specific", first(all_accessor_types)) + elif single_accessor_class_type: + self.reference_test_types[location] = "constrained-specific-object" + elif single_accessor_general_type: + self.reference_test_types[location] = test_for_type("constrained-common", first(all_accessor_general_types)) + elif single_accessor_general_class_type: + self.reference_test_types[location] = "constrained-common-object" else: - guard_attrs = None - - self.reference_all_attrs[location] = all_accessed_attrs - - # Constrained accesses guarantee the nature of the accessor. - # However, there may still be many types involved. - - if constrained: - if single_accessor_type: - self.reference_test_types[location] = test_for_type("constrained-specific", first(all_accessor_types)) - elif single_accessor_class_type: - self.reference_test_types[location] = "constrained-specific-object" - elif single_accessor_general_type: - self.reference_test_types[location] = test_for_type("constrained-common", first(all_accessor_general_types)) - elif single_accessor_general_class_type: - self.reference_test_types[location] = "constrained-common-object" + self.reference_test_types[location] = "constrained-many" + + # Suitably guarded accesses, where the nature of the + # accessor can be guaranteed, do not require the attribute + # involved to be validated. Otherwise, for unguarded + # accesses, access-level tests are required. + + elif guarded and all_accessed_attrs.issubset(guard_attrs): + if single_accessor_type: + self.reference_test_types[location] = test_for_type("guarded-specific", first(all_accessor_types)) + elif single_accessor_class_type: + self.reference_test_types[location] = "guarded-specific-object" + elif single_accessor_general_type: + self.reference_test_types[location] = test_for_type("guarded-common", first(all_accessor_general_types)) + elif single_accessor_general_class_type: + self.reference_test_types[location] = "guarded-common-object" + + # Record the need to test the type of anonymous and + # unconstrained accessors. + + elif len(all_providers) == 1: + provider = first(all_providers) + if provider != '__builtins__.object': + all_accessor_kinds = set(get_kinds(all_accessor_types)) + if len(all_accessor_kinds) == 1: + test_type = test_for_kinds("specific", all_accessor_kinds) else: - self.reference_test_types[location] = "constrained-many" - - # Suitably guarded accesses, where the nature of the - # accessor can be guaranteed, do not require the attribute - # involved to be validated. Otherwise, for unguarded - # accesses, access-level tests are required. - - elif guarded and all_accessed_attrs.issubset(guard_attrs): - if single_accessor_type: - self.reference_test_types[location] = test_for_type("guarded-specific", first(all_accessor_types)) - elif single_accessor_class_type: - self.reference_test_types[location] = "guarded-specific-object" - elif single_accessor_general_type: - self.reference_test_types[location] = test_for_type("guarded-common", first(all_accessor_general_types)) - elif single_accessor_general_class_type: - self.reference_test_types[location] = "guarded-common-object" - - # Record the need to test the type of anonymous and - # unconstrained accessors. - - elif len(all_providers) == 1: - provider = first(all_providers) - if provider != '__builtins__.object': - all_accessor_kinds = set(get_kinds(all_accessor_types)) - if len(all_accessor_kinds) == 1: - test_type = test_for_kinds("specific", all_accessor_kinds) - else: - test_type = "specific-object" - self.reference_test_types[location] = test_type - self.reference_test_accessor_types[location] = provider - - elif len(all_general_providers) == 1: - provider = first(all_general_providers) - if provider != '__builtins__.object': - all_accessor_kinds = set(get_kinds(all_accessor_general_types)) - if len(all_accessor_kinds) == 1: - test_type = test_for_kinds("common", all_accessor_kinds) - else: - test_type = "common-object" - self.reference_test_types[location] = test_type - self.reference_test_accessor_types[location] = provider - - # Record the need to test the identity of the attribute. - - else: - self.reference_test_types[location] = "validate" + test_type = "specific-object" + self.reference_test_types[location] = test_type + self.reference_test_accessor_types[location] = provider + + elif len(all_general_providers) == 1: + provider = first(all_general_providers) + if provider != '__builtins__.object': + all_accessor_kinds = set(get_kinds(all_accessor_general_types)) + if len(all_accessor_kinds) == 1: + test_type = test_for_kinds("common", all_accessor_kinds) + else: + test_type = "common-object" + self.reference_test_types[location] = test_type + self.reference_test_accessor_types[location] = provider + + # Record the need to test the identity of the attribute. + + else: + self.reference_test_types[location] = "validate" def initialise_access_plans(self): @@ -784,6 +790,9 @@ else: access_location = (path, None, attrnames, 0) + if assignment: + self.reference_assignments.add(access_location) + # Associate assignments with usage. accessor_locations = self.get_accessors_for_access(access_location) @@ -1838,16 +1847,16 @@ # Determine the method of access. + # Identified attribute that must be accessed via its parent. + + if attr and attr.get_name() and (not attr.static() or location in self.reference_assignments): + method = "direct"; origin = attr.get_name() + # Static, identified attribute. - if attr and attr.static(): + elif attr and attr.static(): method = "static"; origin = attr.final() - # Identified attribute that must be accessed via its parent. - - elif attr and attr.get_name(): - method = "direct"; origin = attr.get_name() - # Attribute accessed at a known position via its parent. elif base or dynamic_base: diff -r 263bb3a6e288 -r 701a83e828a0 errors.py --- a/errors.py Thu Sep 29 19:25:48 2016 +0200 +++ b/errors.py Thu Sep 29 23:11:26 2016 +0200 @@ -78,6 +78,12 @@ pass +class DeduceError(NodeProcessingError): + + "An error during the deduction process." + + pass + class TranslateError(NodeProcessingError): "An error during the module translation process." diff -r 263bb3a6e288 -r 701a83e828a0 tests/chain.py --- a/tests/chain.py Thu Sep 29 19:25:48 2016 +0200 +++ b/tests/chain.py Thu Sep 29 23:11:26 2016 +0200 @@ -9,6 +9,7 @@ n = 123 o = "123" p = "456" + q = 789 def main(): c = C @@ -18,6 +19,7 @@ g = C.D.E.n h = C.D.p i = C.D.p.__len__ + C.D.q = 987 inst = e() method = inst.m return method("5") @@ -30,6 +32,7 @@ g = C.D.E.n h = C.D.p i = C.D.p.__len__ +C.D.q = 987 inst = e() method = inst.m result2 = method("5")