From 66148861926a8e70cb75ff20cb2f0ff171c2e630 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Mon, 10 Apr 2023 22:11:04 -0400 Subject: [PATCH] fix(es/parser): Parse `const` type parameters in arrow function expressions (#7242) --- crates/swc_ecma_parser/src/parser/expr.rs | 2 +- .../swc_ecma_parser/src/parser/typescript.rs | 9 +- .../1/input.ts.swc-stderr | 228 +++++++++++++++++- .../arrow-function/const-type-param/input.ts | 1 + .../const-type-param/input.ts.json | 162 +++++++++++++ .../variance-annotations/1/input.ts.json | 6 +- .../with_jsx/input.tsx.json | 6 +- 7 files changed, 400 insertions(+), 14 deletions(-) create mode 100644 crates/swc_ecma_parser/tests/typescript/arrow-function/const-type-param/input.ts create mode 100644 crates/swc_ecma_parser/tests/typescript/arrow-function/const-type-param/input.ts.json diff --git a/crates/swc_ecma_parser/src/parser/expr.rs b/crates/swc_ecma_parser/src/parser/expr.rs index 0728f870f61..70e23f87be6 100644 --- a/crates/swc_ecma_parser/src/parser/expr.rs +++ b/crates/swc_ecma_parser/src/parser/expr.rs @@ -105,7 +105,7 @@ impl Parser { } } - let type_parameters = p.parse_ts_type_params(false, false)?; + let type_parameters = p.parse_ts_type_params(false, true)?; let mut arrow = p.parse_assignment_expr_base()?; match *arrow { Expr::Arrow(ArrowExpr { diff --git a/crates/swc_ecma_parser/src/parser/typescript.rs b/crates/swc_ecma_parser/src/parser/typescript.rs index 37f919db52f..f64d7d4ea9e 100644 --- a/crates/swc_ecma_parser/src/parser/typescript.rs +++ b/crates/swc_ecma_parser/src/parser/typescript.rs @@ -398,16 +398,16 @@ impl Parser { )? { match modifer { "const" => { + is_const = true; if !permit_const { self.emit_err( self.input.prev_span(), SyntaxError::TS1277(js_word!("const")), ); - } else { - is_const = true; } } "in" => { + is_in = true; if !permit_in_out { self.emit_err(self.input.prev_span(), SyntaxError::TS1274(js_word!("in"))); } else if is_in { @@ -417,17 +417,14 @@ impl Parser { self.input.prev_span(), SyntaxError::TS1029(js_word!("in"), js_word!("out")), ); - } else { - is_in = true; } } "out" => { + is_out = true; if !permit_in_out { self.emit_err(self.input.prev_span(), SyntaxError::TS1274(js_word!("out"))); } else if is_out { self.emit_err(self.input.prev_span(), SyntaxError::TS1030(js_word!("out"))); - } else { - is_out = true; } } other => self.emit_err(self.input.prev_span(), SyntaxError::TS1273(other.into())), diff --git a/crates/swc_ecma_parser/tests/typescript-errors/variance-annotations/1/input.ts.swc-stderr b/crates/swc_ecma_parser/tests/typescript-errors/variance-annotations/1/input.ts.swc-stderr index 1420b07e51a..93cf16a0302 100644 --- a/crates/swc_ecma_parser/tests/typescript-errors/variance-annotations/1/input.ts.swc-stderr +++ b/crates/swc_ecma_parser/tests/typescript-errors/variance-annotations/1/input.ts.swc-stderr @@ -1,4 +1,152 @@ + x 'out' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:1:1] + 1 | type Covariant = { + : ^^^ + 2 | x: T; + `---- + + x 'in' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:10:1] + 10 | + 11 | type Contravariant = { + : ^^ + 12 | f: (x: T) => void; + `---- + + x 'in' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:20:1] + 20 | + 21 | type Invariant = { + : ^^ + 22 | f: (x: T) => T; + `---- + + x 'out' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:20:1] + 20 | + 21 | type Invariant = { + : ^^^ + 22 | f: (x: T) => T; + `---- + + x 'out' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:32:1] + 32 | + 33 | type T10 = T; + : ^^^ + 34 | type T11 = keyof T; + `---- + + x 'in' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:33:1] + 33 | type T10 = T; + 34 | type T11 = keyof T; + : ^^ + 35 | type T12 = T[K]; + `---- + + x 'out' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:34:1] + 34 | type T11 = keyof T; + 35 | type T12 = T[K]; + : ^^^ + 36 | type T13 = T[keyof T]; + `---- + + x 'out' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:34:1] + 34 | type T11 = keyof T; + 35 | type T12 = T[K]; + : ^^^ + 36 | type T13 = T[keyof T]; + `---- + + x 'in' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:35:1] + 35 | type T12 = T[K]; + 36 | type T13 = T[keyof T]; + : ^^ + `---- + + x 'out' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:35:1] + 35 | type T12 = T[K]; + 36 | type T13 = T[keyof T]; + : ^^^ + `---- + + x 'in' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:39:1] + 39 | + 40 | type Covariant1 = { // Error + : ^^ + 41 | x: T; + `---- + + x 'out' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:43:1] + 43 | + 44 | type Contravariant1 = keyof T; // Error + : ^^^ + `---- + + x 'out' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:45:1] + 45 | + 46 | type Contravariant2 = { // Error + : ^^^ + 47 | f: (x: T) => void; + `---- + + x 'in' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:49:1] + 49 | + 50 | type Invariant1 = { // Error + : ^^ + 51 | f: (x: T) => T; + `---- + + x 'out' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:53:1] + 53 | + 54 | type Invariant2 = { // Error + : ^^^ + 55 | f: (x: T) => T; + `---- + + x 'in' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:59:1] + 59 | + 60 | type Foo1 = { // Error + : ^^ + 61 | x: T; + `---- + + x 'out' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:70:1] + 70 | + 71 | type Foo2 = { // Error + : ^^^ + 72 | x: T; + `---- + + x 'in' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:81:1] + 81 | + 82 | type Foo3 = { + : ^^ + 83 | x: T; + `---- + + x 'out' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:81:1] + 81 | + 82 | type Foo3 = { + : ^^^ + 83 | x: T; + `---- + x 'public' modifier cannot appear on a type parameter ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:94:1] 94 | @@ -10,11 +158,43 @@ x 'in' modifier already seen. ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:95:1] 95 | type T20 = T; // Error + 96 | type T21 = T; // Error + : ^^ + 97 | type T22 = T; // Error + `---- + + x 'out' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:95:1] + 95 | type T20 = T; // Error + 96 | type T21 = T; // Error + : ^^^ + 97 | type T22 = T; // Error + `---- + + x 'in' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:95:1] + 95 | type T20 = T; // Error 96 | type T21 = T; // Error : ^^ 97 | type T22 = T; // Error `---- + x 'in' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:96:1] + 96 | type T21 = T; // Error + 97 | type T22 = T; // Error + : ^^ + 98 | type T23 = T; // Error + `---- + + x 'out' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:96:1] + 96 | type T21 = T; // Error + 97 | type T22 = T; // Error + : ^^^ + 98 | type T23 = T; // Error + `---- + x 'out' modifier already seen. ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:96:1] 96 | type T21 = T; // Error @@ -23,7 +203,14 @@ 98 | type T23 = T; // Error `---- - x 'in' modifier must precede 'out' modifier. + x 'out' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:97:1] + 97 | type T22 = T; // Error + 98 | type T23 = T; // Error + : ^^^ + `---- + + x 'in' modifier already seen. ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:97:1] 97 | type T22 = T; // Error 98 | type T23 = T; // Error @@ -60,3 +247,42 @@ : ^^^ 106 | } `---- + + x 'out' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:109:1] + 109 | + 110 | interface Baz {} + : ^^^ + 111 | interface Baz {} + `---- + + x 'in' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:110:1] + 110 | interface Baz {} + 111 | interface Baz {} + : ^^ + `---- + + x 'out' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:120:1] + 120 | + 121 | interface Parent { + : ^^^ + 122 | child: Child | null; + `---- + + x 'in' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:139:1] + 139 | + 140 | declare class StateNode { + : ^^ + 141 | _storedEvent: TEvent; + `---- + + x 'out' modifier already seen. + ,-[$DIR/tests/typescript-errors/variance-annotations/1/input.ts:139:1] + 139 | + 140 | declare class StateNode { + : ^^^ + 141 | _storedEvent: TEvent; + `---- diff --git a/crates/swc_ecma_parser/tests/typescript/arrow-function/const-type-param/input.ts b/crates/swc_ecma_parser/tests/typescript/arrow-function/const-type-param/input.ts new file mode 100644 index 00000000000..11626abaf17 --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript/arrow-function/const-type-param/input.ts @@ -0,0 +1 @@ +export const fn = (payload: Data) => payload; diff --git a/crates/swc_ecma_parser/tests/typescript/arrow-function/const-type-param/input.ts.json b/crates/swc_ecma_parser/tests/typescript/arrow-function/const-type-param/input.ts.json new file mode 100644 index 00000000000..8127f13bac4 --- /dev/null +++ b/crates/swc_ecma_parser/tests/typescript/arrow-function/const-type-param/input.ts.json @@ -0,0 +1,162 @@ +{ + "type": "Module", + "span": { + "start": 1, + "end": 71, + "ctxt": 0 + }, + "body": [ + { + "type": "ExportDeclaration", + "span": { + "start": 1, + "end": 71, + "ctxt": 0 + }, + "declaration": { + "type": "VariableDeclaration", + "span": { + "start": 8, + "end": 71, + "ctxt": 0 + }, + "kind": "const", + "declare": false, + "declarations": [ + { + "type": "VariableDeclarator", + "span": { + "start": 14, + "end": 70, + "ctxt": 0 + }, + "id": { + "type": "Identifier", + "span": { + "start": 14, + "end": 16, + "ctxt": 0 + }, + "value": "fn", + "optional": false, + "typeAnnotation": null + }, + "init": { + "type": "ArrowFunctionExpression", + "span": { + "start": 19, + "end": 70, + "ctxt": 0 + }, + "params": [ + { + "type": "Identifier", + "span": { + "start": 45, + "end": 58, + "ctxt": 0 + }, + "value": "payload", + "optional": false, + "typeAnnotation": { + "type": "TsTypeAnnotation", + "span": { + "start": 52, + "end": 58, + "ctxt": 0 + }, + "typeAnnotation": { + "type": "TsTypeReference", + "span": { + "start": 54, + "end": 58, + "ctxt": 0 + }, + "typeName": { + "type": "Identifier", + "span": { + "start": 54, + "end": 58, + "ctxt": 0 + }, + "value": "Data", + "optional": false + }, + "typeParams": null + } + } + } + ], + "body": { + "type": "Identifier", + "span": { + "start": 63, + "end": 70, + "ctxt": 0 + }, + "value": "payload", + "optional": false + }, + "async": false, + "generator": false, + "typeParameters": { + "type": "TsTypeParameterDeclaration", + "span": { + "start": 19, + "end": 44, + "ctxt": 0 + }, + "parameters": [ + { + "type": "TsTypeParameter", + "span": { + "start": 20, + "end": 43, + "ctxt": 0 + }, + "name": { + "type": "Identifier", + "span": { + "start": 26, + "end": 30, + "ctxt": 0 + }, + "value": "Data", + "optional": false + }, + "in": false, + "out": false, + "const": true, + "constraint": { + "type": "TsTypeReference", + "span": { + "start": 39, + "end": 43, + "ctxt": 0 + }, + "typeName": { + "type": "Identifier", + "span": { + "start": 39, + "end": 43, + "ctxt": 0 + }, + "value": "Type", + "optional": false + }, + "typeParams": null + }, + "default": null + } + ] + }, + "returnType": null + }, + "definite": false + } + ] + } + } + ], + "interpreter": null +} diff --git a/crates/swc_ecma_parser/tests/typescript/variance-annotations/1/input.ts.json b/crates/swc_ecma_parser/tests/typescript/variance-annotations/1/input.ts.json index 685a0c2841d..11898fd8c1a 100644 --- a/crates/swc_ecma_parser/tests/typescript/variance-annotations/1/input.ts.json +++ b/crates/swc_ecma_parser/tests/typescript/variance-annotations/1/input.ts.json @@ -3973,7 +3973,7 @@ "value": "T", "optional": false }, - "in": false, + "in": true, "out": true, "const": false, "constraint": null, @@ -4096,7 +4096,7 @@ "value": "T", "optional": false }, - "in": false, + "in": true, "out": false, "const": false, "constraint": null, @@ -4171,7 +4171,7 @@ "optional": false }, "in": false, - "out": false, + "out": true, "const": false, "constraint": null, "default": null diff --git a/crates/swc_ecma_parser/tests/typescript/variance-annotations/with_jsx/input.tsx.json b/crates/swc_ecma_parser/tests/typescript/variance-annotations/with_jsx/input.tsx.json index 685a0c2841d..11898fd8c1a 100644 --- a/crates/swc_ecma_parser/tests/typescript/variance-annotations/with_jsx/input.tsx.json +++ b/crates/swc_ecma_parser/tests/typescript/variance-annotations/with_jsx/input.tsx.json @@ -3973,7 +3973,7 @@ "value": "T", "optional": false }, - "in": false, + "in": true, "out": true, "const": false, "constraint": null, @@ -4096,7 +4096,7 @@ "value": "T", "optional": false }, - "in": false, + "in": true, "out": false, "const": false, "constraint": null, @@ -4171,7 +4171,7 @@ "optional": false }, "in": false, - "out": false, + "out": true, "const": false, "constraint": null, "default": null