Skip to content

Commit 80f0f5c

Browse files
committed
[GR-59902] Fix clinic-generated arg indices for builtins with var args
PullRequest: graalpython/3579
2 parents 4efdcb2 + 1e7f0d9 commit 80f0f5c

File tree

2 files changed

+71
-5
lines changed

2 files changed

+71
-5
lines changed

graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/ArgumentClinicProcessor.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ private static BuiltinAnnotation getBuiltinAnnotation(TypeElement type) throws P
358358
Stream<?> parameterNames = null;
359359
Stream<?> keywordOnlyNames = null;
360360
int minNumOfPositionalArgs = -1;
361+
boolean takesVarArgs = false;
361362
AnnotationMirror annot = findAnnotationMirror(type, BuiltinAnnotationClass);
362363
if (annot == null) {
363364
annot = findAnnotationMirror(type, BuiltinsAnnotationClass);
@@ -392,18 +393,22 @@ private static BuiltinAnnotation getBuiltinAnnotation(TypeElement type) throws P
392393
builtinName = (String) item.getValue().getValue();
393394
} else if (item.getKey().getSimpleName().toString().equals("minNumOfPositionalArgs")) {
394395
minNumOfPositionalArgs = (int) item.getValue().getValue();
396+
} else if (item.getKey().getSimpleName().toString().equals("takesVarArgs")) {
397+
takesVarArgs = (boolean) item.getValue().getValue();
395398
}
396399
}
397400
}
398401
if ((parameterNames == null && keywordOnlyNames == null) || builtinName == null) {
399402
throw error(type, "In order to use Argument Clinic, the Builtin annotation must contain 'name' and 'parameterNames' and/or 'keywordOnlyNames' fields.");
400403
}
404+
if (parameterNames == null) {
405+
parameterNames = Stream.of();
406+
}
407+
if (takesVarArgs) {
408+
parameterNames = Stream.concat(parameterNames, Stream.of("*args"));
409+
}
401410
if (keywordOnlyNames != null) {
402-
if (parameterNames == null) {
403-
parameterNames = keywordOnlyNames;
404-
} else {
405-
parameterNames = Stream.concat(parameterNames, keywordOnlyNames);
406-
}
411+
parameterNames = Stream.concat(parameterNames, keywordOnlyNames);
407412
}
408413
return new BuiltinAnnotation(builtinName, parameterNames.toArray(String[]::new), minNumOfPositionalArgs);
409414
}

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/builtin/modules/ClinicTests.java

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,13 @@
6060
import com.oracle.graal.python.builtins.Builtin;
6161
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
6262
import com.oracle.graal.python.builtins.objects.PNone;
63+
import com.oracle.graal.python.builtins.objects.function.PArguments;
64+
import com.oracle.graal.python.builtins.objects.function.PKeyword;
65+
import com.oracle.graal.python.nodes.argument.ReadArgumentNode;
66+
import com.oracle.graal.python.nodes.argument.ReadIndexedArgumentNode;
67+
import com.oracle.graal.python.nodes.argument.ReadVarArgsNode;
6368
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryClinicBuiltinNode;
69+
import com.oracle.graal.python.nodes.function.builtins.PythonClinicBuiltinNode;
6470
import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentCastNode;
6571
import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider;
6672
import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile;
@@ -180,6 +186,42 @@ public void testCustomConvertor() {
180186
assertEquals(T_DONE, callTarget.call(T_A_INPUT, T_B_INPUT));
181187
}
182188

189+
@Builtin(name = "my_vararg_builtin", parameterNames = {"x", "a"}, takesVarArgs = true, keywordOnlyNames = {"b"})
190+
@ArgumentClinic(name = "a", conversion = ClinicConversion.Int)
191+
@ArgumentClinic(name = "b", conversion = ClinicConversion.Int, defaultValue = "7")
192+
public abstract static class MyVarArgBuiltinWithDefaultValues extends PythonClinicBuiltinNode {
193+
@Override
194+
protected ArgumentClinicProvider getArgumentClinic() {
195+
return ClinicTestsClinicProviders.MyVarArgBuiltinWithDefaultValuesClinicProviderGen.INSTANCE;
196+
}
197+
198+
@Specialization
199+
Object doDefaults(Object x, int a, Object[] varArgs, int b) {
200+
assertEquals("abc", x);
201+
assertEquals(42, a);
202+
assertEquals(1, varArgs.length);
203+
assertEquals(7, b);
204+
return varArgs[0];
205+
}
206+
}
207+
208+
@Test
209+
public void testVarArgDefaultValues() {
210+
CallTarget callTarget = createCallTarget(ClinicTestsFactory.MyVarArgBuiltinWithDefaultValuesNodeGen.create(
211+
new ReadArgumentNode[]{
212+
ReadIndexedArgumentNode.create(0),
213+
ReadIndexedArgumentNode.create(1),
214+
ReadVarArgsNode.create(true),
215+
ReadIndexedArgumentNode.create(2)
216+
}));
217+
Object[] scope_w = PArguments.create(2);
218+
scope_w[PArguments.USER_ARGUMENTS_OFFSET] = "abc";
219+
scope_w[PArguments.USER_ARGUMENTS_OFFSET + 1] = 42;
220+
PArguments.setVariableArguments(scope_w, 666);
221+
PArguments.setKeywordArguments(scope_w, new PKeyword[]{new PKeyword(tsLiteral("b"), PNone.NO_VALUE)});
222+
assertEquals(666, callTarget.call(scope_w));
223+
}
224+
183225
private static CallTarget createCallTarget(PythonBinaryClinicBuiltinNode node) {
184226
return new BinaryBuiltinRoot(node).getCallTarget();
185227
}
@@ -207,4 +249,23 @@ public Object execute(VirtualFrame frame) {
207249
}
208250
}
209251
}
252+
253+
private static CallTarget createCallTarget(PythonClinicBuiltinNode node) {
254+
return new BuiltinRoot(node).getCallTarget();
255+
}
256+
257+
private static final class BuiltinRoot extends RootNode {
258+
@Child PythonClinicBuiltinNode node;
259+
260+
BuiltinRoot(PythonClinicBuiltinNode node) {
261+
super(null);
262+
this.node = node;
263+
}
264+
265+
@Override
266+
public Object execute(VirtualFrame frame) {
267+
return node.execute(frame);
268+
}
269+
}
270+
210271
}

0 commit comments

Comments
 (0)