# HG changeset patch # User Paul Boddie # Date 1530812174 -7200 # Node ID 3fda355ec392461351f14fc3578b117004d2ff0d # Parent 8e119abbd91c310b0697e53ddc84600af4577cb9# Parent 3b243cd23b58d6251a35e5ab633b57eb9d1c0842 Merged changes from the default branch. diff -r 8e119abbd91c -r 3fda355ec392 deducer.py --- a/deducer.py Tue Jul 03 16:02:02 2018 +0200 +++ b/deducer.py Thu Jul 05 19:36:14 2018 +0200 @@ -651,7 +651,8 @@ referenced_attrs = self.referenced_attrs[location] if not referenced_attrs: - raise DeduceError("In %s, access via %s to attribute %s (occurrence %d) cannot be identified." % location) + raise DeduceError("In %s, access via %s to attribute %s (occurrence %d) cannot be identified." % + (location.path, location.name, location.get_attrname(), location.access_number)) # Record attribute information for each name used on the # accessor. @@ -2135,6 +2136,17 @@ if constrained: self.accessor_constrained.add(location) + # Complain about situations where no types are valid but where a + # specific, known accessor type has been indicated. This absence of + # suitable types is likely to occur when the presence of invocations + # filters out the accessor type. + + if not class_only_types and not instance_types and not module_types and \ + invocations and constrained_specific: + + raise DeduceError("In %s, methods of class %s cannot be called directly." % + (path, name)) + def update_provider_types(self, location, class_types, instance_types, module_types): """ diff -r 8e119abbd91c -r 3fda355ec392 encoders.py --- a/encoders.py Tue Jul 03 16:02:02 2018 +0200 +++ b/encoders.py Thu Jul 05 19:36:14 2018 +0200 @@ -78,6 +78,13 @@ return "%s:%s:%s:%d" % (t.path, t.name or "{}", t.attrnames or "{}", t.access_number) +def decode_access_location(s): + + "Decode the access location 's'." + + path, name, attrnames, access_number = s.split(":") + return path, name, attrnames, access_number + def encode_alias_location(t, invocation=False): "Encode the alias location 't'." diff -r 8e119abbd91c -r 3fda355ec392 tests/contexts.py --- a/tests/contexts.py Tue Jul 03 16:02:02 2018 +0200 +++ b/tests/contexts.py Thu Jul 05 19:36:14 2018 +0200 @@ -5,6 +5,8 @@ self.x = x self.y = 3 self.z = "zebra libre" + def __len__(self): + return len(self.z) c = C([1]) x = c.x @@ -45,3 +47,11 @@ print b # zebra libre print i # __builtins__.str.basestring.__len__ print i() # 11 + +j = C.__len__ +k = get_using(j, c) +try: + print j() +except UnboundMethodInvocation: + print "j(): invocation of method with class context" +print k() # 11 diff -r 8e119abbd91c -r 3fda355ec392 tests/methods_unbound_bad.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/methods_unbound_bad.py Thu Jul 05 19:36:14 2018 +0200 @@ -0,0 +1,12 @@ +class C: + def __init__(self, x, y, z): + self.x = x + self.y = y + self.z = z + + def c(self): + return self.x + +c = C(1, 2, 3) +print c.c() # 1 +print C.c() # bad diff -r 8e119abbd91c -r 3fda355ec392 tools/showalias.py --- a/tools/showalias.py Tue Jul 03 16:02:02 2018 +0200 +++ b/tools/showalias.py Thu Jul 05 19:36:14 2018 +0200 @@ -1,6 +1,6 @@ #!/usr/bin/env python -from os.path import abspath, split +from os.path import abspath, exists, join, split import sys # Find the modules. @@ -15,12 +15,18 @@ from encoders import decode_alias_location if len(sys.argv) < 3: - print >>sys.stderr, "Usage: %s " % sys.argv[0] + print >>sys.stderr, "Usage: %s " % sys.argv[0] sys.exit(1) -filename = sys.argv[1] +dirname = sys.argv[1] alias = sys.argv[2] +filename = join(dirname, "_deduced", "aliases") + +if not exists(filename): + print >>sys.stderr, "Directory %s does not provide file %s." % (dirname, filename) + sys.exit(1) + f = open(filename) try: for line in f.xreadlines(): diff -r 8e119abbd91c -r 3fda355ec392 tools/showplan.py --- a/tools/showplan.py Tue Jul 03 16:02:02 2018 +0200 +++ b/tools/showplan.py Thu Jul 05 19:36:14 2018 +0200 @@ -1,14 +1,32 @@ #!/usr/bin/env python +from os.path import abspath, exists, join, split import sys +# Find the modules. + +try: + import encoders +except ImportError: + parent = abspath(split(split(__file__)[0])[0]) + if split(parent)[1] == "Lichen": + sys.path.append(parent) + +from encoders import decode_access_location + if len(sys.argv) < 3: - print >>sys.stderr, "Usage: %s " % sys.argv[0] + print >>sys.stderr, "Usage: %s " % sys.argv[0] sys.exit(1) -filename = sys.argv[1] +dirname = sys.argv[1] access = sys.argv[2] +filename = join(dirname, "_deduced", "attribute_plans") + +if not exists(filename): + print >>sys.stderr, "Directory %s does not provide file %s." % (dirname, filename) + sys.exit(1) + f = open(filename) try: for line in f.xreadlines(): @@ -17,17 +35,21 @@ continue location, name, test, test_type, base, traversed, traversal_modes, \ - attrnames, context, context_test, first_method, final_method, attr, \ - accessor_kinds = columns + traversal_attrnames, context, context_test, \ + first_method, final_method, attr, accessor_kinds = columns + + path, _name, attrnames, access_number = decode_access_location(location) print "Location:", location print "Name:", name + print "Attribute names:", attrnames + print "Access number:", access_number print "Test:", test print "Test type:", test_type print "Base:", base print "Traversed:", traversed print "Traversal modes:", traversal_modes - print "Attribute names:", attrnames + print "Traversed attributes:", traversal_attrnames print "Context:", context print "Context test:", context_test print "First method:", first_method diff -r 8e119abbd91c -r 3fda355ec392 translator.py --- a/translator.py Tue Jul 03 16:02:02 2018 +0200 +++ b/translator.py Thu Jul 05 19:36:14 2018 +0200 @@ -1403,12 +1403,14 @@ elif function: if context_required: + + # With context_verified or context_identity... + if have_access_context: - if context_verified: - emit("__get_function_member(%s)" % target_expr) - else: - emit("__get_function(%s, %s)" % ( - context_identity, target_expr)) + emit("__get_function_member(%s)" % target_expr) + + # Otherwise, test the context for the function/method. + else: emit("__get_function(__CONTEXT_AS_VALUE(%s), %s)" % ( target_var, target_expr)) @@ -1420,7 +1422,7 @@ elif known_parameters: context_arg = context_required and args[0] or "__NULL" if self.always_callable(refs): - if context_verified: + if context_verified or context_identity: emit("__get_function_member(%s)" % target_expr) else: emit("__get_function(%s, %s)" % (context_arg, target_expr))