# HG changeset patch # User Paul Boddie # Date 1489366151 -3600 # Node ID 823020deac339cf696c6ace4d95561a7e3a3141b # Parent d760a72fbd2e6967c19fc303ac4e68239091ddd1 Define both accessor and provider details for aliases based on access details. diff -r d760a72fbd2e -r 823020deac33 deducer.py --- a/deducer.py Mon Mar 13 01:46:58 2017 +0100 +++ b/deducer.py Mon Mar 13 01:49:11 2017 +0100 @@ -1623,11 +1623,19 @@ provider_instance_types = self.provider_instance_types[accessor_location] provider_module_types = self.provider_module_types[accessor_location] + accessor_class_types = self.accessor_class_types[accessor_location] + accessor_instance_types = self.accessor_instance_types[accessor_location] + accessor_module_types = self.accessor_module_types[accessor_location] + # Find details for any corresponding access. - all_class_types = set() - all_instance_types = set() - all_module_types = set() + new_provider_class_types = set() + new_provider_instance_types = set() + new_provider_module_types = set() + + new_accessor_class_types = set() + new_accessor_instance_types = set() + new_accessor_module_types = set() for access_location in self.alias_index[accessor_location]: location, name, attrnames, access_number = access_location @@ -1650,10 +1658,20 @@ # Obtain references and attribute types for the access. attrs = self.get_references_for_access(access_location) - attrs = self.convert_invocation_providers(attrs, invocation) + + # Where no specific attributes are defined, do not attempt + # to refine the alias's types. + + if not attrs: + return + + # Invocations converting class accessors to instances do not + # change the nature of class providers. + + provider_attrs = self.convert_invocation_providers(attrs, invocation) (class_types, instance_types, module_types, function_types, - var_types) = separate_types(attrs) + var_types) = separate_types(provider_attrs) # Where non-accessor types are found, do not attempt to refine # the defined accessor types. @@ -1661,13 +1679,30 @@ if function_types or var_types: return - # Invocations converting class accessors to instances do not - # change the nature of class providers. - class_types = set(provider_class_types).intersection(class_types) instance_types = set(provider_instance_types).intersection(instance_types) module_types = set(provider_module_types).intersection(module_types) + new_provider_class_types.update(class_types) + new_provider_instance_types.update(instance_types) + new_provider_module_types.update(module_types) + + # Accessors are updated separately, employing invocation + # result details. + + accessor_attrs = self.convert_invocations(attrs, invocation) + + (class_types, instance_types, module_types, function_types, + var_types) = separate_types(accessor_attrs) + + class_types = set(accessor_class_types).intersection(class_types) + instance_types = set(accessor_instance_types).intersection(instance_types) + module_types = set(accessor_module_types).intersection(module_types) + + new_accessor_class_types.update(class_types) + new_accessor_instance_types.update(instance_types) + new_accessor_module_types.update(module_types) + # Alias references a name, not an access. else: @@ -1675,10 +1710,32 @@ attr = self.get_initialised_name(access_location) if attr: - attrs = self.convert_invocation_providers([attr], invocation) + attrs = [attr] + provider_attrs = self.convert_invocation_providers(attrs, invocation) (class_types, instance_types, module_types, function_types, - var_types) = separate_types(attrs) + var_types) = separate_types(provider_attrs) + + class_types = set(provider_class_types).intersection(class_types) + instance_types = set(provider_instance_types).intersection(instance_types) + module_types = set(provider_module_types).intersection(module_types) + + new_provider_class_types.update(class_types) + new_provider_instance_types.update(instance_types) + new_provider_module_types.update(module_types) + + accessor_attrs = self.convert_invocations(attrs, invocation) + + (class_types, instance_types, module_types, function_types, + var_types) = separate_types(accessor_attrs) + + class_types = set(accessor_class_types).intersection(class_types) + instance_types = set(accessor_instance_types).intersection(instance_types) + module_types = set(accessor_module_types).intersection(module_types) + + new_accessor_class_types.update(class_types) + new_accessor_instance_types.update(instance_types) + new_accessor_module_types.update(module_types) # Where no further information is found, do not attempt to # refine the defined accessor types. @@ -1686,14 +1743,11 @@ else: return - all_class_types.update(class_types) - all_instance_types.update(instance_types) - all_module_types.update(module_types) - # Record refined type details for the alias as an accessor. self.init_definition_details(accessor_location) - self.record_reference_types(accessor_location, all_class_types, all_instance_types, all_module_types, False) + self.update_provider_types(accessor_location, new_provider_class_types, new_provider_instance_types, new_provider_module_types) + self.update_accessor_types(accessor_location, new_accessor_class_types, new_accessor_instance_types, new_accessor_module_types) # Without an access, attempt to identify references for the alias. # Invocations convert classes to instances and also attempt to find @@ -1724,9 +1778,7 @@ # Alias references an attribute access. - attrname = attrnames and attrnames[0] - - if attrname: + if attrnames: # Obtain references and attribute types for the access. @@ -1751,7 +1803,8 @@ instance_types = self.provider_instance_types[access_location] module_types = self.provider_module_types[access_location] - refs.update(combine_types(class_types, instance_types, module_types)) + types = combine_types(class_types, instance_types, module_types) + refs.update(self.convert_invocation_providers(types, invocation)) # Record reference details for the alias separately from accessors. @@ -1858,15 +1911,13 @@ # Update the type details for the location. - self.provider_class_types[location].update(class_types) - self.provider_instance_types[location].update(instance_types) - self.provider_module_types[location].update(module_types) + self.update_provider_types(location, class_types, instance_types, module_types) # Class types support classes and instances as accessors. # Instance-only and module types support only their own kinds as # accessors. - path, name, version, attrnames = location + path, name, attrnames, version = location if invocations: class_only_types = self.filter_for_invocations(class_types, invocations) @@ -1890,6 +1941,28 @@ if constrained: self.accessor_constrained.add(location) + def update_provider_types(self, location, class_types, instance_types, module_types): + + """ + Update provider types for the given 'location', adding 'class_types', + 'instance_types' and 'module_types' to those already stored. + """ + + self.provider_class_types[location].update(class_types) + self.provider_instance_types[location].update(instance_types) + self.provider_module_types[location].update(module_types) + + def update_accessor_types(self, location, class_types, instance_types, module_types): + + """ + Update accessor types for the given 'location', adding 'class_types', + 'instance_types' and 'module_types' to those already stored. + """ + + self.accessor_class_types[location].update(class_types) + self.accessor_instance_types[location].update(instance_types) + self.accessor_module_types[location].update(module_types) + def filter_for_invocations(self, class_types, attrnames): """