mirror of
https://github.com/aphrody-labs/oxc.git
synced 2026-10-17 12:56:09 +00:00
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:
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,
|
||||
);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
+233
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user