fix(semantic): stop arguments resolution at ordinary functions (#26929)

Keep references to an ordinary function’s implicit `arguments` object unresolved when an outer scope declares `arguments`. Preserve explicit local bindings, arrow-function inheritance, and type-only resolution. A function expression’s own name is skipped, because it lies outside the function’s arguments environment.

The async-to-generator wrapper looked `arguments` up by name, which bound it to an outer declaration and made the transformer’s scoping disagree with a rebuild in two Test262 cases. It now creates an unbound reference. Emitted JavaScript is unchanged. This folds in #26933.

References named `arguments` are resolved in a separate cold function, so the ordinary scope walk is unchanged.

## Example

In sloppy mode (a classic script or CommonJS):

```js
function h() {
  {
    let arguments = 1;
    return function () {
      return arguments[0];
    };
  }
}
console.log(h()(2));
```

This prints `2`, because the inner function reads its own arguments object. Before, the minifier inlined the outer binding into it, and the output printed `undefined`:

```js
function h() {
	return function() {
		return 1[0];
	};
}
console.log(h()(2));
```

After, the outer `let` is unused and removed, and the output prints `2`:

```js
function h() {
	return function() {
		return arguments[0];
	};
}
console.log(h()(2));
```

New fixtures cover a function expression named `arguments`, class members, catch parameters, a function inside a default parameter, writes, `var arguments`, and TypeScript signatures. The conformance and transform conformance snapshots are unchanged.

Fixes #23844.
This commit is contained in:
camc314 committed 2026-10-12 02:29:02 +00:00
1 parent 1f1d7eae2e
commit f8e9a50c20
13 files changed
+1279 -6

No files matched your search

@@ -647,3 +647,38 @@ fn small_value() {
&options,
);
}
// https://github.com/oxc-project/oxc/issues/23844
// An ordinary function reads its own arguments object, so an outer binding
// named `arguments` must not be inlined into it.
#[test]
fn outer_arguments_binding_not_inlined_into_function() {
let options = CompressOptions::smallest();
// Outer block `let`.
test_options_source_type(
"use(function () { { let arguments = 1; return function () { return arguments[0]; }; } });",
"use(function () { return function () { return arguments[0]; }; });",
SourceType::cjs(),
&options,
);
// Outer `var` in an enclosing function.
test_options_source_type(
"use(function () { var arguments = 1; return function () { return arguments[0]; }; });",
"use(function () { return function () { return arguments[0]; }; });",
SourceType::cjs(),
&options,
);
// Top-level `const` in CommonJS and in a script.
test_options_source_type(
"const arguments = 1; use(function () { return arguments[0]; });",
"use(function () { return arguments[0]; });",
SourceType::cjs(),
&options,
);
test_options_source_type(
"const arguments = 1; use(function () { return arguments[0]; });",
"const arguments = 1; use(function () { return arguments[0]; });",
SourceType::cjs().with_script(true),
&options,
);
}
+63 -2
View File
@@ -644,13 +644,30 @@ impl<'a> SemanticBuilder<'a> {
let root_scope_id = self.scoping.root_scope_id();
let refs = self.unresolved_references.take();
for unresolved in refs {
if !self.walk_up_resolve_reference(unresolved, root_scope_id) {
if !self.resolve_reference(unresolved, root_scope_id) {
self.scoping
.add_root_unresolved_reference(unresolved.name, unresolved.reference_id);
}
}
}
/// Resolve a reference by walking up the scope chain through `last_scope_id`.
///
/// Returns `true` when lookup is finished: the reference is resolved, or it belongs to an
/// implicit arguments object.
#[expect(clippy::inline_always, reason = "Hot path — called for every reference resolution")]
#[inline(always)]
fn resolve_reference(
&mut self,
unresolved: UnresolvedReference<'a>,
last_scope_id: ScopeId,
) -> bool {
if unresolved.name == "arguments" {
return self.resolve_arguments_reference(unresolved, last_scope_id);
}
self.walk_up_resolve_reference(unresolved, last_scope_id)
}
/// Walk up the scope chain through `last_scope_id`.
#[expect(clippy::inline_always, reason = "Hot path — called for every reference resolution")]
#[inline(always)]
@@ -674,6 +691,50 @@ impl<'a> SemanticBuilder<'a> {
false
}
/// Resolve a reference named `arguments`.
///
/// An ordinary function has an implicit arguments object, which has no symbol. A value
/// reference therefore ends its lookup at the nearest ordinary function. Unless a parameter
/// or declaration of that function binds the name, the reference is recorded as a root
/// unresolved reference, so it never resolves to a binding outside the function.
///
/// Returns `true` when lookup is finished.
#[cold]
#[inline(never)]
fn resolve_arguments_reference(
&mut self,
unresolved: UnresolvedReference<'a>,
last_scope_id: ScopeId,
) -> bool {
// A type named `arguments` is an ordinary type binding.
let flags = self.scoping.get_reference(unresolved.reference_id).flags();
if !flags.intersects(ReferenceFlags::Value | ReferenceFlags::ValueAsType) {
return self.walk_up_resolve_reference(unresolved, last_scope_id);
}
let mut current_scope_id = Some(unresolved.lookup_scope_id);
while let Some(scope_id) = current_scope_id {
if let Some(symbol_id) = self.scoping.get_binding(scope_id, unresolved.name)
// A function expression's own name lies outside its arguments environment.
&& !self.scoping.symbol_flags(symbol_id).contains(SymbolFlags::FunctionExpression)
&& self.try_resolve_reference(unresolved.reference_id, symbol_id)
{
return true;
}
let scope_flags = self.scoping.scope_flags(scope_id);
if scope_flags.is_function() && !scope_flags.is_arrow() {
self.scoping
.add_root_unresolved_reference(unresolved.name, unresolved.reference_id);
return true;
}
if scope_id == last_scope_id {
return false;
}
current_scope_id = self.scoping.scope_parent_id(scope_id);
}
false
}
/// Try to resolve a reference to a symbol. Returns `true` if resolved.
fn try_resolve_reference(&mut self, reference_id: ReferenceId, symbol_id: SymbolId) -> bool {
let symbol_flags = self.scoping.symbol_flags(symbol_id);
@@ -762,7 +823,7 @@ impl<'a> SemanticBuilder<'a> {
{
return true;
}
if self.walk_up_resolve_reference(*unresolved, current_scope_id) {
if self.resolve_reference(*unresolved, current_scope_id) {
return false;
}
// Skip this function body during final resolution. An enclosing parameter resolution
+5
View File
@@ -913,6 +913,11 @@ impl Scoping {
///
/// Bindings are resolved by walking up the scope tree until a binding is
/// found. If no binding is found, [`None`] is returned.
///
/// This lookup does not model the implicit `arguments` object. It walks past
/// function boundaries, so `arguments` can resolve to a binding in an outer
/// scope. A transform that needs a function's own `arguments` must create an
/// unbound reference instead of looking the name up.
pub fn find_binding(&self, mut scope_id: ScopeId, name: Ident<'_>) -> Option<SymbolId> {
let cell = self.cell.borrow_dependent();
loop {
@@ -0,0 +1,37 @@
function classMembers(arguments) {
return class {
constructor() {
arguments;
}
get getter() {
return arguments;
}
static method() {
arguments;
}
};
}
function catchParameter() {
try {
} catch (arguments) {
arguments;
return function inner() {
arguments;
};
}
}
function defaultFunction(value = function inner() { arguments; }) {
let arguments;
arguments;
}
function writes(arguments) {
return function inner() {
arguments = 1;
arguments++;
};
}
function sloppyVar() {
var arguments;
arguments;
return () => arguments;
}
@@ -0,0 +1,272 @@
---
source: crates/oxc_semantic/tests/main.rs
input_file: crates/oxc_semantic/tests/fixtures/oxc/arguments/enclosing-bindings.js
---
[
{
"children": [
{
"children": [
{
"children": [
{
"children": [],
"flags": "ScopeFlags(StrictMode | Function | Constructor)",
"id": 3,
"node": "Function(<anonymous>)",
"symbols": []
},
{
"children": [],
"flags": "ScopeFlags(StrictMode | Function | GetAccessor)",
"id": 4,
"node": "Function(<anonymous>)",
"symbols": []
},
{
"children": [],
"flags": "ScopeFlags(StrictMode | Function)",
"id": 5,
"node": "Function(<anonymous>)",
"symbols": []
}
],
"flags": "ScopeFlags(StrictMode)",
"id": 2,
"node": "Class(<anonymous>)",
"symbols": []
}
],
"flags": "ScopeFlags(Function)",
"id": 1,
"node": "Function(classMembers)",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 1,
"name": "arguments",
"node": "FormalParameter(arguments)",
"references": []
}
]
},
{
"children": [
{
"children": [],
"flags": "ScopeFlags(0x0)",
"id": 7,
"node": "BlockStatement",
"symbols": []
},
{
"children": [
{
"children": [
{
"children": [],
"flags": "ScopeFlags(Function)",
"id": 10,
"node": "Function(inner)",
"symbols": [
{
"flags": "SymbolFlags(Function | FunctionExpression)",
"id": 4,
"name": "inner",
"node": "Function(inner)",
"references": []
}
]
}
],
"flags": "ScopeFlags(0x0)",
"id": 9,
"node": "BlockStatement",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable | CatchVariable)",
"id": 3,
"name": "arguments",
"node": "CatchParameter",
"references": [
{
"flags": "ReferenceFlags(Read)",
"id": 3,
"name": "arguments",
"node_id": 42,
"scope_id": 9
}
]
}
]
}
],
"flags": "ScopeFlags(CatchClause)",
"id": 8,
"node": "CatchClause",
"symbols": []
}
],
"flags": "ScopeFlags(Function)",
"id": 6,
"node": "Function(catchParameter)",
"symbols": []
},
{
"children": [
{
"children": [],
"flags": "ScopeFlags(Function)",
"id": 12,
"node": "Function(inner)",
"symbols": [
{
"flags": "SymbolFlags(Function | FunctionExpression)",
"id": 7,
"name": "inner",
"node": "Function(inner)",
"references": []
}
]
}
],
"flags": "ScopeFlags(Function)",
"id": 11,
"node": "Function(defaultFunction)",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 6,
"name": "value",
"node": "FormalParameter(value)",
"references": []
},
{
"flags": "SymbolFlags(BlockScopedVariable)",
"id": 8,
"name": "arguments",
"node": "VariableDeclarator(arguments)",
"references": [
{
"flags": "ReferenceFlags(Read)",
"id": 6,
"name": "arguments",
"node_id": 66,
"scope_id": 11
}
]
}
]
},
{
"children": [
{
"children": [],
"flags": "ScopeFlags(Function)",
"id": 14,
"node": "Function(inner)",
"symbols": [
{
"flags": "SymbolFlags(Function | FunctionExpression)",
"id": 11,
"name": "inner",
"node": "Function(inner)",
"references": []
}
]
}
],
"flags": "ScopeFlags(Function)",
"id": 13,
"node": "Function(writes)",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 10,
"name": "arguments",
"node": "FormalParameter(arguments)",
"references": []
}
]
},
{
"children": [
{
"children": [],
"flags": "ScopeFlags(Function | Arrow)",
"id": 16,
"node": "ArrowFunctionExpression",
"symbols": []
}
],
"flags": "ScopeFlags(Function)",
"id": 15,
"node": "Function(sloppyVar)",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 13,
"name": "arguments",
"node": "VariableDeclarator(arguments)",
"references": [
{
"flags": "ReferenceFlags(Read)",
"id": 9,
"name": "arguments",
"node_id": 93,
"scope_id": 15
},
{
"flags": "ReferenceFlags(Read)",
"id": 10,
"name": "arguments",
"node_id": 97,
"scope_id": 16
}
]
}
]
}
],
"flags": "ScopeFlags(Top)",
"id": 0,
"node": "Program",
"symbols": [
{
"flags": "SymbolFlags(Function)",
"id": 0,
"name": "classMembers",
"node": "Function(classMembers)",
"references": []
},
{
"flags": "SymbolFlags(Function)",
"id": 2,
"name": "catchParameter",
"node": "Function(catchParameter)",
"references": []
},
{
"flags": "SymbolFlags(Function)",
"id": 5,
"name": "defaultFunction",
"node": "Function(defaultFunction)",
"references": []
},
{
"flags": "SymbolFlags(Function)",
"id": 9,
"name": "writes",
"node": "Function(writes)",
"references": []
},
{
"flags": "SymbolFlags(Function)",
"id": 12,
"name": "sloppyVar",
"node": "Function(sloppyVar)",
"references": []
}
]
}
]
@@ -0,0 +1,28 @@
const arguments = [];
function direct() {
return function arguments() {
arguments;
};
}
function throughArrow() {
return function arguments() {
return () => arguments;
};
}
function inDefault() {
return function arguments(value = arguments) {};
}
function withParameter() {
return function arguments(arguments) {
arguments;
return () => arguments;
};
}
function withVar() {
return function arguments() {
var arguments;
arguments;
return () => arguments;
};
}
@@ -0,0 +1,233 @@
---
source: crates/oxc_semantic/tests/main.rs
input_file: crates/oxc_semantic/tests/fixtures/oxc/arguments/function-expression-name.js
---
[
{
"children": [
{
"children": [
{
"children": [],
"flags": "ScopeFlags(Function)",
"id": 2,
"node": "Function(arguments)",
"symbols": [
{
"flags": "SymbolFlags(Function | FunctionExpression)",
"id": 2,
"name": "arguments",
"node": "Function(arguments)",
"references": []
}
]
}
],
"flags": "ScopeFlags(Function)",
"id": 1,
"node": "Function(direct)",
"symbols": []
},
{
"children": [
{
"children": [
{
"children": [],
"flags": "ScopeFlags(Function | Arrow)",
"id": 5,
"node": "ArrowFunctionExpression",
"symbols": []
}
],
"flags": "ScopeFlags(Function)",
"id": 4,
"node": "Function(arguments)",
"symbols": [
{
"flags": "SymbolFlags(Function | FunctionExpression)",
"id": 4,
"name": "arguments",
"node": "Function(arguments)",
"references": []
}
]
}
],
"flags": "ScopeFlags(Function)",
"id": 3,
"node": "Function(throughArrow)",
"symbols": []
},
{
"children": [
{
"children": [],
"flags": "ScopeFlags(Function)",
"id": 7,
"node": "Function(arguments)",
"symbols": [
{
"flags": "SymbolFlags(Function | FunctionExpression)",
"id": 6,
"name": "arguments",
"node": "Function(arguments)",
"references": []
},
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 7,
"name": "value",
"node": "FormalParameter(value)",
"references": []
}
]
}
],
"flags": "ScopeFlags(Function)",
"id": 6,
"node": "Function(inDefault)",
"symbols": []
},
{
"children": [
{
"children": [
{
"children": [],
"flags": "ScopeFlags(Function | Arrow)",
"id": 10,
"node": "ArrowFunctionExpression",
"symbols": []
}
],
"flags": "ScopeFlags(Function)",
"id": 9,
"node": "Function(arguments)",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 10,
"name": "arguments",
"node": "FormalParameter(arguments)",
"references": [
{
"flags": "ReferenceFlags(Read)",
"id": 3,
"name": "arguments",
"node_id": 53,
"scope_id": 9
},
{
"flags": "ReferenceFlags(Read)",
"id": 4,
"name": "arguments",
"node_id": 57,
"scope_id": 10
}
]
}
]
}
],
"flags": "ScopeFlags(Function)",
"id": 8,
"node": "Function(withParameter)",
"symbols": []
},
{
"children": [
{
"children": [
{
"children": [],
"flags": "ScopeFlags(Function | Arrow)",
"id": 13,
"node": "ArrowFunctionExpression",
"symbols": []
}
],
"flags": "ScopeFlags(Function)",
"id": 12,
"node": "Function(arguments)",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 13,
"name": "arguments",
"node": "VariableDeclarator(arguments)",
"references": [
{
"flags": "ReferenceFlags(Read)",
"id": 5,
"name": "arguments",
"node_id": 71,
"scope_id": 12
},
{
"flags": "ReferenceFlags(Read)",
"id": 6,
"name": "arguments",
"node_id": 75,
"scope_id": 13
}
]
}
]
}
],
"flags": "ScopeFlags(Function)",
"id": 11,
"node": "Function(withVar)",
"symbols": []
}
],
"flags": "ScopeFlags(Top)",
"id": 0,
"node": "Program",
"symbols": [
{
"flags": "SymbolFlags(BlockScopedVariable | ConstVariable)",
"id": 0,
"name": "arguments",
"node": "VariableDeclarator(arguments)",
"references": []
},
{
"flags": "SymbolFlags(Function)",
"id": 1,
"name": "direct",
"node": "Function(direct)",
"references": []
},
{
"flags": "SymbolFlags(Function)",
"id": 3,
"name": "throughArrow",
"node": "Function(throughArrow)",
"references": []
},
{
"flags": "SymbolFlags(Function)",
"id": 5,
"name": "inDefault",
"node": "Function(inDefault)",
"references": []
},
{
"flags": "SymbolFlags(Function)",
"id": 8,
"name": "withParameter",
"node": "Function(withParameter)",
"references": []
},
{
"flags": "SymbolFlags(Function)",
"id": 11,
"name": "withVar",
"node": "Function(withVar)",
"references": []
}
]
}
]
@@ -0,0 +1,344 @@
---
source: crates/oxc_semantic/tests/main.rs
input_file: crates/oxc_semantic/tests/fixtures/oxc/arguments/implicit.ts
---
[
{
"children": [
{
"children": [],
"flags": "ScopeFlags(0x0)",
"id": 1,
"node": "TSTypeAliasDeclaration",
"symbols": []
},
{
"children": [],
"flags": "ScopeFlags(Function | Arrow)",
"id": 2,
"node": "ArrowFunctionExpression",
"symbols": []
},
{
"children": [
{
"children": [],
"flags": "ScopeFlags(0x0)",
"id": 4,
"node": "BlockStatement",
"symbols": []
},
{
"children": [],
"flags": "ScopeFlags(Function | Arrow)",
"id": 5,
"node": "ArrowFunctionExpression",
"symbols": []
},
{
"children": [],
"flags": "ScopeFlags(0x0)",
"id": 6,
"node": "TSTypeAliasDeclaration",
"symbols": []
},
{
"children": [],
"flags": "ScopeFlags(0x0)",
"id": 7,
"node": "TSTypeAliasDeclaration",
"symbols": []
}
],
"flags": "ScopeFlags(Function)",
"id": 3,
"node": "Function(ordinary)",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 3,
"name": "value",
"node": "FormalParameter(value)",
"references": []
},
{
"flags": "SymbolFlags(BlockScopedVariable | ConstVariable)",
"id": 4,
"name": "inherited",
"node": "VariableDeclarator(inherited)",
"references": []
},
{
"flags": "SymbolFlags(TypeAlias)",
"id": 5,
"name": "T",
"node": "TSTypeAliasDeclaration",
"references": []
},
{
"flags": "SymbolFlags(TypeAlias)",
"id": 6,
"name": "Q",
"node": "TSTypeAliasDeclaration",
"references": []
}
]
},
{
"children": [
{
"children": [],
"flags": "ScopeFlags(Function | Arrow)",
"id": 9,
"node": "ArrowFunctionExpression",
"symbols": []
},
{
"children": [],
"flags": "ScopeFlags(Function)",
"id": 10,
"node": "Function(nested)",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 11,
"name": "value",
"node": "FormalParameter(value)",
"references": []
}
]
}
],
"flags": "ScopeFlags(Function)",
"id": 8,
"node": "Function(parameter)",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 8,
"name": "arguments",
"node": "FormalParameter(arguments)",
"references": [
{
"flags": "ReferenceFlags(Read)",
"id": 8,
"name": "arguments",
"node_id": 50,
"scope_id": 8
},
{
"flags": "ReferenceFlags(Read)",
"id": 9,
"name": "arguments",
"node_id": 56,
"scope_id": 9
}
]
},
{
"flags": "SymbolFlags(BlockScopedVariable | ConstVariable)",
"id": 9,
"name": "inherited",
"node": "VariableDeclarator(inherited)",
"references": []
},
{
"flags": "SymbolFlags(Function)",
"id": 10,
"name": "nested",
"node": "Function(nested)",
"references": []
}
]
},
{
"children": [
{
"children": [],
"flags": "ScopeFlags(Function | Arrow)",
"id": 12,
"node": "ArrowFunctionExpression",
"symbols": []
},
{
"children": [],
"flags": "ScopeFlags(Function)",
"id": 13,
"node": "Function(nested)",
"symbols": []
}
],
"flags": "ScopeFlags(Function)",
"id": 11,
"node": "Function(local)",
"symbols": [
{
"flags": "SymbolFlags(BlockScopedVariable | ConstVariable)",
"id": 13,
"name": "arguments",
"node": "VariableDeclarator(arguments)",
"references": [
{
"flags": "ReferenceFlags(Read)",
"id": 12,
"name": "arguments",
"node_id": 75,
"scope_id": 11
},
{
"flags": "ReferenceFlags(Read)",
"id": 13,
"name": "arguments",
"node_id": 81,
"scope_id": 12
}
]
},
{
"flags": "SymbolFlags(BlockScopedVariable | ConstVariable)",
"id": 14,
"name": "inherited",
"node": "VariableDeclarator(inherited)",
"references": []
},
{
"flags": "SymbolFlags(Function)",
"id": 15,
"name": "nested",
"node": "Function(nested)",
"references": []
}
]
},
{
"children": [
{
"children": [],
"flags": "ScopeFlags(Function | Arrow)",
"id": 15,
"node": "ArrowFunctionExpression",
"symbols": []
}
],
"flags": "ScopeFlags(Function)",
"id": 14,
"node": "Function(defaults)",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 17,
"name": "value",
"node": "FormalParameter(value)",
"references": []
},
{
"flags": "SymbolFlags(BlockScopedVariable | ConstVariable)",
"id": 18,
"name": "arguments",
"node": "VariableDeclarator(arguments)",
"references": [
{
"flags": "ReferenceFlags(Read)",
"id": 16,
"name": "arguments",
"node_id": 102,
"scope_id": 14
}
]
}
]
},
{
"children": [],
"flags": "ScopeFlags(Function)",
"id": 16,
"node": "Function(<anonymous>)",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 20,
"name": "value",
"node": "FormalParameter(value)",
"references": []
}
]
}
],
"flags": "ScopeFlags(Top)",
"id": 0,
"node": "Program",
"symbols": [
{
"flags": "SymbolFlags(BlockScopedVariable | ConstVariable | TypeAlias)",
"id": 0,
"name": "arguments",
"node": "VariableDeclarator(arguments)",
"references": [
{
"flags": "ReferenceFlags(Read)",
"id": 0,
"name": "arguments",
"node_id": 9,
"scope_id": 0
},
{
"flags": "ReferenceFlags(Read)",
"id": 1,
"name": "arguments",
"node_id": 15,
"scope_id": 2
},
{
"flags": "ReferenceFlags(Type)",
"id": 6,
"name": "arguments",
"node_id": 37,
"scope_id": 6
}
]
},
{
"flags": "SymbolFlags(BlockScopedVariable | ConstVariable)",
"id": 1,
"name": "arrow",
"node": "VariableDeclarator(arrow)",
"references": []
},
{
"flags": "SymbolFlags(Function)",
"id": 2,
"name": "ordinary",
"node": "Function(ordinary)",
"references": []
},
{
"flags": "SymbolFlags(Function)",
"id": 7,
"name": "parameter",
"node": "Function(parameter)",
"references": []
},
{
"flags": "SymbolFlags(Function)",
"id": 12,
"name": "local",
"node": "Function(local)",
"references": []
},
{
"flags": "SymbolFlags(Function)",
"id": 16,
"name": "defaults",
"node": "Function(defaults)",
"references": []
},
{
"flags": "SymbolFlags(BlockScopedVariable | ConstVariable)",
"id": 19,
"name": "object",
"node": "VariableDeclarator(object)",
"references": []
}
]
}
]
@@ -0,0 +1,30 @@
const arguments = [];
type arguments = number;
arguments;
const arrow = () => arguments;
function ordinary(value = arguments) {
arguments;
{ arguments; }
const inherited = () => arguments;
type T = arguments;
type Q = typeof arguments;
}
function parameter(arguments = []) {
arguments;
const inherited = () => arguments;
function nested(value = arguments) { arguments; }
}
function local() {
const arguments = [];
arguments;
const inherited = () => arguments;
function nested() { arguments; }
}
function defaults(value = () => arguments) {
const arguments = [];
arguments;
}
const object = {
method(value = arguments) { arguments; },
};
@@ -0,0 +1,194 @@
---
source: crates/oxc_semantic/tests/main.rs
input_file: crates/oxc_semantic/tests/fixtures/oxc/arguments/types.ts
---
[
{
"children": [
{
"children": [],
"flags": "ScopeFlags(Function)",
"id": 1,
"node": "Function(ambient)",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 2,
"name": "value",
"node": "FormalParameter(value)",
"references": []
}
]
},
{
"children": [],
"flags": "ScopeFlags(Function)",
"id": 2,
"node": "Function(overload)",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 4,
"name": "value",
"node": "FormalParameter(value)",
"references": []
}
]
},
{
"children": [],
"flags": "ScopeFlags(Function)",
"id": 3,
"node": "Function(overload)",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 5,
"name": "value",
"node": "FormalParameter(value)",
"references": []
}
]
},
{
"children": [
{
"children": [],
"flags": "ScopeFlags(0x0)",
"id": 5,
"node": "TSFunctionType",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 7,
"name": "value",
"node": "FormalParameter(value)",
"references": []
}
]
}
],
"flags": "ScopeFlags(0x0)",
"id": 4,
"node": "TSTypeAliasDeclaration",
"symbols": []
},
{
"children": [
{
"children": [],
"flags": "ScopeFlags(0x0)",
"id": 7,
"node": "TSMethodSignature",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 9,
"name": "value",
"node": "FormalParameter(value)",
"references": []
}
]
}
],
"flags": "ScopeFlags(0x0)",
"id": 6,
"node": "TSInterfaceDeclaration",
"symbols": []
},
{
"children": [
{
"children": [],
"flags": "ScopeFlags(Function)",
"id": 9,
"node": "Function(inner)",
"symbols": [
{
"flags": "SymbolFlags(FunctionScopedVariable)",
"id": 12,
"name": "value",
"node": "FormalParameter(value)",
"references": []
}
]
}
],
"flags": "ScopeFlags(TsModuleBlock)",
"id": 8,
"node": "TSNamespaceDeclaration(Namespace)",
"symbols": [
{
"flags": "SymbolFlags(Function)",
"id": 11,
"name": "inner",
"node": "Function(inner)",
"references": []
}
]
}
],
"flags": "ScopeFlags(Top)",
"id": 0,
"node": "Program",
"symbols": [
{
"flags": "SymbolFlags(BlockScopedVariable | ConstVariable)",
"id": 0,
"name": "arguments",
"node": "VariableDeclarator(arguments)",
"references": [
{
"flags": "ReferenceFlags(Type)",
"id": 2,
"name": "arguments",
"node_id": 41,
"scope_id": 5
},
{
"flags": "ReferenceFlags(Type)",
"id": 3,
"name": "arguments",
"node_id": 54,
"scope_id": 7
}
]
},
{
"flags": "SymbolFlags(Function | Ambient)",
"id": 1,
"name": "ambient",
"node": "Function(ambient)",
"references": []
},
{
"flags": "SymbolFlags(Function)",
"id": 3,
"name": "overload",
"node": "Function(overload)",
"references": []
},
{
"flags": "SymbolFlags(TypeAlias)",
"id": 6,
"name": "FunctionType",
"node": "TSTypeAliasDeclaration",
"references": []
},
{
"flags": "SymbolFlags(Interface)",
"id": 8,
"name": "Signatures",
"node": "TSInterfaceDeclaration",
"references": []
},
{
"flags": "SymbolFlags(ValueModule)",
"id": 10,
"name": "Namespace",
"node": "TSNamespaceDeclaration(Namespace)",
"references": []
}
]
}
]
@@ -0,0 +1,18 @@
const arguments = [];
declare function ambient(value: typeof arguments): void;
function overload(value: typeof arguments): void;
function overload(value: any) {}
type FunctionType = (value: typeof arguments) => void;
interface Signatures {
method(value: typeof arguments): void;
}
namespace Namespace {
export function inner(value = arguments) {
arguments;
}
}
@@ -624,3 +624,18 @@ fn test_import_value_redeclaration_in_module() {
// TypeScript should NOT report this error (declaration merging)
SemanticTester::ts("import { Foo } from './foo.js'; var Foo;").has_root_symbol("Foo").test();
}
#[test]
fn test_implicit_arguments_unresolved_references() {
let tester = SemanticTester::ts(
"const arguments = []; function f(value = arguments) { return () => arguments; }",
);
let semantic = tester.build();
let scoping = semantic.scoping();
let references = scoping.root_unresolved_references().get("arguments").unwrap();
assert_eq!(references.len(), 2);
assert_ne!(references[0], references[1]);
for &reference_id in references {
assert!(scoping.get_reference(reference_id).symbol_id().is_none());
}
}
@@ -727,10 +727,11 @@ impl<'a> AsyncGeneratorExecutor<'a> {
bound_ident: &BoundIdentifier<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Statement<'a> {
let arguments = static_ident!("arguments");
let symbol_id = ctx.scoping().find_binding(ctx.current_scope_id(), arguments);
let arguments_ident =
Argument::from(ctx.create_ident_expr(SPAN, arguments, symbol_id, ReferenceFlags::Read));
let arguments_ident = Argument::from(ctx.create_unbound_ident_expr(
SPAN,
static_ident!("arguments"),
ReferenceFlags::Read,
));
// (this, arguments)
let this = Argument::new_this_expression(SPAN, ctx);