Skip to content

Commit

Permalink
fix(semantic): correctly resolve binding for return type of functions (
Browse files Browse the repository at this point in the history
…#6388)

Fixes #6387.
  • Loading branch information
overlookmotel committed Nov 26, 2024
1 parent b0e1c03 commit f3850eb
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 9 deletions.
32 changes: 23 additions & 9 deletions crates/oxc_semantic/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1655,6 +1655,18 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
if let Some(return_type) = &func.return_type {
self.visit_ts_type_annotation(return_type);
}

if func.params.has_parameter() || func.return_type.is_some() {
// `function foo({bar: identifier_reference}) {}`
// ^^^^^^^^^^^^^^^^^^^^
// `function foo<SomeType>(v: SomeType): SomeType { return v; }`
// ^^^^^^^^ ^^^^^^^^
// Parameter initializers must be resolved after all parameters have been declared.
// Param types and return type must be resolved after type parameters have been declared.
// In both cases, need to avoid binding to variables/types declared inside the function body.
self.resolve_references_for_current_scope();
}

if let Some(body) = &func.body {
self.visit_function_body(body);
}
Expand Down Expand Up @@ -1719,6 +1731,17 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
self.visit_ts_type_annotation(return_type);
}

if expr.params.has_parameter() || expr.return_type.is_some() {
// `let foo = ({bar: identifier_reference}) => {};`
// ^^^^^^^^^^^^^^^^^^^^
// `let foo = <SomeType>(v: SomeType): SomeType => v;`
// ^^^^^^^^ ^^^^^^^^
// Parameter initializers must be resolved after all parameters have been declared.
// Param types and return type must be resolved after type parameters have been declared.
// In both cases, need to avoid binding to variables/types declared inside the function body.
self.resolve_references_for_current_scope();
}

self.visit_function_body(&expr.body);

/* cfg */
Expand Down Expand Up @@ -2021,15 +2044,6 @@ impl<'a> SemanticBuilder<'a> {
AstKind::Function(_) | AstKind::ArrowFunctionExpression(_) => {
self.function_stack.pop();
}
AstKind::FormalParameters(parameters) => {
if parameters.kind != FormalParameterKind::Signature && parameters.has_parameter() {
// `function foo({bar: identifier_reference}) {}`
// ^^^^^^^^^^^^^^^^^^^^ Parameter initializer must be resolved
// after all parameters have been declared
// to avoid binding to variables inside the scope
self.resolve_references_for_current_scope();
}
}
AstKind::CatchParameter(_) => {
self.resolve_references_for_current_scope();
}
Expand Down
102 changes: 102 additions & 0 deletions crates/oxc_semantic/tests/fixtures/oxc/ts/functions/return-type.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
source: crates/oxc_semantic/tests/main.rs
input_file: crates/oxc_semantic/tests/fixtures/oxc/ts/functions/return-type.ts
---
[
{
"children": [
{
"children": [],
"flags": "ScopeFlags(StrictMode)",
"id": 1,
"node": "TSTypeAliasDeclaration",
"symbols": []
},
{
"children": [
{
"children": [],
"flags": "ScopeFlags(StrictMode)",
"id": 3,
"node": "TSTypeAliasDeclaration",
"symbols": []
}
],
"flags": "ScopeFlags(StrictMode | Function)",
"id": 2,
"node": "Function(Foo)",
"symbols": [
{
"flags": "SymbolFlags(TypeAlias)",
"id": 2,
"name": "T",
"node": "TSTypeAliasDeclaration",
"references": []
}
]
},
{
"children": [
{
"children": [],
"flags": "ScopeFlags(StrictMode)",
"id": 5,
"node": "TSTypeAliasDeclaration",
"symbols": []
}
],
"flags": "ScopeFlags(StrictMode | Function | Arrow)",
"id": 4,
"node": "ArrowFunctionExpression",
"symbols": [
{
"flags": "SymbolFlags(TypeAlias)",
"id": 4,
"name": "T",
"node": "TSTypeAliasDeclaration",
"references": []
}
]
}
],
"flags": "ScopeFlags(StrictMode | Top)",
"id": 0,
"node": "Program",
"symbols": [
{
"flags": "SymbolFlags(TypeAlias)",
"id": 0,
"name": "T",
"node": "TSTypeAliasDeclaration",
"references": [
{
"flags": "ReferenceFlags(Type)",
"id": 0,
"name": "T",
"node_id": 12
},
{
"flags": "ReferenceFlags(Type)",
"id": 1,
"name": "T",
"node_id": 27
}
]
},
{
"flags": "SymbolFlags(BlockScopedVariable | Function)",
"id": 1,
"name": "Foo",
"node": "Function(Foo)",
"references": []
},
{
"flags": "SymbolFlags(BlockScopedVariable | ConstVariable)",
"id": 3,
"name": "Bar",
"node": "VariableDeclarator(Bar)",
"references": []
}
]
}
]
12 changes: 12 additions & 0 deletions crates/oxc_semantic/tests/fixtures/oxc/ts/functions/return-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type T = number;

function Foo(): T {
type T = string;
return 0;
}

const Bar = (): T => {
type T = string;
return 0;
}

0 comments on commit f3850eb

Please sign in to comment.