Skip to content

Commit e19b95f

Browse files
committed
ApplyKeywordsNode raise TypeError when multiple keyword args of the same name are present
- added an explode loop for the combined args initialization sub-routine in the cached specialization
1 parent ad1e6b8 commit e19b95f

File tree

1 file changed

+54
-50
lines changed

1 file changed

+54
-50
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/ApplyKeywordsNode.java

Lines changed: 54 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -40,55 +40,26 @@
4040
*/
4141
package com.oracle.graal.python.nodes.argument;
4242

43+
import java.util.ArrayList;
44+
4345
import com.oracle.graal.python.builtins.objects.function.Arity;
4446
import com.oracle.graal.python.builtins.objects.function.PArguments;
4547
import com.oracle.graal.python.builtins.objects.function.PKeyword;
48+
import com.oracle.graal.python.nodes.PBaseNode;
4649
import com.oracle.graal.python.nodes.argument.ApplyKeywordsNodeGen.SearchNamedParameterNodeGen;
50+
import com.oracle.graal.python.runtime.exception.PythonErrorType;
4751
import com.oracle.truffle.api.dsl.Cached;
4852
import com.oracle.truffle.api.dsl.Specialization;
4953
import com.oracle.truffle.api.nodes.ExplodeLoop;
5054
import com.oracle.truffle.api.nodes.Node;
5155

