1.1 --- a/deducer.py Tue Jul 03 16:02:02 2018 +0200
1.2 +++ b/deducer.py Thu Jul 05 19:36:14 2018 +0200
1.3 @@ -651,7 +651,8 @@
1.4 referenced_attrs = self.referenced_attrs[location]
1.5
1.6 if not referenced_attrs:
1.7 - raise DeduceError("In %s, access via %s to attribute %s (occurrence %d) cannot be identified." % location)
1.8 + raise DeduceError("In %s, access via %s to attribute %s (occurrence %d) cannot be identified." %
1.9 + (location.path, location.name, location.get_attrname(), location.access_number))
1.10
1.11 # Record attribute information for each name used on the
1.12 # accessor.
1.13 @@ -2135,6 +2136,17 @@
1.14 if constrained:
1.15 self.accessor_constrained.add(location)
1.16
1.17 + # Complain about situations where no types are valid but where a
1.18 + # specific, known accessor type has been indicated. This absence of
1.19 + # suitable types is likely to occur when the presence of invocations
1.20 + # filters out the accessor type.
1.21 +
1.22 + if not class_only_types and not instance_types and not module_types and \
1.23 + invocations and constrained_specific:
1.24 +
1.25 + raise DeduceError("In %s, methods of class %s cannot be called directly." %
1.26 + (path, name))
1.27 +
1.28 def update_provider_types(self, location, class_types, instance_types, module_types):
1.29
1.30 """
2.1 --- a/encoders.py Tue Jul 03 16:02:02 2018 +0200
2.2 +++ b/encoders.py Thu Jul 05 19:36:14 2018 +0200
2.3 @@ -78,6 +78,13 @@
2.4
2.5 return "%s:%s:%s:%d" % (t.path, t.name or "{}", t.attrnames or "{}", t.access_number)
2.6
2.7 +def decode_access_location(s):
2.8 +
2.9 + "Decode the access location 's'."
2.10 +
2.11 + path, name, attrnames, access_number = s.split(":")
2.12 + return path, name, attrnames, access_number
2.13 +
2.14 def encode_alias_location(t, invocation=False):
2.15
2.16 "Encode the alias location 't'."
3.1 --- a/tests/contexts.py Tue Jul 03 16:02:02 2018 +0200
3.2 +++ b/tests/contexts.py Thu Jul 05 19:36:14 2018 +0200
3.3 @@ -5,6 +5,8 @@
3.4 self.x = x
3.5 self.y = 3
3.6 self.z = "zebra libre"
3.7 + def __len__(self):
3.8 + return len(self.z)
3.9
3.10 c = C([1])
3.11 x = c.x
3.12 @@ -45,3 +47,11 @@
3.13 print b # zebra libre
3.14 print i # __builtins__.str.basestring.__len__
3.15 print i() # 11
3.16 +
3.17 +j = C.__len__
3.18 +k = get_using(j, c)
3.19 +try:
3.20 + print j()
3.21 +except UnboundMethodInvocation:
3.22 + print "j(): invocation of method with class context"
3.23 +print k() # 11
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/tests/methods_unbound_bad.py Thu Jul 05 19:36:14 2018 +0200
4.3 @@ -0,0 +1,12 @@
4.4 +class C:
4.5 + def __init__(self, x, y, z):
4.6 + self.x = x
4.7 + self.y = y
4.8 + self.z = z
4.9 +
4.10 + def c(self):
4.11 + return self.x
4.12 +
4.13 +c = C(1, 2, 3)
4.14 +print c.c() # 1
4.15 +print C.c() # bad
5.1 --- a/tools/showalias.py Tue Jul 03 16:02:02 2018 +0200
5.2 +++ b/tools/showalias.py Thu Jul 05 19:36:14 2018 +0200
5.3 @@ -1,6 +1,6 @@
5.4 #!/usr/bin/env python
5.5
5.6 -from os.path import abspath, split
5.7 +from os.path import abspath, exists, join, split
5.8 import sys
5.9
5.10 # Find the modules.
5.11 @@ -15,12 +15,18 @@
5.12 from encoders import decode_alias_location
5.13
5.14 if len(sys.argv) < 3:
5.15 - print >>sys.stderr, "Usage: %s <filename> <alias>" % sys.argv[0]
5.16 + print >>sys.stderr, "Usage: %s <directory> <alias>" % sys.argv[0]
5.17 sys.exit(1)
5.18
5.19 -filename = sys.argv[1]
5.20 +dirname = sys.argv[1]
5.21 alias = sys.argv[2]
5.22
5.23 +filename = join(dirname, "_deduced", "aliases")
5.24 +
5.25 +if not exists(filename):
5.26 + print >>sys.stderr, "Directory %s does not provide file %s." % (dirname, filename)
5.27 + sys.exit(1)
5.28 +
5.29 f = open(filename)
5.30 try:
5.31 for line in f.xreadlines():
6.1 --- a/tools/showplan.py Tue Jul 03 16:02:02 2018 +0200
6.2 +++ b/tools/showplan.py Thu Jul 05 19:36:14 2018 +0200
6.3 @@ -1,14 +1,32 @@
6.4 #!/usr/bin/env python
6.5
6.6 +from os.path import abspath, exists, join, split
6.7 import sys
6.8
6.9 +# Find the modules.
6.10 +
6.11 +try:
6.12 + import encoders
6.13 +except ImportError:
6.14 + parent = abspath(split(split(__file__)[0])[0])
6.15 + if split(parent)[1] == "Lichen":
6.16 + sys.path.append(parent)
6.17 +
6.18 +from encoders import decode_access_location
6.19 +
6.20 if len(sys.argv) < 3:
6.21 - print >>sys.stderr, "Usage: %s <filename> <access>" % sys.argv[0]
6.22 + print >>sys.stderr, "Usage: %s <directory> <access>" % sys.argv[0]
6.23 sys.exit(1)
6.24
6.25 -filename = sys.argv[1]
6.26 +dirname = sys.argv[1]
6.27 access = sys.argv[2]
6.28
6.29 +filename = join(dirname, "_deduced", "attribute_plans")
6.30 +
6.31 +if not exists(filename):
6.32 + print >>sys.stderr, "Directory %s does not provide file %s." % (dirname, filename)
6.33 + sys.exit(1)
6.34 +
6.35 f = open(filename)
6.36 try:
6.37 for line in f.xreadlines():
6.38 @@ -17,17 +35,21 @@
6.39 continue
6.40
6.41 location, name, test, test_type, base, traversed, traversal_modes, \
6.42 - attrnames, context, context_test, first_method, final_method, attr, \
6.43 - accessor_kinds = columns
6.44 + traversal_attrnames, context, context_test, \
6.45 + first_method, final_method, attr, accessor_kinds = columns
6.46 +
6.47 + path, _name, attrnames, access_number = decode_access_location(location)
6.48
6.49 print "Location:", location
6.50 print "Name:", name
6.51 + print "Attribute names:", attrnames
6.52 + print "Access number:", access_number
6.53 print "Test:", test
6.54 print "Test type:", test_type
6.55 print "Base:", base
6.56 print "Traversed:", traversed
6.57 print "Traversal modes:", traversal_modes
6.58 - print "Attribute names:", attrnames
6.59 + print "Traversed attributes:", traversal_attrnames
6.60 print "Context:", context
6.61 print "Context test:", context_test
6.62 print "First method:", first_method
7.1 --- a/translator.py Tue Jul 03 16:02:02 2018 +0200
7.2 +++ b/translator.py Thu Jul 05 19:36:14 2018 +0200
7.3 @@ -1403,12 +1403,14 @@
7.4
7.5 elif function:
7.6 if context_required:
7.7 +
7.8 + # With context_verified or context_identity...
7.9 +
7.10 if have_access_context:
7.11 - if context_verified:
7.12 - emit("__get_function_member(%s)" % target_expr)
7.13 - else:
7.14 - emit("__get_function(%s, %s)" % (
7.15 - context_identity, target_expr))
7.16 + emit("__get_function_member(%s)" % target_expr)
7.17 +
7.18 + # Otherwise, test the context for the function/method.
7.19 +
7.20 else:
7.21 emit("__get_function(__CONTEXT_AS_VALUE(%s), %s)" % (
7.22 target_var, target_expr))
7.23 @@ -1420,7 +1422,7 @@
7.24 elif known_parameters:
7.25 context_arg = context_required and args[0] or "__NULL"
7.26 if self.always_callable(refs):
7.27 - if context_verified:
7.28 + if context_verified or context_identity:
7.29 emit("__get_function_member(%s)" % target_expr)
7.30 else:
7.31 emit("__get_function(%s, %s)" % (context_arg, target_expr))