Skip to content

Commit 558a016

Browse files
committed
py/compile: Refine SyntaxError for repeated use of global/nonlocal.
1 parent 3a2171e commit 558a016

File tree

3 files changed

+35
-8
lines changed

3 files changed

+35
-8
lines changed

py/compile.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,9 +1355,8 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {
13551355
STATIC void compile_declare_global(compiler_t *comp, mp_parse_node_t pn, qstr qst) {
13561356
bool added;
13571357
id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added);
1358-
if (!added) {
1359-
// TODO this is not compliant with CPython
1360-
compile_syntax_error(comp, pn, "identifier already used");
1358+
if (!added && id_info->kind != ID_INFO_KIND_GLOBAL_EXPLICIT) {
1359+
compile_syntax_error(comp, pn, "identifier redefined as global");
13611360
return;
13621361
}
13631362
id_info->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;
@@ -1382,9 +1381,8 @@ STATIC void compile_global_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
13821381
STATIC void compile_declare_nonlocal(compiler_t *comp, mp_parse_node_t pn, qstr qst) {
13831382
bool added;
13841383
id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added);
1385-
if (!added) {
1386-
// TODO this is not compliant with CPython
1387-
compile_syntax_error(comp, pn, "identifier already used");
1384+
if (!added && id_info->kind != ID_INFO_KIND_FREE) {
1385+
compile_syntax_error(comp, pn, "identifier redefined as nonlocal");
13881386
return;
13891387
}
13901388
id_info_t *id_info2 = scope_find_local_in_parent(comp->scope_cur, qst);

tests/basics/scope.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# test scoping rules
2+
3+
# explicit global variable
4+
a = 1
5+
def f():
6+
global a
7+
global a, a # should be able to redefine as global
8+
a = 2
9+
f()
10+
print(a)
11+
12+
# explicit nonlocal variable
13+
def f():
14+
a = 1
15+
def g():
16+
nonlocal a
17+
nonlocal a, a # should be able to redefine as nonlocal
18+
a = 2
19+
g()
20+
return a
21+
print(f())

tests/basics/syntaxerror.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,7 @@ def test_syntax(code):
7777
test_syntax("yield")
7878
test_syntax("nonlocal a")
7979

80-
# errors on uPy but shouldn't
81-
#test_syntax("global a; global a")
80+
# error on uPy, warning on CPy
8281
#test_syntax("def f():\n a = 1\n global a")
8382

8483
# default except must be last
@@ -109,3 +108,12 @@ def test_syntax(code):
109108

110109
# nonlocal must exist in outer function/class scope
111110
test_syntax("def f():\n def g():\n nonlocal a")
111+
112+
# param can't be redefined as global
113+
test_syntax('def f(x):\n global x')
114+
115+
# param can't be redefined as nonlocal
116+
test_syntax('def f(x):\n nonlocal x')
117+
118+
# can define variable to be both nonlocal and global
119+
test_syntax('def f():\n nonlocal x\n global x')

0 commit comments

Comments
 (0)