1.1 --- a/tests/methods_unbound.py Fri Nov 25 18:36:45 2016 +0100
1.2 +++ b/tests/methods_unbound.py Fri Nov 25 19:20:37 2016 +0100
1.3 @@ -4,6 +4,15 @@
1.4 def m(self, x):
1.5 return x
1.6
1.7 +class D:
1.8 + pass
1.9 +
1.10 +def getc():
1.11 + return C()
1.12 +
1.13 +def getd():
1.14 + return D()
1.15 +
1.16 def f(obj, i):
1.17 if i:
1.18 return obj.m(i) # should cause access to an unbound method
1.19 @@ -17,6 +26,14 @@
1.20 else:
1.21 return obj.m
1.22
1.23 +def h(obj, fn):
1.24 + if fn:
1.25 + obj = fn()
1.26 + obj.a # only provided by instances of C
1.27 + return obj.m(1)
1.28 + else:
1.29 + return obj.m
1.30 +
1.31 c = C()
1.32
1.33 try:
1.34 @@ -41,3 +58,11 @@
1.35
1.36 print g(c, 1) # 1
1.37 print g(c, 0)(3) # 3
1.38 +
1.39 +print h(c, getc) # 1
1.40 +print h(c, 0)(4) # 4
1.41 +
1.42 +try:
1.43 + print h(c, getd) # should fail with an error caused by a guard
1.44 +except TypeError:
1.45 + print "h(c, getd): getd provides an unsuitable result."
2.1 --- a/translator.py Fri Nov 25 18:36:45 2016 +0100
2.2 +++ b/translator.py Fri Nov 25 19:20:37 2016 +0100
2.3 @@ -587,6 +587,11 @@
2.4 name_ref = self.process_name_node(n, self.process_structure_node(expr))
2.5 self.statement(name_ref)
2.6
2.7 + # Employ guards after assignments if required.
2.8 +
2.9 + if expr and name_ref.is_name():
2.10 + self.generate_guard(name_ref.name)
2.11 +
2.12 elif isinstance(n, compiler.ast.AssAttr):
2.13 in_assignment = self.in_assignment
2.14 self.in_assignment = self.process_structure_node(expr)
2.15 @@ -772,28 +777,7 @@
2.16 # Process any guards defined for the parameters.
2.17
2.18 for name in self.importer.function_parameters.get(function_name):
2.19 -
2.20 - # Get the accessor details and any guards defined for it.
2.21 -
2.22 - location = self.get_accessor_location(name)
2.23 - test = self.deducer.accessor_guard_tests.get(location)
2.24 - if test:
2.25 - guard, guard_type = test
2.26 -
2.27 - if guard == "specific":
2.28 - ref = first(self.deducer.accessor_all_types[location])
2.29 - argstr = "&%s" % encode_path(ref.get_origin())
2.30 - elif guard == "common":
2.31 - ref = first(self.deducer.accessor_all_general_types[location])
2.32 - typeattr = encode_type_attribute(ref.get_origin())
2.33 - argstr = "%s, %s" % (encode_symbol("pos", typeattr), encode_symbol("code", typeattr))
2.34 - else:
2.35 - continue
2.36 -
2.37 - # Write a test that raises a TypeError upon failure.
2.38 -
2.39 - self.writestmt("if (!__test_%s_%s(%s->value, %s)) __raise_type_error();" % (
2.40 - guard, guard_type, name, argstr))
2.41 + self.generate_guard(name)
2.42
2.43 # Produce the body and any additional return statement.
2.44
2.45 @@ -805,6 +789,38 @@
2.46
2.47 self.end_function(function_name)
2.48
2.49 + def generate_guard(self, name):
2.50 +
2.51 + """
2.52 + Get the accessor details for 'name', found in the current namespace, and
2.53 + generate any guards defined for it.
2.54 + """
2.55 +
2.56 + # Obtain the location, keeping track of assignment versions.
2.57 +
2.58 + location = self.get_accessor_location(name)
2.59 + test = self.deducer.accessor_guard_tests.get(location)
2.60 +
2.61 + # Generate any guard from the deduced information.
2.62 +
2.63 + if test:
2.64 + guard, guard_type = test
2.65 +
2.66 + if guard == "specific":
2.67 + ref = first(self.deducer.accessor_all_types[location])
2.68 + argstr = "&%s" % encode_path(ref.get_origin())
2.69 + elif guard == "common":
2.70 + ref = first(self.deducer.accessor_all_general_types[location])
2.71 + typeattr = encode_type_attribute(ref.get_origin())
2.72 + argstr = "%s, %s" % (encode_symbol("pos", typeattr), encode_symbol("code", typeattr))
2.73 + else:
2.74 + return
2.75 +
2.76 + # Write a test that raises a TypeError upon failure.
2.77 +
2.78 + self.writestmt("if (!__test_%s_%s(%s->value, %s)) __raise_type_error();" % (
2.79 + guard, guard_type, name, argstr))
2.80 +
2.81 def process_function_node(self, n):
2.82
2.83 """