Repository: swc-project/swc (rust)

Issue:
Issue parsing arrow function expression return types
**Describe the bug**

The parser seems to have issues with arrow function expression return types.

**Input code**

Examples:

```ts
Array(5).fill(0).map((_, i): true => {
    return true
});
```

```ts
Array(5).fill(0).map((_, i): ({ loading: false }) => ({
    loading: false,
}));
```

https://swc.rs/repl#%7B%22rawCode%22%3A%22Array(5).fill(0).map((_%2C%20i)%3A%20(%7B%20loading%3A%20false%20%7D)%20%3D%3E%20(%7B%5Cn%20%20%20%20loading%3A%20false%2C%5Cn%7D))%3B%22%2C%22rawConfig%22%3A%22%7B%7D%22%7D

**Expected behavior**

It parses.

**Version**

swc_ecmascript 0.57, but I see it happening still in the playground in the above link.

Pull request:
fix(parser): Fix `skip_ts_parameter_start` (#2160)
fixes #2160 

Patch:
diff --git a/crates/swc_ecma_parser/src/parser/typescript.rs b/crates/swc_ecma_parser/src/parser/typescript.rs
index 25f5ef3878..f72f3ed9c3 100644
--- a/crates/swc_ecma_parser/src/parser/typescript.rs
+++ b/crates/swc_ecma_parser/src/parser/typescript.rs
@@ -1110,34 +1110,10 @@ impl<I: Tokens> Parser<I> {
             return Ok(true);
         }
 
-        if is!(self, '{') {
-            let mut brace_stack_counter = 1;
-            bump!(self);
-
-            while brace_stack_counter > 0 {
-                if is!(self, '{') {
-                    brace_stack_counter += 1;
-                } else if is!(self, '}') {
-                    brace_stack_counter -= 1;
-                }
-                bump!(self);
-            }
-            return Ok(true);
-        }
-
-        if is!(self, '[') {
-            let mut bracket_stack_counter = 1;
-            bump!(self);
-
-            while bracket_stack_counter > 0 {
-                if is!(self, '[') {
-                    bracket_stack_counter += 1;
-                } else if is!(self, ']') {
-                    bracket_stack_counter -= 1;
-                }
-                bump!(self);
+        if (is!(self, '{') || is!(self, '[')) {
+            if self.parse_binding_pat_or_ident().is_ok() {
+                return Ok(true);
             }
-            return Ok(true);
         }
 
         Ok(false)


Test patch:
diff --git a/crates/swc_ecma_parser/tests/typescript/issue-2160/case1/input.ts b/crates/swc_ecma_parser/tests/typescript/issue-2160/case1/input.ts
new file mode 100644
index 0000000000..3bde4ae3bd
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/typescript/issue-2160/case1/input.ts
@@ -0,0 +1,3 @@
+Array(5).fill(0).map((_, i): ({ loading: false }) => ({
+    loading: false,
+}));
diff --git a/crates/swc_ecma_parser/tests/typescript/issue-2160/case1/input.ts.json b/crates/swc_ecma_parser/tests/typescript/issue-2160/case1/input.ts.json
new file mode 100644
index 0000000000..c250b97b2d
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/typescript/issue-2160/case1/input.ts.json
@@ -0,0 +1,277 @@
+{
+  "type": "Script",
+  "span": {
+    "start": 0,
+    "end": 80,
+    "ctxt": 0
+  },
+  "body": [
+    {
+      "type": "ExpressionStatement",
+      "span": {
+        "start": 0,
+        "end": 80,
+        "ctxt": 0
+      },
+      "expression": {
+        "type": "CallExpression",
+        "span": {
+          "start": 0,
+          "end": 79,
+          "ctxt": 0
+        },
+        "callee": {
+          "type": "MemberExpression",
+          "span": {
+            "start": 0,
+            "end": 20,
+            "ctxt": 0
+          },
+          "object": {
+            "type": "CallExpression",
+            "span": {
+              "start": 0,
+              "end": 16,
+              "ctxt": 0
+            },
+            "callee": {
+              "type": "MemberExpression",
+              "span": {
+                "start": 0,
+                "end": 13,
+                "ctxt": 0
+              },
+              "object": {
+                "type": "CallExpression",
+                "span": {
+                  "start": 0,
+                  "end": 8,
+                  "ctxt": 0
+                },
+                "callee": {
+                  "type": "Identifier",
+                  "span": {
+                    "start": 0,
+                    "end": 5,
+                    "ctxt": 0
+                  },
+                  "value": "Array",
+                  "optional": false
+                },
+                "arguments": [
+                  {
+                    "spread": null,
+                    "expression": {
+                      "type": "NumericLiteral",
+                      "span": {
+                        "start": 6,
+                        "end": 7,
+                        "ctxt": 0
+                      },
+                      "value": 5.0
+                    }
+                  }
+                ],
+                "typeArguments": null
+              },
+              "property": {
+                "type": "Identifier",
+                "span": {
+                  "start": 9,
+                  "end": 13,
+                  "ctxt": 0
+                },
+                "value": "fill",
+                "optional": false
+              },
+              "computed": false
+            },
+            "arguments": [
+              {
+                "spread": null,
+                "expression": {
+                  "type": "NumericLiteral",
+                  "span": {
+                    "start": 14,
+                    "end": 15,
+                    "ctxt": 0
+                  },
+                  "value": 0.0
+                }
+              }
+            ],
+            "typeArguments": null
+          },
+          "property": {
+            "type": "Identifier",
+            "span": {
+              "start": 17,
+              "end": 20,
+              "ctxt": 0
+            },
+            "value": "map",
+            "optional": false
+          },
+          "computed": false
+        },
+        "arguments": [
+          {
+            "spread": null,
+            "expression": {
+              "type": "ArrowFunctionExpression",
+              "span": {
+                "start": 21,
+                "end": 78,
+                "ctxt": 0
+              },
+              "params": [
+                {
+                  "type": "Identifier",
+                  "span": {
+                    "start": 22,
+                    "end": 23,
+                    "ctxt": 0
+                  },
+                  "value": "_",
+                  "optional": false,
+                  "typeAnnotation": null
+                },
+                {
+                  "type": "Identifier",
+                  "span": {
+                    "start": 25,
+                    "end": 26,
+                    "ctxt": 0
+                  },
+                  "value": "i",
+                  "optional": false,
+                  "typeAnnotation": null
+                }
+              ],
+              "body": {
+                "type": "ParenthesisExpression",
+                "span": {
+                  "start": 53,
+                  "end": 78,
+                  "ctxt": 0
+                },
+                "expression": {
+                  "type": "ObjectExpression",
+                  "span": {
+                    "start": 54,
+                    "end": 77,
+                    "ctxt": 0
+                  },
+                  "properties": [
+                    {
+                      "type": "KeyValueProperty",
+                      "key": {
+                        "type": "Identifier",
+                        "span": {
+                          "start": 60,
+                          "end": 67,
+                          "ctxt": 0
+                        },
+                        "value": "loading",
+                        "optional": false
+                      },
+                      "value": {
+                        "type": "BooleanLiteral",
+                        "span": {
+                          "start": 69,
+                          "end": 74,
+                          "ctxt": 0
+                        },
+                        "value": false
+                      }
+                    }
+                  ]
+                }
+              },
+              "async": false,
+              "generator": false,
+              "typeParameters": null,
+              "returnType": {
+                "type": "TsTypeAnnotation",
+                "span": {
+                  "start": 27,
+                  "end": 49,
+                  "ctxt": 0
+                },
+                "typeAnnotation": {
+                  "type": "TsParenthesizedType",
+                  "span": {
+                    "start": 29,
+                    "end": 49,
+                    "ctxt": 0
+                  },
+                  "typeAnnotation": {
+                    "type": "TsTypeLiteral",
+                    "span": {
+                      "start": 30,
+                      "end": 48,
+                      "ctxt": 0
+                    },
+                    "members": [
+                      {
+                        "type": "TsPropertySignature",
+                        "span": {
+                          "start": 32,
+                          "end": 46,
+                          "ctxt": 0
+                        },
+                        "readonly": false,
+                        "key": {
+                          "type": "Identifier",
+                          "span": {
+                            "start": 32,
+                            "end": 39,
+                            "ctxt": 0
+                          },
+                          "value": "loading",
+                          "optional": false
+                        },
+                        "computed": false,
+                        "optional": false,
+                        "init": null,
+                        "params": [],
+                        "typeAnnotation": {
+                          "type": "TsTypeAnnotation",
+                          "span": {
+                            "start": 39,
+                            "end": 46,
+                            "ctxt": 0
+                          },
+                          "typeAnnotation": {
+                            "type": "TsLiteralType",
+                            "span": {
+                              "start": 41,
+                              "end": 46,
+                              "ctxt": 0
+                            },
+                            "literal": {
+                              "type": "BooleanLiteral",
+                              "span": {
+                                "start": 41,
+                                "end": 46,
+                                "ctxt": 0
+                              },
+                              "value": false
+                            }
+                          }
+                        },
+                        "typeParams": null
+                      }
+                    ]
+                  }
+                }
+              }
+            }
+          }
+        ],
+        "typeArguments": null
+      }
+    }
+  ],
+  "interpreter": null
+}
diff --git a/crates/swc_ecma_parser/tests/typescript/issue-2160/case2/input.ts b/crates/swc_ecma_parser/tests/typescript/issue-2160/case2/input.ts
new file mode 100644
index 0000000000..016c656d9d
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/typescript/issue-2160/case2/input.ts
@@ -0,0 +1,1 @@
+[0].map((_): ({ a: true }) => ({ a: true }));
diff --git a/crates/swc_ecma_parser/tests/typescript/issue-2160/case2/input.ts.json b/crates/swc_ecma_parser/tests/typescript/issue-2160/case2/input.ts.json
new file mode 100644
index 0000000000..9656dc3aec
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/typescript/issue-2160/case2/input.ts.json
@@ -0,0 +1,213 @@
+{
+  "type": "Script",
+  "span": {
+    "start": 0,
+    "end": 45,
+    "ctxt": 0
+  },
+  "body": [
+    {
+      "type": "ExpressionStatement",
+      "span": {
+        "start": 0,
+        "end": 45,
+        "ctxt": 0
+      },
+      "expression": {
+        "type": "CallExpression",
+        "span": {
+          "start": 0,
+          "end": 44,
+          "ctxt": 0
+        },
+        "callee": {
+          "type": "MemberExpression",
+          "span": {
+            "start": 0,
+            "end": 7,
+            "ctxt": 0
+          },
+          "object": {
+            "type": "ArrayExpression",
+            "span": {
+              "start": 0,
+              "end": 3,
+              "ctxt": 0
+            },
+            "elements": [
+              {
+                "spread": null,
+                "expression": {
+                  "type": "NumericLiteral",
+                  "span": {
+                    "start": 1,
+                    "end": 2,
+                    "ctxt": 0
+                  },
+                  "value": 0.0
+                }
+              }
+            ]
+          },
+          "property": {
+            "type": "Identifier",
+            "span": {
+              "start": 4,
+              "end": 7,
+              "ctxt": 0
+            },
+            "value": "map",
+            "optional": false
+          },
+          "computed": false
+        },
+        "arguments": [
+          {
+            "spread": null,
+            "expression": {
+              "type": "ArrowFunctionExpression",
+              "span": {
+                "start": 8,
+                "end": 43,
+                "ctxt": 0
+              },
+              "params": [
+                {
+                  "type": "Identifier",
+                  "span": {
+                    "start": 9,
+                    "end": 10,
+                    "ctxt": 0
+                  },
+                  "value": "_",
+                  "optional": false,
+                  "typeAnnotation": null
+                }
+              ],
+              "body": {
+                "type": "ParenthesisExpression",
+                "span": {
+                  "start": 30,
+                  "end": 43,
+                  "ctxt": 0
+                },
+                "expression": {
+                  "type": "ObjectExpression",
+                  "span": {
+                    "start": 31,
+                    "end": 42,
+                    "ctxt": 0
+                  },
+                  "properties": [
+                    {
+                      "type": "KeyValueProperty",
+                      "key": {
+                        "type": "Identifier",
+                        "span": {
+                          "start": 33,
+                          "end": 34,
+                          "ctxt": 0
+                        },
+                        "value": "a",
+                        "optional": false
+                      },
+                      "value": {
+                        "type": "BooleanLiteral",
+                        "span": {
+                          "start": 36,
+                          "end": 40,
+                          "ctxt": 0
+                        },
+                        "value": true
+                      }
+                    }
+                  ]
+                }
+              },
+              "async": false,
+              "generator": false,
+              "typeParameters": null,
+              "returnType": {
+                "type": "TsTypeAnnotation",
+                "span": {
+                  "start": 11,
+                  "end": 26,
+                  "ctxt": 0
+                },
+                "typeAnnotation": {
+                  "type": "TsParenthesizedType",
+                  "span": {
+                    "start": 13,
+                    "end": 26,
+                    "ctxt": 0
+                  },
+                  "typeAnnotation": {
+                    "type": "TsTypeLiteral",
+                    "span": {
+                      "start": 14,
+                      "end": 25,
+                      "ctxt": 0
+                    },
+                    "members": [
+                      {
+                        "type": "TsPropertySignature",
+                        "span": {
+                          "start": 16,
+                          "end": 23,
+                          "ctxt": 0
+                        },
+                        "readonly": false,
+                        "key": {
+                          "type": "Identifier",
+                          "span": {
+                            "start": 16,
+                            "end": 17,
+                            "ctxt": 0
+                          },
+                          "value": "a",
+                          "optional": false
+                        },
+                        "computed": false,
+                        "optional": false,
+                        "init": null,
+                        "params": [],
+                        "typeAnnotation": {
+                          "type": "TsTypeAnnotation",
+                          "span": {
+                            "start": 17,
+                            "end": 23,
+                            "ctxt": 0
+                          },
+                          "typeAnnotation": {
+                            "type": "TsLiteralType",
+                            "span": {
+                              "start": 19,
+                              "end": 23,
+                              "ctxt": 0
+                            },
+                            "literal": {
+                              "type": "BooleanLiteral",
+                              "span": {
+                                "start": 19,
+                                "end": 23,
+                                "ctxt": 0
+                              },
+                              "value": true
+                            }
+                          }
+                        },
+                        "typeParams": null
+                      }
+                    ]
+                  }
+                }
+              }
+            }
+          }
+        ],
+        "typeArguments": null
+      }
+    }
+  ],
+  "interpreter": null
+}
diff --git a/crates/swc_ecma_parser/tests/typescript/issue-2160/case3/input.ts b/crates/swc_ecma_parser/tests/typescript/issue-2160/case3/input.ts
new file mode 100644
index 0000000000..f7a0e3d4c7
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/typescript/issue-2160/case3/input.ts
@@ -0,0 +1,1 @@
+[0].map((_): ([a: true]) => [true]);
diff --git a/crates/swc_ecma_parser/tests/typescript/issue-2160/case3/input.ts.json b/crates/swc_ecma_parser/tests/typescript/issue-2160/case3/input.ts.json
new file mode 100644
index 0000000000..75df0248c6
--- /dev/null
+++ b/crates/swc_ecma_parser/tests/typescript/issue-2160/case3/input.ts.json
@@ -0,0 +1,182 @@
+{
+  "type": "Script",
+  "span": {
+    "start": 0,
+    "end": 36,
+    "ctxt": 0
+  },
+  "body": [
+    {
+      "type": "ExpressionStatement",
+      "span": {
+        "start": 0,
+        "end": 36,
+        "ctxt": 0
+      },
+      "expression": {
+        "type": "CallExpression",
+        "span": {
+          "start": 0,
+          "end": 35,
+          "ctxt": 0
+        },
+        "callee": {
+          "type": "MemberExpression",
+          "span": {
+            "start": 0,
+            "end": 7,
+            "ctxt": 0
+          },
+          "object": {
+            "type": "ArrayExpression",
+            "span": {
+              "start": 0,
+              "end": 3,
+              "ctxt": 0
+            },
+            "elements": [
+              {
+                "spread": null,
+                "expression": {
+                  "type": "NumericLiteral",
+                  "span": {
+                    "start": 1,
+                    "end": 2,
+                    "ctxt": 0
+                  },
+                  "value": 0.0
+                }
+              }
+            ]
+          },
+          "property": {
+            "type": "Identifier",
+            "span": {
+              "start": 4,
+              "end": 7,
+              "ctxt": 0
+            },
+            "value": "map",
+            "optional": false
+          },
+          "computed": false
+        },
+        "arguments": [
+          {
+            "spread": null,
+            "expression": {
+              "type": "ArrowFunctionExpression",
+              "span": {
+                "start": 8,
+                "end": 34,
+                "ctxt": 0
+              },
+              "params": [
+                {
+                  "type": "Identifier",
+                  "span": {
+                    "start": 9,
+                    "end": 10,
+                    "ctxt": 0
+                  },
+                  "value": "_",
+                  "optional": false,
+                  "typeAnnotation": null
+                }
+              ],
+              "body": {
+                "type": "ArrayExpression",
+                "span": {
+                  "start": 28,
+                  "end": 34,
+                  "ctxt": 0
+                },
+                "elements": [
+                  {
+                    "spread": null,
+                    "expression": {
+                      "type": "BooleanLiteral",
+                      "span": {
+                        "start": 29,
+                        "end": 33,
+                        "ctxt": 0
+                      },
+                      "value": true
+                    }
+                  }
+                ]
+              },
+              "async": false,
+              "generator": false,
+              "typeParameters": null,
+              "returnType": {
+                "type": "TsTypeAnnotation",
+                "span": {
+                  "start": 11,
+                  "end": 24,
+                  "ctxt": 0
+                },
+                "typeAnnotation": {
+                  "type": "TsParenthesizedType",
+                  "span": {
+                    "start": 13,
+                    "end": 24,
+                    "ctxt": 0
+                  },
+                  "typeAnnotation": {
+                    "type": "TsTupleType",
+                    "span": {
+                      "start": 14,
+                      "end": 23,
+                      "ctxt": 0
+                    },
+                    "elemTypes": [
+                      {
+                        "type": "TsTupleElement",
+                        "span": {
+                          "start": 15,
+                          "end": 22,
+                          "ctxt": 0
+                        },
+                        "label": {
+                          "type": "Identifier",
+                          "span": {
+                            "start": 15,
+                            "end": 16,
+                            "ctxt": 0
+                          },
+                          "value": "a",
+                          "optional": false,
+                          "typeAnnotation": null
+                        },
+                        "ty": {
+                          "type": "TsLiteralType",
+                          "span": {
+                            "start": 18,
+                            "end": 22,
+                            "ctxt": 0
+                          },
+                          "literal": {
+                            "type": "BooleanLiteral",
+                            "span": {
+                              "start": 18,
+                              "end": 22,
+                              "ctxt": 0
+                            },
+                            "value": true
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            }
+          }
+        ],
+        "typeArguments": null
+      }
+    }
+  ],
+  "interpreter": null
+}