mirror of
https://github.com/oxc-project/oxc.git
synced 2026-09-14 19:36:11 +08:00
fix(parser): require arrow separator in TypeScript function types (#26529)
Require `=>` when parsing TypeScript function and constructor types, while retaining `:` for function, method, and arrow return annotations. Previously, any token could be consumed as the separator, accepting invalid types such as `type F = (): number` and `type F = new () + number`. This also prevents a valid conditional expression from being silently grouped into the wrong arrows: ```ts const a = true, b = 1, c = 2; const f = a ? (b) : (): any => b ? c : (x = 1): any => x; console.log(typeof f); ``` The transformed program now prints `number`; previously it printed `function`.
This commit is contained in:
@@ -53,7 +53,7 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
});
|
||||
let return_type = {
|
||||
let return_type_start = self.cur_start();
|
||||
let return_type = self.parse_return_type();
|
||||
let return_type = self.parse_return_type(Kind::Arrow);
|
||||
TSTypeAnnotation::boxed(self.end_span(return_type_start), return_type, self)
|
||||
};
|
||||
|
||||
@@ -1322,12 +1322,12 @@ impl<'a, C: Config> ParserImpl<'a, C> {
|
||||
return None;
|
||||
}
|
||||
let start = self.cur_start();
|
||||
let return_type = self.parse_return_type();
|
||||
let return_type = self.parse_return_type(Kind::Colon);
|
||||
Some(TSTypeAnnotation::boxed(self.end_span(start), return_type, self))
|
||||
}
|
||||
|
||||
fn parse_return_type(&mut self) -> TSType<'a> {
|
||||
self.bump_any();
|
||||
fn parse_return_type(&mut self, separator: Kind) -> TSType<'a> {
|
||||
self.expect(separator);
|
||||
self.context_remove(Context::DisallowConditionalTypes, Self::parse_type_or_type_predicate)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
type F = abstract new () : number;
|
||||
@@ -0,0 +1 @@
|
||||
type F = abstract new () number;
|
||||
@@ -0,0 +1 @@
|
||||
type F = abstract new () + number;
|
||||
@@ -0,0 +1 @@
|
||||
type F = new () : number;
|
||||
@@ -0,0 +1 @@
|
||||
type F = new () number;
|
||||
@@ -0,0 +1 @@
|
||||
type F = new () + number;
|
||||
@@ -0,0 +1 @@
|
||||
type F = () : number;
|
||||
@@ -0,0 +1 @@
|
||||
type F = () + number;
|
||||
@@ -0,0 +1,7 @@
|
||||
type F = () => number;
|
||||
type C = new () => object;
|
||||
type A = abstract new () => object;
|
||||
type Predicate = (x: unknown) => x is number;
|
||||
function f(): number { return 1; }
|
||||
const arrow = (): number => 1;
|
||||
const object = { method(): number { return 1; } };
|
||||
@@ -1,3 +1,3 @@
|
||||
codegen_misc Summary:
|
||||
AST Parsed : 103/103 (100.00%)
|
||||
Positive Passed: 103/103 (100.00%)
|
||||
AST Parsed : 104/104 (100.00%)
|
||||
Positive Passed: 104/104 (100.00%)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
formatter_misc Summary:
|
||||
AST Parsed : 103/103 (100.00%)
|
||||
Positive Passed: 103/103 (100.00%)
|
||||
AST Parsed : 104/104 (100.00%)
|
||||
Positive Passed: 104/104 (100.00%)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
lexer_misc Summary:
|
||||
AST Parsed : 305/305 (100.00%)
|
||||
Positive Passed: 305/305 (100.00%)
|
||||
AST Parsed : 314/314 (100.00%)
|
||||
Positive Passed: 314/314 (100.00%)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
parser_misc Summary:
|
||||
AST Parsed : 103/103 (100.00%)
|
||||
Positive Passed: 103/103 (100.00%)
|
||||
Negative Passed: 202/202 (100.00%)
|
||||
AST Parsed : 104/104 (100.00%)
|
||||
Positive Passed: 104/104 (100.00%)
|
||||
Negative Passed: 210/210 (100.00%)
|
||||
|
||||
× Cannot assign to 'arguments' in strict mode
|
||||
╭─[misc/fail/arguments-eval-ambient.ts:2:13]
|
||||
@@ -4762,6 +4762,62 @@ Negative Passed: 202/202 (100.00%)
|
||||
· ╰── `,` expected
|
||||
╰────
|
||||
|
||||
× Expected `=>` but found `:`
|
||||
╭─[misc/fail/ts-abstract-constructor-type-colon-separator.ts:1:26]
|
||||
1 │ type F = abstract new () : number;
|
||||
· ┬
|
||||
· ╰── `=>` expected
|
||||
╰────
|
||||
|
||||
× Expected `=>` but found `number`
|
||||
╭─[misc/fail/ts-abstract-constructor-type-missing-separator.ts:1:27]
|
||||
1 │ type F = abstract new () number;
|
||||
· ───┬──
|
||||
· ╰── `=>` expected
|
||||
╰────
|
||||
|
||||
× Expected `=>` but found `+`
|
||||
╭─[misc/fail/ts-abstract-constructor-type-plus-separator.ts:1:26]
|
||||
1 │ type F = abstract new () + number;
|
||||
· ┬
|
||||
· ╰── `=>` expected
|
||||
╰────
|
||||
|
||||
× Expected `=>` but found `:`
|
||||
╭─[misc/fail/ts-constructor-type-colon-separator.ts:1:17]
|
||||
1 │ type F = new () : number;
|
||||
· ┬
|
||||
· ╰── `=>` expected
|
||||
╰────
|
||||
|
||||
× Expected `=>` but found `number`
|
||||
╭─[misc/fail/ts-constructor-type-missing-separator.ts:1:18]
|
||||
1 │ type F = new () number;
|
||||
· ───┬──
|
||||
· ╰── `=>` expected
|
||||
╰────
|
||||
|
||||
× Expected `=>` but found `+`
|
||||
╭─[misc/fail/ts-constructor-type-plus-separator.ts:1:17]
|
||||
1 │ type F = new () + number;
|
||||
· ┬
|
||||
· ╰── `=>` expected
|
||||
╰────
|
||||
|
||||
× Expected `=>` but found `:`
|
||||
╭─[misc/fail/ts-function-type-colon-separator.ts:1:13]
|
||||
1 │ type F = () : number;
|
||||
· ┬
|
||||
· ╰── `=>` expected
|
||||
╰────
|
||||
|
||||
× Expected `=>` but found `+`
|
||||
╭─[misc/fail/ts-function-type-plus-separator.ts:1:13]
|
||||
1 │ type F = () + number;
|
||||
· ┬
|
||||
· ╰── `=>` expected
|
||||
╰────
|
||||
|
||||
× TS(1009): Trailing comma not allowed.
|
||||
╭─[misc/fail/ts-interface-invalid-heritage.ts:1:22]
|
||||
1 │ interface A extends B, {}
|
||||
|
||||
@@ -7560,21 +7560,14 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/types/wit
|
||||
15 │ }
|
||||
╰────
|
||||
|
||||
× Expected `,` or `)` but found `var`
|
||||
╭─[typescript/tests/cases/compiler/functionTypesLackingReturnTypes.ts:2:11]
|
||||
× Expected `=>` but found `)`
|
||||
╭─[typescript/tests/cases/compiler/functionTypesLackingReturnTypes.ts:2:17]
|
||||
1 │ // Error (no '=>')
|
||||
2 │ function f(x: ()) {
|
||||
· ┬
|
||||
· ╰── Opened here
|
||||
· ┬
|
||||
· ╰── `=>` expected
|
||||
3 │ }
|
||||
╰────
|
||||
╭─[typescript/tests/cases/compiler/functionTypesLackingReturnTypes.ts:6:1]
|
||||
5 │ // Error (no '=>')
|
||||
6 │ var g: (param);
|
||||
· ─┬─
|
||||
· ╰── `,` or `)` expected
|
||||
7 │
|
||||
╰────
|
||||
|
||||
× Identifier `total` has already been declared
|
||||
╭─[typescript/tests/cases/compiler/functionWithSameNameAsField.ts:2:12]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
semantic_misc Summary:
|
||||
AST Parsed : 103/103 (100.00%)
|
||||
Positive Passed: 99/103 (96.12%)
|
||||
AST Parsed : 104/104 (100.00%)
|
||||
Positive Passed: 100/104 (96.15%)
|
||||
semantic Error: tasks/coverage/misc/pass/declare-let-private.ts
|
||||
Bindings mismatch:
|
||||
after transform: ScopeId(0): ["private"]
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
transformer_misc Summary:
|
||||
AST Parsed : 103/103 (100.00%)
|
||||
Positive Passed: 103/103 (100.00%)
|
||||
AST Parsed : 104/104 (100.00%)
|
||||
Positive Passed: 104/104 (100.00%)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
commit: 1eac4481
|
||||
|
||||
Passed: 276/404
|
||||
Passed: 277/405
|
||||
|
||||
# All Passed:
|
||||
* babel-plugin-transform-class-static-block
|
||||
@@ -48,7 +48,7 @@ x Output mismatch
|
||||
x Output mismatch
|
||||
|
||||
|
||||
# babel-plugin-transform-typescript (41/60)
|
||||
# babel-plugin-transform-typescript (42/61)
|
||||
* allow-declare-fields-false/input.ts
|
||||
Unresolved references mismatch:
|
||||
after transform: ["dce"]
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
const a = true, b = 1, c = 2;
|
||||
const f = a ? (b) : (): any => b ? c : (x = 1): any => x;
|
||||
console.log(typeof f);
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"plugins": ["transform-typescript"]
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
const a = true, b = 1, c = 2;
|
||||
const f = a ? b : () => b ? c : (x = 1) => x;
|
||||
console.log(typeof f);
|
||||
Reference in New Issue
Block a user