Skip to content

Commit 9e7c496

Browse files
authored
Fix syntax error for weird spread parameters (#80)
This output isn't correct, but at least it isn't a syntax error.
1 parent 989207d commit 9e7c496

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed

type-generation/src/astToIR.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -792,12 +792,21 @@ export class Converter {
792792
const param = params[idx];
793793
const spread = !!param.getDotDotDotToken();
794794
const optional = !!param.hasQuestionToken();
795-
const name = param.getName();
796-
const isIdentifier = isValidPythonIdentifier(name);
795+
let name = param.getName();
796+
let isIdentifier = isValidPythonIdentifier(name);
797797
const oldNameContext = this.nameContext?.slice();
798798
const paramType = param.getTypeNode()!;
799799
const isLast = idx === params.length - 1;
800-
if (isLast && Node.isTypeLiteral(paramType)) {
800+
const destructureOnly = isLast && Node.isTypeLiteral(paramType);
801+
if (!destructureOnly && !isIdentifier) {
802+
// Replace name with args${idx}. This is an unfortunate case so we log it.
803+
console.log("Encountered argument with non identifier name");
804+
console.log(params[idx].print());
805+
console.log(getNodeLocation(params[idx]));
806+
name = `args${idx}`;
807+
isIdentifier = true;
808+
}
809+
if (destructureOnly) {
801810
// If it's the last argument and the type is a type literal, we'll
802811
// destructure it so don't make a type.
803812
this.nameContext = undefined;

type-generation/tests/a.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2056,6 +2056,23 @@ describe("emit", () => {
20562056
`).trim(),
20572057
);
20582058
});
2059+
it("Weird spread function signature", () => {
2060+
const res = emitFile(`
2061+
declare function f(...[value]: [] | [string]): void;
2062+
`);
2063+
// This output isn't correct, but at least it isn't a syntax error.
2064+
// We actually should produce:
2065+
// @overload
2066+
// def f(*args0: tuple[()]) -> None: ...
2067+
// @overload
2068+
// def f(*args0: tuple[str]) -> None:
2069+
assert.strictEqual(
2070+
removeTypeIgnores(res.slice(1).join("\n\n")),
2071+
dedent(`
2072+
def f(*args0: tuple[()] | tuple[str]) -> None: ...
2073+
`).trim(),
2074+
);
2075+
});
20592076
describe("adjustments", () => {
20602077
it("setTimeout", () => {
20612078
const res = emitIRNoTypeIgnores(convertBuiltinFunction("setTimeout"));

0 commit comments

Comments
 (0)