# HG changeset patch # User Paul Boddie # Date 1480098037 -3600 # Node ID ed3fbc0d4e4a852843028fb64fbeeac776505a93 # Parent b2748d715f7c1680d463ee2eaf07b0f1fd0fed68 Added support for guards after name assignments. diff -r b2748d715f7c -r ed3fbc0d4e4a tests/methods_unbound.py --- a/tests/methods_unbound.py Fri Nov 25 18:36:45 2016 +0100 +++ b/tests/methods_unbound.py Fri Nov 25 19:20:37 2016 +0100 @@ -4,6 +4,15 @@ def m(self, x): return x +class D: + pass + +def getc(): + return C() + +def getd(): + return D() + def f(obj, i): if i: return obj.m(i) # should cause access to an unbound method @@ -17,6 +26,14 @@ else: return obj.m +def h(obj, fn): + if fn: + obj = fn() + obj.a # only provided by instances of C + return obj.m(1) + else: + return obj.m + c = C() try: @@ -41,3 +58,11 @@ print g(c, 1) # 1 print g(c, 0)(3) # 3 + +print h(c, getc) # 1 +print h(c, 0)(4) # 4 + +try: + print h(c, getd) # should fail with an error caused by a guard +except TypeError: + print "h(c, getd): getd provides an unsuitable result." diff -r b2748d715f7c -r ed3fbc0d4e4a translator.py --- a/translator.py Fri Nov 25 18:36:45 2016 +0100 +++ b/translator.py Fri Nov 25 19:20:37 2016 +0100 @@ -587,6 +587,11 @@ name_ref = self.process_name_node(n, self.process_structure_node(expr)) self.statement(name_ref) + # Employ guards after assignments if required. + + if expr and name_ref.is_name(): + self.generate_guard(name_ref.name) + elif isinstance(n, compiler.ast.AssAttr): in_assignment = self.in_assignment self.in_assignment = self.process_structure_node(expr) @@ -772,28 +777,7 @@ # Process any guards defined for the parameters. for name in self.importer.function_parameters.get(function_name): - - # Get the accessor details and any guards defined for it. - - location = self.get_accessor_location(name) - test = self.deducer.accessor_guard_tests.get(location) - if test: - guard, guard_type = test - - if guard == "specific": - ref = first(self.deducer.accessor_all_types[location]) - argstr = "&%s" % encode_path(ref.get_origin()) - elif guard == "common": - ref = first(self.deducer.accessor_all_general_types[location]) - typeattr = encode_type_attribute(ref.get_origin()) - argstr = "%s, %s" % (encode_symbol("pos", typeattr), encode_symbol("code", typeattr)) - else: - continue - - # Write a test that raises a TypeError upon failure. - - self.writestmt("if (!__test_%s_%s(%s->value, %s)) __raise_type_error();" % ( - guard, guard_type, name, argstr)) + self.generate_guard(name) # Produce the body and any additional return statement. @@ -805,6 +789,38 @@ self.end_function(function_name) + def generate_guard(self, name): + + """ + Get the accessor details for 'name', found in the current namespace, and + generate any guards defined for it. + """ + + # Obtain the location, keeping track of assignment versions. + + location = self.get_accessor_location(name) + test = self.deducer.accessor_guard_tests.get(location) + + # Generate any guard from the deduced information. + + if test: + guard, guard_type = test + + if guard == "specific": + ref = first(self.deducer.accessor_all_types[location]) + argstr = "&%s" % encode_path(ref.get_origin()) + elif guard == "common": + ref = first(self.deducer.accessor_all_general_types[location]) + typeattr = encode_type_attribute(ref.get_origin()) + argstr = "%s, %s" % (encode_symbol("pos", typeattr), encode_symbol("code", typeattr)) + else: + return + + # Write a test that raises a TypeError upon failure. + + self.writestmt("if (!__test_%s_%s(%s->value, %s)) __raise_type_error();" % ( + guard, guard_type, name, argstr)) + def process_function_node(self, n): """