[Python-checkins] bpo-40147: Move the check for duplicate keywords to the compiler (GH-19289)

Pablo Galindo webhook-mailer at python.org
Fri Apr 3 15:37:21 EDT 2020


https://github.com/python/cpython/commit/254ec783411d9d16e51f1116f98918be2ef0e884
commit: 254ec783411d9d16e51f1116f98918be2ef0e884
branch: master
author: Pablo Galindo <Pablogsal at gmail.com>
committer: GitHub <noreply at github.com>
date: 2020-04-03T20:37:13+01:00
summary:

bpo-40147: Move the check for duplicate keywords to the compiler (GH-19289)

files:
M Lib/test/test_metaclass.py
M Lib/test/test_syntax.py
M Python/ast.c
M Python/compile.c

diff --git a/Lib/test/test_metaclass.py b/Lib/test/test_metaclass.py
index e6fe20a107c23..6edd899b0d213 100644
--- a/Lib/test/test_metaclass.py
+++ b/Lib/test/test_metaclass.py
@@ -128,7 +128,7 @@
     ...
     Traceback (most recent call last):
     [...]
-    SyntaxError: keyword argument repeated
+    SyntaxError: keyword argument repeated: metaclass
     >>>
 
 Another way.
diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py
index 128c4da143841..a7e7e2c9e6f02 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -588,7 +588,7 @@
 >>> f(a=23, a=234)
 Traceback (most recent call last):
    ...
-SyntaxError: keyword argument repeated
+SyntaxError: keyword argument repeated: a
 
 >>> {1, 2, 3} = 42
 Traceback (most recent call last):
diff --git a/Python/ast.c b/Python/ast.c
index 550ee03b1ac38..6ba62fb479f99 100644
--- a/Python/ast.c
+++ b/Python/ast.c
@@ -3048,8 +3048,7 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func,
             else {
                 /* a keyword argument */
                 keyword_ty kw;
-                identifier key, tmp;
-                int k;
+                identifier key;
 
                 // To remain LL(1), the grammar accepts any test (basically, any
                 // expression) in the keyword slot of a call site.  So, we need
@@ -3093,14 +3092,6 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func,
                 if (forbidden_name(c, key, chch, 1)) {
                     return NULL;
                 }
-                for (k = 0; k < nkeywords; k++) {
-                    tmp = ((keyword_ty)asdl_seq_GET(keywords, k))->arg;
-                    if (tmp && !PyUnicode_Compare(tmp, key)) {
-                        ast_error(c, chch,
-                                  "keyword argument repeated");
-                        return NULL;
-                    }
-                }
                 e = ast_for_expr(c, CHILD(ch, 2));
                 if (!e)
                     return NULL;
diff --git a/Python/compile.c b/Python/compile.c
index 01700e0e78cc9..b1c1982fd2c4a 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -4049,6 +4049,31 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
     return 1;
 }
 
+static int
+validate_keywords(struct compiler *c, asdl_seq* keywords) {
+    int nkeywords = asdl_seq_LEN(keywords);
+    for (int i = 0; i < nkeywords; i++) {
+        keyword_ty key = ((keyword_ty)asdl_seq_GET(keywords, i));
+        if (key->arg == NULL) {
+            continue;
+        }
+        for (int j = i+1; j < nkeywords; j++) {
+            keyword_ty other = ((keyword_ty)asdl_seq_GET(keywords, j));
+            if (other->arg && !PyUnicode_Compare(key->arg, other->arg)) {
+                PyObject *msg = PyUnicode_FromFormat("keyword argument repeated: %U", key->arg);
+                if (msg == NULL) {
+                    return -1;
+                }
+                c->u->u_col_offset = other->col_offset;
+                compiler_error(c, PyUnicode_AsUTF8(msg));
+                Py_DECREF(msg);
+                return -1;
+            }
+        }
+    }
+    return 0;
+}
+
 static int
 compiler_call(struct compiler *c, expr_ty e)
 {
@@ -4165,6 +4190,10 @@ compiler_call_helper(struct compiler *c,
 {
     Py_ssize_t i, nseen, nelts, nkwelts;
 
+    if (validate_keywords(c, keywords) == -1) {
+        return 0;
+    }
+
     nelts = asdl_seq_LEN(args);
     nkwelts = asdl_seq_LEN(keywords);
 



More information about the Python-checkins mailing list