Author: Ronan Lamy <ronan.l...@gmail.com> Branch: py3.5 Changeset: r90412:0436a099e10a Date: 2017-02-28 09:58 +0000 http://bitbucket.org/pypy/pypy/changeset/0436a099e10a/
Log: Merged in robert-zaremba/pypy/py3.5-fix-globals (pull request #521) (stevie, robert-zaremba) Approved-by: Richard Plangger diff --git a/pypy/interpreter/astcompiler/symtable.py b/pypy/interpreter/astcompiler/symtable.py --- a/pypy/interpreter/astcompiler/symtable.py +++ b/pypy/interpreter/astcompiler/symtable.py @@ -8,7 +8,7 @@ # These are for internal use only: SYM_BLANK = 0 SYM_GLOBAL = 1 -SYM_ASSIGNED = 2 # Or deleted actually. +SYM_ASSIGNED = 2 # (DEF_LOCAL in CPython3). Or deleted actually. SYM_PARAM = 2 << 1 SYM_NONLOCAL = 2 << 2 SYM_USED = 2 << 3 @@ -123,12 +123,6 @@ def _finalize_name(self, name, flags, local, bound, free, globs): """Decide on the scope of a name.""" if flags & SYM_GLOBAL: - if flags & SYM_PARAM: - err = "name '%s' is parameter and global" % (name,) - raise SyntaxError(err, self.lineno, self.col_offset) - if flags & SYM_NONLOCAL: - err = "name '%s' is nonlocal and global" % (name,) - raise SyntaxError(err, self.lineno, self.col_offset) self.symbols[name] = SCOPE_GLOBAL_EXPLICIT globs[name] = None if bound: @@ -137,12 +131,6 @@ except KeyError: pass elif flags & SYM_NONLOCAL: - if flags & SYM_PARAM: - err = "name '%s' is parameter and nonlocal" % (name,) - raise SyntaxError(err, self.lineno, self.col_offset) - if bound is None: - err = "nonlocal declaration not allowed at module level" - raise SyntaxError(err, self.lineno, self.col_offset) if name not in bound: err = "no binding for nonlocal '%s' found" % (name,) raise SyntaxError(err, self.lineno, self.col_offset) @@ -293,7 +281,8 @@ def _pass_on_bindings(self, local, bound, globs, new_bound, new_globs): new_bound.update(local) - Scope._pass_on_bindings(self, local, bound, globs, new_bound, new_globs) + Scope._pass_on_bindings(self, local, bound, globs, new_bound, + new_globs) def _finalize_cells(self, free): for name, role in self.symbols.iteritems(): @@ -496,20 +485,38 @@ "implemented in PyPy") raise SyntaxError(msg, glob.lineno, glob.col_offset, filename=self.compile_info.filename) + if old_role & SYM_PARAM: + msg = "name '%s' is parameter and global" % (name,) + raise SyntaxError(msg, glob.lineno, glob.col_offset) + if old_role & SYM_NONLOCAL: + msg = "name '%s' is nonlocal and global" % (name,) + raise SyntaxError(msg, glob.lineno, glob.col_offset) + if old_role & (SYM_USED | SYM_ASSIGNED): if old_role & SYM_ASSIGNED: - msg = "name '%s' is assigned to before global declaration" \ + msg = "name '%s' is assigned to before global declaration"\ % (name,) else: msg = "name '%s' is used prior to global declaration" % \ (name,) - misc.syntax_warning(self.space, msg, self.compile_info.filename, + misc.syntax_warning(self.space, msg, + self.compile_info.filename, glob.lineno, glob.col_offset) self.note_symbol(name, SYM_GLOBAL) def visit_Nonlocal(self, nonl): for name in nonl.names: old_role = self.scope.lookup_role(name) + msg = "" + if old_role & SYM_GLOBAL: + msg = "name '%s' is nonlocal and global" % (name,) + if old_role & SYM_PARAM: + msg = "name '%s' is parameter and nonlocal" % (name,) + if type(self.scope) == ModuleScope: + msg = "nonlocal declaration not allowed at module level" + if msg is not "": + raise SyntaxError(msg, nonl.lineno, nonl.col_offset) + if (old_role & (SYM_USED | SYM_ASSIGNED) and not (name == '__class__' and self.scope._hide_bound_from_nested_scopes)): @@ -519,8 +526,10 @@ else: msg = "name '%s' is used prior to nonlocal declaration" % \ (name,) - misc.syntax_warning(self.space, msg, self.compile_info.filename, + misc.syntax_warning(self.space, msg, + self.compile_info.filename, nonl.lineno, nonl.col_offset) + self.note_symbol(name, SYM_NONLOCAL) def visit_Lambda(self, lamb): @@ -589,7 +598,7 @@ def visit_arguments(self, arguments): scope = self.scope - assert isinstance(scope, FunctionScope) # Annotator hint. + assert isinstance(scope, FunctionScope) # Annotator hint. if arguments.args: self._handle_params(arguments.args, True) if arguments.kwonlyargs: diff --git a/pypy/interpreter/astcompiler/test/test_symtable.py b/pypy/interpreter/astcompiler/test/test_symtable.py --- a/pypy/interpreter/astcompiler/test/test_symtable.py +++ b/pypy/interpreter/astcompiler/test/test_symtable.py @@ -283,7 +283,6 @@ def test_global(self): scp = self.func_scope("def f():\n global x\n x = 4") assert scp.lookup("x") == symtable.SCOPE_GLOBAL_EXPLICIT - input = "def f(x):\n global x" scp = self.func_scope("""def f(): y = 3 def x(): @@ -295,18 +294,38 @@ xscp, zscp = scp.children assert xscp.lookup("y") == symtable.SCOPE_GLOBAL_EXPLICIT assert zscp.lookup("y") == symtable.SCOPE_FREE - exc = py.test.raises(SyntaxError, self.func_scope, input).value + + src = "def f(x):\n global x" + exc = py.test.raises(SyntaxError, self.func_scope, src).value + assert exc.lineno == 2 assert exc.msg == "name 'x' is parameter and global" + def test_global_nested(self): + src = """ +def f(x): + def g(x): + global x""" + exc = py.test.raises(SyntaxError, self.func_scope, src).value + assert exc.lineno == 4 + assert exc.msg == "name 'x' is parameter and global" + + scp = self.func_scope(""" +def f(x): + def g(): + global x""") + g = scp.children[0] + assert g.name == 'g' + x = g.lookup_role('x') + assert x == symtable.SYM_GLOBAL + def test_nonlocal(self): - src = str(py.code.Source(""" - def f(): - nonlocal x - global x - """)) + src = """ +x = 1 +def f(): + nonlocal x""" exc = py.test.raises(SyntaxError, self.func_scope, src).value - assert exc.msg == "name 'x' is nonlocal and global" - # + assert exc.msg == "no binding for nonlocal 'x' found" + src = str(py.code.Source(""" def f(x): nonlocal x @@ -324,6 +343,58 @@ src = "nonlocal x" exc = py.test.raises(SyntaxError, self.func_scope, src).value assert exc.msg == "nonlocal declaration not allowed at module level" + assert exc.lineno == 1 + + src = "x = 2\nnonlocal x" + exc = py.test.raises(SyntaxError, self.func_scope, src).value + assert exc.msg == "nonlocal declaration not allowed at module level" + assert exc.lineno == 2 + + def test_nonlocal_and_global(self): + """This test differs from CPython3 behaviour. CPython points to the + first occurance of the global/local expression. PyPy will point to the + last expression which makes the problem.""" + src = """ +def f(): + nonlocal x + global x""" + exc = py.test.raises(SyntaxError, self.func_scope, src).value + assert exc.msg == "name 'x' is nonlocal and global" + assert exc.lineno == 4 + + src = """ +def f(): + global x + nonlocal x """ + exc = py.test.raises(SyntaxError, self.func_scope, src).value + assert exc.msg == "name 'x' is nonlocal and global" + assert exc.lineno == 4 + + def test_nonlocal_nested(self): + scp = self.func_scope(""" +def f(x): + def g(): + nonlocal x""") + g = scp.children[0] + x = g.lookup_role('x') + assert x == symtable.SYM_NONLOCAL + + scp = self.func_scope(""" +def f(): + def g(): + nonlocal x + x = 1""") + g = scp.children[0] + x = g.lookup_role('x') + assert x == symtable.SYM_NONLOCAL + + src = """ +def f(x): + def g(x): + nonlocal x""" + exc = py.test.raises(SyntaxError, self.func_scope, src).value + assert exc.msg == "name 'x' is parameter and nonlocal" + assert exc.lineno == 4 def test_optimization(self): assert not self.mod_scope("").can_be_optimized _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit