diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index 5c68400be0e19..74f4fa7774547 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -2013,7 +2013,19 @@ impl<'a> SemanticBuilder<'a> { for node in self.nodes.iter_parents(self.current_node_id).skip(1) { return match node.kind() { AstKind::ParenthesizedExpression(_) => continue, - AstKind::ExpressionStatement(_) => false, + AstKind::ExpressionStatement(_) => { + if self.current_scope_flags().is_arrow() { + if let Some(node) = self.nodes.iter_parents(node.id()).nth(2) { + // (x) => x++ + // ^^^ implicit return, we need to treat `x` as a read reference + if matches!(node.kind(), AstKind::ArrowFunctionExpression(arrow) if arrow.expression) + { + return true; + } + } + } + false + } _ => true, }; } diff --git a/crates/oxc_semantic/tests/integration/symbols.rs b/crates/oxc_semantic/tests/integration/symbols.rs index baef2aa92d7f7..76a061b5f8ace 100644 --- a/crates/oxc_semantic/tests/integration/symbols.rs +++ b/crates/oxc_semantic/tests/integration/symbols.rs @@ -372,3 +372,57 @@ fn test_ts_interface_heritage() { .has_number_of_references(1) .test(); } + +#[test] +fn test_arrow_implicit_return() { + SemanticTester::js("let i = 0; const x = () => i") + .has_root_symbol("i") + .has_number_of_reads(1) + .has_number_of_writes(0) + .test(); + + SemanticTester::js("let i = 0; const x = () => ++i") + .has_root_symbol("i") + .has_number_of_reads(1) + .has_number_of_writes(1) + .test(); + + SemanticTester::js("let i = 0; const x = () => { ++i }") + .has_root_symbol("i") + .has_number_of_reads(0) + .has_number_of_writes(1) + .test(); + + SemanticTester::js("let i = 0; const x = () => (0, ++i)") + .has_root_symbol("i") + .has_number_of_reads(1) + .has_number_of_writes(1) + .test(); + + SemanticTester::js("let i = 0; const x = () => (++i, 0)") + .has_root_symbol("i") + .has_number_of_reads(1) + .has_number_of_writes(1) + .test(); + + SemanticTester::js("let i = 1; const foo = () => () => { i++ }") + .has_root_symbol("i") + .has_number_of_reads(0) + .has_number_of_writes(1) + .test(); +} + +#[test] +fn test_arrow_explicit_return() { + SemanticTester::js("let i = 0; const x = () => { return i }") + .has_root_symbol("i") + .has_number_of_reads(1) + .has_number_of_writes(0) + .test(); + + SemanticTester::js("let i = 0; const x = () => { return ++i }") + .has_root_symbol("i") + .has_number_of_reads(1) + .has_number_of_writes(1) + .test(); +}