Lichen

Changeset

722:6a2e6400b252
2017-03-13 Paul Boddie raw files shortlog changelog graph Merged changes from the default branch. return-value-definition
deducer.py (file) inspector.py (file) resolving.py (file)
     1.1 --- a/deducer.py	Sun Mar 12 21:41:50 2017 +0100
     1.2 +++ b/deducer.py	Mon Mar 13 01:53:43 2017 +0100
     1.3 @@ -903,9 +903,11 @@
     1.4                          access_location = (path, None, attrname_str, 0)
     1.5  
     1.6                      # Plain name accesses do not employ attributes and are
     1.7 -                    # ignored.
     1.8 +                    # ignored. Whether they are invoked is of interest, however.
     1.9  
    1.10                      if not attrname_str:
    1.11 +                        if invocation:
    1.12 +                            self.reference_invocations[access_location] = invocation
    1.13                          continue
    1.14  
    1.15                      attrnames = get_attrnames(attrname_str)
    1.16 @@ -1518,6 +1520,9 @@
    1.17          if not attrname:
    1.18              return
    1.19  
    1.20 +        invocation = access_location in self.reference_invocations
    1.21 +        assignment = access_location in self.reference_assignments
    1.22 +
    1.23          # Collect all suggested types for the accessors. Accesses may
    1.24          # require accessors from of a subset of the complete set of types.
    1.25  
    1.26 @@ -1547,7 +1552,7 @@
    1.27  
    1.28              else:
    1.29                  self.init_definition_details(location)
    1.30 -                self.record_types_for_usage(location, [(attrname, False, False)])
    1.31 +                self.record_types_for_usage(location, [(attrname, invocation, assignment)])
    1.32  
    1.33              constrained = location in self.accessor_constrained and constrained
    1.34  
    1.35 @@ -1618,11 +1623,19 @@
    1.36              provider_instance_types = self.provider_instance_types[accessor_location]
    1.37              provider_module_types = self.provider_module_types[accessor_location]
    1.38  
    1.39 +            accessor_class_types = self.accessor_class_types[accessor_location]
    1.40 +            accessor_instance_types = self.accessor_instance_types[accessor_location]
    1.41 +            accessor_module_types = self.accessor_module_types[accessor_location]
    1.42 +
    1.43              # Find details for any corresponding access.
    1.44  
    1.45 -            all_class_types = set()
    1.46 -            all_instance_types = set()
    1.47 -            all_module_types = set()
    1.48 +            new_provider_class_types = set()
    1.49 +            new_provider_instance_types = set()
    1.50 +            new_provider_module_types = set()
    1.51 +
    1.52 +            new_accessor_class_types = set()
    1.53 +            new_accessor_instance_types = set()
    1.54 +            new_accessor_module_types = set()
    1.55  
    1.56              for access_location in self.alias_index[accessor_location]:
    1.57                  location, name, attrnames, access_number = access_location
    1.58 @@ -1645,10 +1658,20 @@
    1.59                      # Obtain references and attribute types for the access.
    1.60  
    1.61                      attrs = self.get_references_for_access(access_location)
    1.62 -                    attrs = self.convert_invocation_providers(attrs, invocation)
    1.63 +
    1.64 +                    # Where no specific attributes are defined, do not attempt
    1.65 +                    # to refine the alias's types.
    1.66 +
    1.67 +                    if not attrs:
    1.68 +                        return
    1.69 +
    1.70 +                    # Invocations converting class accessors to instances do not
    1.71 +                    # change the nature of class providers.
    1.72 +
    1.73 +                    provider_attrs = self.convert_invocation_providers(attrs, invocation)
    1.74  
    1.75                      (class_types, instance_types, module_types, function_types,
    1.76 -                        var_types) = separate_types(attrs)
    1.77 +                        var_types) = separate_types(provider_attrs)
    1.78  
    1.79                      # Where non-accessor types are found, do not attempt to refine
    1.80                      # the defined accessor types.
    1.81 @@ -1656,13 +1679,30 @@
    1.82                      if function_types or var_types:
    1.83                          return
    1.84  
    1.85 -                    # Invocations converting class accessors to instances do not
    1.86 -                    # change the nature of class providers.
    1.87 -
    1.88                      class_types = set(provider_class_types).intersection(class_types)
    1.89                      instance_types = set(provider_instance_types).intersection(instance_types)
    1.90                      module_types = set(provider_module_types).intersection(module_types)
    1.91  
    1.92 +                    new_provider_class_types.update(class_types)
    1.93 +                    new_provider_instance_types.update(instance_types)
    1.94 +                    new_provider_module_types.update(module_types)
    1.95 +
    1.96 +                    # Accessors are updated separately, employing invocation
    1.97 +                    # result details.
    1.98 +
    1.99 +                    accessor_attrs = self.convert_invocations(attrs, invocation)
   1.100 +
   1.101 +                    (class_types, instance_types, module_types, function_types,
   1.102 +                        var_types) = separate_types(accessor_attrs)
   1.103 +
   1.104 +                    class_types = set(accessor_class_types).intersection(class_types)
   1.105 +                    instance_types = set(accessor_instance_types).intersection(instance_types)
   1.106 +                    module_types = set(accessor_module_types).intersection(module_types)
   1.107 +
   1.108 +                    new_accessor_class_types.update(class_types)
   1.109 +                    new_accessor_instance_types.update(instance_types)
   1.110 +                    new_accessor_module_types.update(module_types)
   1.111 +
   1.112                  # Alias references a name, not an access.
   1.113  
   1.114                  else:
   1.115 @@ -1670,10 +1710,32 @@
   1.116  
   1.117                      attr = self.get_initialised_name(access_location)
   1.118                      if attr:
   1.119 -                        attrs = self.convert_invocation_providers([attr], invocation)
   1.120 +                        attrs = [attr]
   1.121 +                        provider_attrs = self.convert_invocation_providers(attrs, invocation)
   1.122  
   1.123                          (class_types, instance_types, module_types, function_types,
   1.124 -                            var_types) = separate_types(attrs)
   1.125 +                            var_types) = separate_types(provider_attrs)
   1.126 +
   1.127 +                        class_types = set(provider_class_types).intersection(class_types)
   1.128 +                        instance_types = set(provider_instance_types).intersection(instance_types)
   1.129 +                        module_types = set(provider_module_types).intersection(module_types)
   1.130 +
   1.131 +                        new_provider_class_types.update(class_types)
   1.132 +                        new_provider_instance_types.update(instance_types)
   1.133 +                        new_provider_module_types.update(module_types)
   1.134 +
   1.135 +                        accessor_attrs = self.convert_invocations(attrs, invocation)
   1.136 +
   1.137 +                        (class_types, instance_types, module_types, function_types,
   1.138 +                            var_types) = separate_types(accessor_attrs)
   1.139 +
   1.140 +                        class_types = set(accessor_class_types).intersection(class_types)
   1.141 +                        instance_types = set(accessor_instance_types).intersection(instance_types)
   1.142 +                        module_types = set(accessor_module_types).intersection(module_types)
   1.143 +
   1.144 +                        new_accessor_class_types.update(class_types)
   1.145 +                        new_accessor_instance_types.update(instance_types)
   1.146 +                        new_accessor_module_types.update(module_types)
   1.147  
   1.148                      # Where no further information is found, do not attempt to
   1.149                      # refine the defined accessor types.
   1.150 @@ -1681,14 +1743,11 @@
   1.151                      else:
   1.152                          return
   1.153  
   1.154 -                all_class_types.update(class_types)
   1.155 -                all_instance_types.update(instance_types)
   1.156 -                all_module_types.update(module_types)
   1.157 -
   1.158              # Record refined type details for the alias as an accessor.
   1.159  
   1.160              self.init_definition_details(accessor_location)
   1.161 -            self.record_reference_types(accessor_location, all_class_types, all_instance_types, all_module_types, False)
   1.162 +            self.update_provider_types(accessor_location, new_provider_class_types, new_provider_instance_types, new_provider_module_types)
   1.163 +            self.update_accessor_types(accessor_location, new_accessor_class_types, new_accessor_instance_types, new_accessor_module_types)
   1.164  
   1.165          # Without an access, attempt to identify references for the alias.
   1.166          # Invocations convert classes to instances and also attempt to find
   1.167 @@ -1719,9 +1778,7 @@
   1.168  
   1.169                  # Alias references an attribute access.
   1.170  
   1.171 -                attrname = attrnames and attrnames[0]
   1.172 -
   1.173 -                if attrname:
   1.174 +                if attrnames:
   1.175  
   1.176                      # Obtain references and attribute types for the access.
   1.177  
   1.178 @@ -1746,7 +1803,8 @@
   1.179                          instance_types = self.provider_instance_types[access_location]
   1.180                          module_types = self.provider_module_types[access_location]
   1.181  
   1.182 -                        refs.update(combine_types(class_types, instance_types, module_types))
   1.183 +                        types = combine_types(class_types, instance_types, module_types)
   1.184 +                        refs.update(self.convert_invocation_providers(types, invocation))
   1.185  
   1.186              # Record reference details for the alias separately from accessors.
   1.187  
   1.188 @@ -1863,15 +1921,13 @@
   1.189  
   1.190          # Update the type details for the location.
   1.191  
   1.192 -        self.provider_class_types[location].update(class_types)
   1.193 -        self.provider_instance_types[location].update(instance_types)
   1.194 -        self.provider_module_types[location].update(module_types)
   1.195 +        self.update_provider_types(location, class_types, instance_types, module_types)
   1.196  
   1.197          # Class types support classes and instances as accessors.
   1.198          # Instance-only and module types support only their own kinds as
   1.199          # accessors.
   1.200  
   1.201 -        path, name, version, attrnames = location
   1.202 +        path, name, attrnames, version = location
   1.203  
   1.204          if invocations:
   1.205              class_only_types = self.filter_for_invocations(class_types, invocations)
   1.206 @@ -1895,6 +1951,28 @@
   1.207          if constrained:
   1.208              self.accessor_constrained.add(location)
   1.209  
   1.210 +    def update_provider_types(self, location, class_types, instance_types, module_types):
   1.211 +
   1.212 +        """
   1.213 +        Update provider types for the given 'location', adding 'class_types',
   1.214 +        'instance_types' and 'module_types' to those already stored.
   1.215 +        """
   1.216 +
   1.217 +        self.provider_class_types[location].update(class_types)
   1.218 +        self.provider_instance_types[location].update(instance_types)
   1.219 +        self.provider_module_types[location].update(module_types)
   1.220 +
   1.221 +    def update_accessor_types(self, location, class_types, instance_types, module_types):
   1.222 +
   1.223 +        """
   1.224 +        Update accessor types for the given 'location', adding 'class_types',
   1.225 +        'instance_types' and 'module_types' to those already stored.
   1.226 +        """
   1.227 +
   1.228 +        self.accessor_class_types[location].update(class_types)
   1.229 +        self.accessor_instance_types[location].update(instance_types)
   1.230 +        self.accessor_module_types[location].update(module_types)
   1.231 +
   1.232      def filter_for_invocations(self, class_types, attrnames):
   1.233  
   1.234          """
     2.1 --- a/inspector.py	Sun Mar 12 21:41:50 2017 +0100
     2.2 +++ b/inspector.py	Mon Mar 13 01:53:43 2017 +0100
     2.3 @@ -909,7 +909,8 @@
     2.4          branches = self.trackers[-1].tracking_name(name)
     2.5          if branches:
     2.6              self.record_branches_for_access(branches, name, None)
     2.7 -            return self.record_access_details(name, None, None, None)
     2.8 +            return self.record_access_details(name, None, self.in_assignment,
     2.9 +                                              self.in_invocation)
    2.10          return None
    2.11  
    2.12      def process_operator_chain(self, nodes, fn):
     4.1 --- a/translator.py	Sun Mar 12 21:41:50 2017 +0100
     4.2 +++ b/translator.py	Mon Mar 13 01:53:43 2017 +0100
     4.3 @@ -866,9 +866,9 @@
     4.4  
     4.5              parameters = self.importer.function_parameters.get(self.get_namespace_path())
     4.6              if parameters and name in parameters:
     4.7 -                name_to_value = "%s->value" % name
     4.8 +                name_to_value = "%s->value" % encode_path(name)
     4.9              else:
    4.10 -                name_to_value = "%s.value" % name
    4.11 +                name_to_value = "%s.value" % encode_path(name)
    4.12  
    4.13              # Write a test that raises a TypeError upon failure.
    4.14