52-
public abstract class ApplyKeywordsNode extends Node {
56+
public abstract class ApplyKeywordsNode extends PBaseNode {
5357
public abstract Object[] execute(Arity calleeArity, Object[] arguments, PKeyword[] keywords);
5458

5559
public static ApplyKeywordsNode create() {
5660
return ApplyKeywordsNodeGen.create();
5761
}
5862

59-
private static Object[] applyKeywordArgs(Arity calleeArity, Object[] arguments, PKeyword[] keywords) {
60-
String[] parameters = calleeArity.getParameterIds();
61-
Object[] combined = arguments;
62-
if (parameters.length > PArguments.getUserArgumentLength(arguments)) {
63-
combined = PArguments.create(parameters.length);
64-
System.arraycopy(arguments, 0, combined, 0, arguments.length);
65-
}
66-
PKeyword[] unusedKeywords = new PKeyword[keywords.length];
67-
int unusedKeywordsIdx = 0;
68-
for (int i = 0; i < keywords.length; i++) {
69-
PKeyword keyarg = keywords[i];
70-
int keywordIdx = -1;
71-
for (int j = 0; j < parameters.length; j++) {
72-
if (parameters[j].equals(keyarg.getName())) {
73-
keywordIdx = j;
74-
break;
75-
}
76-
}
77-
78-
if (keywordIdx != -1) {
79-
assert PArguments.getArgument(combined, keywordIdx) == null : calleeArity.getFunctionName() + " got multiple values for argument '" + keyarg.getName() + "'";
80-
PArguments.setArgument(combined, keywordIdx, keyarg.getValue());
81-
} else {
82-
unusedKeywords[unusedKeywordsIdx] = keyarg;
83-
unusedKeywordsIdx++;
84-
}
85-
}
86-
PKeyword[] keywordArguments = new PKeyword[unusedKeywordsIdx];
87-
System.arraycopy(unusedKeywords, 0, keywordArguments, 0, unusedKeywordsIdx);
88-
PArguments.setKeywordArguments(combined, keywordArguments);
89-
return combined;
90-
}
91-
9263
int getUserArgumentLength(Object[] arguments) {
9364
return PArguments.getUserArgumentLength(arguments);
9465
}
@@ -97,6 +68,13 @@ SearchNamedParameterNode createSearchNamedParameterNode() {
9768
return SearchNamedParameterNodeGen.create();
9869
}
9970

71+
@ExplodeLoop
72+
private static void copyArgs(Object[] src, Object[] dst, int len) {
73+
for (int i = 0; i < len; i++) {
74+
dst[i] = src[i];
75+
}
76+
}
77+
10078
@Specialization(guards = {"kwLen == keywords.length", "argLen == arguments.length", "calleeArity == cachedArity"})
10179
@ExplodeLoop
10280
Object[] applyCached(Arity calleeArity, Object[] arguments, PKeyword[] keywords,
@@ -110,32 +88,58 @@ Object[] applyCached(Arity calleeArity, Object[] arguments, PKeyword[] keywords,
11088
Object[] combined = arguments;
11189
if (paramLen > userArgLen) {
11290
combined = PArguments.create(paramLen);
113-
for (int i = 0; i < argLen; i++) {
114-
combined[i] = arguments[i];
115-
}
91+
copyArgs(arguments, combined, argLen);
11692
}
117-
PKeyword[] unusedKeywords = new PKeyword[kwLen];
118-
int unusedKeywordsIdx = 0;
93+
94+
ArrayList<PKeyword> unusedKeywords = new ArrayList<>();
11995
for (int i = 0; i < kwLen; i++) {
120-
PKeyword keyarg = keywords[i];
121-
int keywordIdx = searchParamNode.execute(parameters, keyarg.getName());
122-
if (keywordIdx != -1) {
123-
assert PArguments.getArgument(combined, keywordIdx) == null : calleeArity.getFunctionName() + " got multiple values for argument '" + keyarg.getName() + "'";
124-
PArguments.setArgument(combined, keywordIdx, keyarg.getValue());
96+
PKeyword kwArg = keywords[i];
97+
int kwIdx = searchParamNode.execute(parameters, kwArg.getName());
98+
99+
if (kwIdx != -1) {
100+
if (PArguments.getArgument(combined, kwIdx) != null) {
101+
throw raise(PythonErrorType.TypeError, "%s() got multiple values for argument '%s'", calleeArity.getFunctionName(), kwArg.getName());
102+
}
103+
PArguments.setArgument(combined, kwIdx, kwArg.getValue());
125104
} else {
126-
unusedKeywords[unusedKeywordsIdx] = keyarg;
127-
unusedKeywordsIdx++;
105+
unusedKeywords.add(kwArg);
128106
}
129107
}
130-
PKeyword[] keywordArguments = new PKeyword[unusedKeywordsIdx];
131-
System.arraycopy(unusedKeywords, 0, keywordArguments, 0, unusedKeywordsIdx);
132-
PArguments.setKeywordArguments(combined, keywordArguments);
108+
PArguments.setKeywordArguments(combined, unusedKeywords.toArray(new PKeyword[unusedKeywords.size()]));
133109
return combined;
134110
}
135111

136112
@Specialization(replaces = "applyCached")
137113
Object[] applyUncached(Arity calleeArity, Object[] arguments, PKeyword[] keywords) {
138-
return applyKeywordArgs(calleeArity, arguments, keywords);
114+
String[] parameters = calleeArity.getParameterIds();
115+
Object[] combined = arguments;
116+
if (parameters.length > PArguments.getUserArgumentLength(arguments)) {
117+
combined = PArguments.create(parameters.length);
118+
System.arraycopy(arguments, 0, combined, 0, arguments.length);
119+
}
120+
121+
ArrayList<PKeyword> unusedKeywords = new ArrayList<>();
122+
for (int i = 0; i < keywords.length; i++) {
123+
PKeyword kwArg = keywords[i];
124+
int kwIdx = -1;
125+
for (int j = 0; j < parameters.length; j++) {
126+
if (parameters[j].equals(kwArg.getName())) {
127+
kwIdx = j;
128+
break;
129+
}
130+
}
131+
132+
if (kwIdx != -1) {
133+
if (PArguments.getArgument(combined, kwIdx) != null) {
134+
throw raise(PythonErrorType.TypeError, "%s() got multiple values for argument '%s'", calleeArity.getFunctionName(), kwArg.getName());
135+
}
136+
PArguments.setArgument(combined, kwIdx, kwArg.getValue());
137+
} else {
138+
unusedKeywords.add(kwArg);
139+
}
140+
}
141+
PArguments.setKeywordArguments(combined, unusedKeywords.toArray(new PKeyword[unusedKeywords.size()]));
142+
return combined;
139143
}
140144

141145
protected abstract static class SearchNamedParameterNode extends Node {

0 commit comments

Comments
 (0)