fix: 词法声明遮蔽内置名不再占镜像槽并拒写臂全局解析

This commit is contained in:
2026-09-20 11:16:13 +00:00
parent de3a9af0e1
commit c4ce29c6f2
7 changed files with 389 additions and 106 deletions
+3 -1
View File
@@ -593,11 +593,13 @@ impl CompileCtx {
/// 名字是否解析到全局内置槽:builtin_reg_map 登记(预注册镜像槽),或绑定 /// 名字是否解析到全局内置槽:builtin_reg_map 登记(预注册镜像槽),或绑定
/// 落全局作用域(scope 0,顶层 var 预声明/隐式全局,含继承的全局槽)。局部 /// 落全局作用域(scope 0,顶层 var 预声明/隐式全局,含继承的全局槽)。局部
/// var/let/参数遮蔽同名时解析到局部寄存器/局部作用域,两条件均不命中。 /// var/let/参数遮蔽同名时解析到局部寄存器/局部作用域,两条件均不命中。
/// scope 0 臂拒词法绑定:顶层 let/const/class/导入绑定遮蔽同名全局属性,
/// 值存储是其自身槽位,写不落全局对象。
fn resolves_to_global_builtin_slot(&self, name: &str, reg: u32) -> bool { fn resolves_to_global_builtin_slot(&self, name: &str, reg: u32) -> bool {
if self.scopes.builtin_reg_map.iter().any(|(n, r)| n == name && *r == reg) { if self.scopes.builtin_reg_map.iter().any(|(n, r)| n == name && *r == reg) {
return true; return true;
} }
matches!(self.scopes.symbols.lookup_any_binding(name), Some((_, 0))) matches!(self.scopes.symbols.lookup_any_binding(name), Some((binding, 0)) if !binding.lexical)
} }
/// 写目标是否为只读全局内置(undefined/NaN/Infinity 的全局绑定——全局对象上 /// 写目标是否为只读全局内置(undefined/NaN/Infinity 的全局绑定——全局对象上
+6 -1
View File
@@ -355,6 +355,7 @@ impl Emitter {
reg: binding.reg, reg: binding.reg,
initialized: binding.initialized, initialized: binding.initialized,
is_const: binding.is_const, is_const: binding.is_const,
lexical: binding.lexical,
predeclared: false, predeclared: false,
}, },
); );
@@ -378,6 +379,8 @@ impl Emitter {
reg: *reg, reg: *reg,
initialized: true, initialized: true,
is_const: true, is_const: true,
// 类 this 自绑定非用户词法声明,不置位。
lexical: false,
predeclared: false, predeclared: false,
}, },
); );
@@ -408,7 +411,9 @@ impl Emitter {
self.predeclare_labeled_function_declarations(body_stmts, &mut ctx); self.predeclare_labeled_function_declarations(body_stmts, &mut ctx);
// 预注册 builtin 引用(先于任何临时寄存器),builtin 槽不与被复用的临时值冲突。 // 预注册 builtin 引用(先于任何临时寄存器),builtin 槽不与被复用的临时值冲突。
self.pre_register_builtin_references(body_stmts, &mut ctx); // 函数体直接子级词法声明名排除登记(顶层词法遮蔽同口径,见 program.rs)。
let lexical_excluded = collect_direct_lexical_names(body_stmts);
self.pre_register_builtin_references(body_stmts, &lexical_excluded, &mut ctx);
// 预声明 `var` 名,使首个 sub-pass 中提升的函数声明能解析其闭包引用的外层 var。 // 预声明 `var` 名,使首个 sub-pass 中提升的函数声明能解析其闭包引用的外层 var。
self.predeclare_var_declarations(body_stmts, &mut ctx); self.predeclare_var_declarations(body_stmts, &mut ctx);
+4 -2
View File
@@ -10,7 +10,7 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::path::Path; use std::path::Path;
use crate::capture::{collect_captured_bindings, collect_own_binding_names}; use crate::capture::{collect_captured_bindings, collect_direct_lexical_names, collect_own_binding_names};
use crate::expr::call::pack_arg_regs; use crate::expr::call::pack_arg_regs;
use crate::{CompileCtx, Emitter}; use crate::{CompileCtx, Emitter};
use oxc_allocator::Box; use oxc_allocator::Box;
@@ -440,7 +440,9 @@ impl Emitter {
// —— 预声明(镜像 emit_program;import/export 包装的声明也计入 hoisting)—— // —— 预声明(镜像 emit_program;import/export 包装的声明也计入 hoisting)——
self.predeclare_function_declarations(body, ctx); self.predeclare_function_declarations(body, ctx);
self.pre_register_builtin_references(body, ctx); // 模块顶层词法声明名排除镜像登记(词法绑定遮蔽同名全局属性,同 program.rs)。
let lexical_excluded = collect_direct_lexical_names(body);
self.pre_register_builtin_references(body, &lexical_excluded, ctx);
self.predeclare_var_declarations(body, ctx); self.predeclare_var_declarations(body, ctx);
// 模块 lexical 声明入模块环境(非全局对象),不做受限全局名检查。 // 模块 lexical 声明入模块环境(非全局对象),不做受限全局名检查。
let _ = self.predeclare_lexical_declarations(body, ctx, false); let _ = self.predeclare_lexical_declarations(body, ctx, false);
+117 -101
View File
@@ -1,151 +1,161 @@
//! emit 前置 pass,builtin 引用预扫描:临时寄存器池分配前遍历 AST,把内置 //! emit 前置 pass,builtin 引用预扫描:临时寄存器池分配前遍历 AST,把内置
//! 全局标识符出现处(语句/表达式/赋值目标/链式成员/实参/绑定 pattern 计算 //! 全局标识符出现处(语句/表达式/赋值目标/链式成员/实参/绑定 pattern 计算
//! 键)预先登记到固定寄存器槽(builtin_reg_map),避免与临时寄存器池冲突。 //! 键)预先登记到固定寄存器槽(builtin_reg_map),避免与临时寄存器池冲突。
//!
//! 排除集:当前语句列表直接子级的词法声明名(let/const/class)。这些名在本作用域
//! 是词法绑定并遮蔽同名全局属性,镜像槽不得为其登记——否则镜像占位先于词法预
//! 声明占 scope 0,词法声明撞名被拒(规范合法遮蔽形被编译期误拒),写臂谓词亦
//! 误把词法槽解析成全局内置槽。
use std::collections::HashSet;
use crate::{CompileCtx, Emitter}; use crate::{CompileCtx, Emitter};
use oxide_parser::{BindingPattern, Declaration, Expression, Statement}; use oxide_parser::{BindingPattern, Declaration, Expression, Statement};
impl Emitter { impl Emitter {
/// 递归遍历程序 AST,把内置全局标识符引用预登记到固定寄存器槽(内置槽在临时 /// 递归遍历程序 AST,把内置全局标识符引用预登记到固定寄存器槽(内置槽在临时
/// 寄存器池之前分配,两者隔离,槽位分配序稳定)。 /// 寄存器池之前分配,两者隔离,槽位分配序稳定)。`excluded` 内的名(本语句
pub(crate) fn pre_register_builtin_references(&self, stmts: &[Statement], ctx: &mut CompileCtx) { /// 列表直接子级词法声明名)跳过登记。
pub(crate) fn pre_register_builtin_references(
&self, stmts: &[Statement], excluded: &HashSet<String>, ctx: &mut CompileCtx,
) {
for stmt in stmts { for stmt in stmts {
self.pre_scan_builtin_stmt(stmt, ctx); self.pre_scan_builtin_stmt(stmt, excluded, ctx);
} }
} }
/// 递归遍历语句树,登记其中的内置标识符引用:表达式语句、变量/函数/类声明、 /// 递归遍历语句树,登记其中的内置标识符引用:表达式语句、变量/函数/类声明、
/// 控制流各分支与模块导出声明。 /// 控制流各分支与模块导出声明。
fn pre_scan_builtin_stmt(&self, stmt: &Statement, ctx: &mut CompileCtx) { fn pre_scan_builtin_stmt(&self, stmt: &Statement, excluded: &HashSet<String>, ctx: &mut CompileCtx) {
match stmt { match stmt {
Statement::ExpressionStatement(es) => self.pre_scan_builtin_expr(&es.expression, ctx), Statement::ExpressionStatement(es) => self.pre_scan_builtin_expr(&es.expression, excluded, ctx),
Statement::VariableDeclaration(vd) => { Statement::VariableDeclaration(vd) => {
for d in &vd.declarations { for d in &vd.declarations {
self.pre_scan_builtin_pattern(&d.id, ctx); self.pre_scan_builtin_pattern(&d.id, excluded, ctx);
if let Some(init) = &d.init { if let Some(init) = &d.init {
self.pre_scan_builtin_expr(init, ctx); self.pre_scan_builtin_expr(init, excluded, ctx);
} }
} }
} }
Statement::ReturnStatement(rs) => { Statement::ReturnStatement(rs) => {
if let Some(a) = &rs.argument { if let Some(a) = &rs.argument {
self.pre_scan_builtin_expr(a, ctx); self.pre_scan_builtin_expr(a, excluded, ctx);
} }
} }
Statement::IfStatement(is) => { Statement::IfStatement(is) => {
self.pre_scan_builtin_expr(&is.test, ctx); self.pre_scan_builtin_expr(&is.test, excluded, ctx);
self.pre_scan_builtin_stmt(&is.consequent, ctx); self.pre_scan_builtin_stmt(&is.consequent, excluded, ctx);
if let Some(alt) = &is.alternate { if let Some(alt) = &is.alternate {
self.pre_scan_builtin_stmt(alt, ctx); self.pre_scan_builtin_stmt(alt, excluded, ctx);
} }
} }
Statement::WhileStatement(wh) => { Statement::WhileStatement(wh) => {
self.pre_scan_builtin_expr(&wh.test, ctx); self.pre_scan_builtin_expr(&wh.test, excluded, ctx);
self.pre_scan_builtin_stmt(&wh.body, ctx); self.pre_scan_builtin_stmt(&wh.body, excluded, ctx);
} }
Statement::DoWhileStatement(dw) => { Statement::DoWhileStatement(dw) => {
self.pre_scan_builtin_stmt(&dw.body, ctx); self.pre_scan_builtin_stmt(&dw.body, excluded, ctx);
self.pre_scan_builtin_expr(&dw.test, ctx); self.pre_scan_builtin_expr(&dw.test, excluded, ctx);
} }
Statement::ForStatement(fs) => { Statement::ForStatement(fs) => {
if let Some(init) = &fs.init { if let Some(init) = &fs.init {
if let Some(e) = init.as_expression() { if let Some(e) = init.as_expression() {
self.pre_scan_builtin_expr(e, ctx); self.pre_scan_builtin_expr(e, excluded, ctx);
} else if let oxide_parser::ForStatementInit::VariableDeclaration(decl) = init { } else if let oxide_parser::ForStatementInit::VariableDeclaration(decl) = init {
for d in &decl.declarations { for d in &decl.declarations {
self.pre_scan_builtin_pattern(&d.id, ctx); self.pre_scan_builtin_pattern(&d.id, excluded, ctx);
if let Some(init_expr) = &d.init { if let Some(init_expr) = &d.init {
self.pre_scan_builtin_expr(init_expr, ctx); self.pre_scan_builtin_expr(init_expr, excluded, ctx);
} }
} }
} }
} }
if let Some(t) = &fs.test { if let Some(t) = &fs.test {
self.pre_scan_builtin_expr(t, ctx); self.pre_scan_builtin_expr(t, excluded, ctx);
} }
if let Some(u) = &fs.update { if let Some(u) = &fs.update {
self.pre_scan_builtin_expr(u, ctx); self.pre_scan_builtin_expr(u, excluded, ctx);
} }
self.pre_scan_builtin_stmt(&fs.body, ctx); self.pre_scan_builtin_stmt(&fs.body, excluded, ctx);
} }
Statement::ForInStatement(fi) => { Statement::ForInStatement(fi) => {
if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fi.left { if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fi.left {
for d in &vd.declarations { for d in &vd.declarations {
self.pre_scan_builtin_pattern(&d.id, ctx); self.pre_scan_builtin_pattern(&d.id, excluded, ctx);
} }
} }
self.pre_scan_builtin_expr(&fi.right, ctx); self.pre_scan_builtin_expr(&fi.right, excluded, ctx);
self.pre_scan_builtin_stmt(&fi.body, ctx); self.pre_scan_builtin_stmt(&fi.body, excluded, ctx);
} }
Statement::ForOfStatement(fo) => { Statement::ForOfStatement(fo) => {
if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fo.left { if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fo.left {
for d in &vd.declarations { for d in &vd.declarations {
self.pre_scan_builtin_pattern(&d.id, ctx); self.pre_scan_builtin_pattern(&d.id, excluded, ctx);
} }
} }
self.pre_scan_builtin_expr(&fo.right, ctx); self.pre_scan_builtin_expr(&fo.right, excluded, ctx);
self.pre_scan_builtin_stmt(&fo.body, ctx); self.pre_scan_builtin_stmt(&fo.body, excluded, ctx);
} }
Statement::SwitchStatement(sw) => { Statement::SwitchStatement(sw) => {
self.pre_scan_builtin_expr(&sw.discriminant, ctx); self.pre_scan_builtin_expr(&sw.discriminant, excluded, ctx);
for case in &sw.cases { for case in &sw.cases {
if let Some(test) = &case.test { if let Some(test) = &case.test {
self.pre_scan_builtin_expr(test, ctx); self.pre_scan_builtin_expr(test, excluded, ctx);
} }
for s in &case.consequent { for s in &case.consequent {
self.pre_scan_builtin_stmt(s, ctx); self.pre_scan_builtin_stmt(s, excluded, ctx);
} }
} }
} }
Statement::ThrowStatement(ts) => { Statement::ThrowStatement(ts) => {
self.pre_scan_builtin_expr(&ts.argument, ctx); self.pre_scan_builtin_expr(&ts.argument, excluded, ctx);
} }
Statement::TryStatement(ts) => { Statement::TryStatement(ts) => {
for s in &ts.block.body { for s in &ts.block.body {
self.pre_scan_builtin_stmt(s, ctx); self.pre_scan_builtin_stmt(s, excluded, ctx);
} }
if let Some(handler) = &ts.handler { if let Some(handler) = &ts.handler {
if let Some(param) = &handler.param { if let Some(param) = &handler.param {
self.pre_scan_builtin_pattern(&param.pattern, ctx); self.pre_scan_builtin_pattern(&param.pattern, excluded, ctx);
} }
for s in &handler.body.body { for s in &handler.body.body {
self.pre_scan_builtin_stmt(s, ctx); self.pre_scan_builtin_stmt(s, excluded, ctx);
} }
} }
if let Some(finalizer) = &ts.finalizer { if let Some(finalizer) = &ts.finalizer {
for s in &finalizer.body { for s in &finalizer.body {
self.pre_scan_builtin_stmt(s, ctx); self.pre_scan_builtin_stmt(s, excluded, ctx);
} }
} }
} }
Statement::BlockStatement(bs) => { Statement::BlockStatement(bs) => {
for s in &bs.body { for s in &bs.body {
self.pre_scan_builtin_stmt(s, ctx); self.pre_scan_builtin_stmt(s, excluded, ctx);
} }
} }
Statement::LabeledStatement(ls) => self.pre_scan_builtin_stmt(&ls.body, ctx), Statement::LabeledStatement(ls) => self.pre_scan_builtin_stmt(&ls.body, excluded, ctx),
Statement::WithStatement(ws) => { Statement::WithStatement(ws) => {
self.pre_scan_builtin_expr(&ws.object, ctx); self.pre_scan_builtin_expr(&ws.object, excluded, ctx);
self.pre_scan_builtin_stmt(&ws.body, ctx); self.pre_scan_builtin_stmt(&ws.body, excluded, ctx);
} }
Statement::ClassDeclaration(cd) => { Statement::ClassDeclaration(cd) => {
if let Some(super_class) = &cd.super_class { if let Some(super_class) = &cd.super_class {
self.pre_scan_builtin_expr(super_class, ctx); self.pre_scan_builtin_expr(super_class, excluded, ctx);
} }
} }
Statement::ExportNamedDeclaration(exp) => { Statement::ExportNamedDeclaration(exp) => {
if let Some(Declaration::VariableDeclaration(vd)) = &exp.declaration { if let Some(Declaration::VariableDeclaration(vd)) = &exp.declaration {
for d in &vd.declarations { for d in &vd.declarations {
self.pre_scan_builtin_pattern(&d.id, ctx); self.pre_scan_builtin_pattern(&d.id, excluded, ctx);
if let Some(init) = &d.init { if let Some(init) = &d.init {
self.pre_scan_builtin_expr(init, ctx); self.pre_scan_builtin_expr(init, excluded, ctx);
} }
} }
} }
} }
Statement::ExportDefaultDeclaration(exp) => { Statement::ExportDefaultDeclaration(exp) => {
if let Some(e) = exp.declaration.as_expression() { if let Some(e) = exp.declaration.as_expression() {
self.pre_scan_builtin_expr(e, ctx); self.pre_scan_builtin_expr(e, excluded, ctx);
} }
} }
Statement::FunctionDeclaration(_) | Statement::BreakStatement(_) | Statement::ContinueStatement(_) => {} Statement::FunctionDeclaration(_) | Statement::BreakStatement(_) | Statement::ContinueStatement(_) => {}
@@ -155,67 +165,69 @@ impl Emitter {
/// 递归遍历表达式树,登记其中的内置标识符引用:标识符、调用/构造、成员、可选链、 /// 递归遍历表达式树,登记其中的内置标识符引用:标识符、调用/构造、成员、可选链、
/// 对象/数组字面量与各类运算表达式。 /// 对象/数组字面量与各类运算表达式。
fn pre_scan_builtin_expr(&self, expr: &Expression, ctx: &mut CompileCtx) { fn pre_scan_builtin_expr(&self, expr: &Expression, excluded: &HashSet<String>, ctx: &mut CompileCtx) {
match expr { match expr {
Expression::Identifier(ident) => { Expression::Identifier(ident) => {
if CompileCtx::is_known_builtin(ident.name.as_str()) { // 本语句列表词法声明同名的 builtin 不登记镜像槽(词法绑定遮蔽,
// 镜像占位会撞 TDZ 预声明并误导写臂全局解析)。
if CompileCtx::is_known_builtin(ident.name.as_str()) && !excluded.contains(ident.name.as_str()) {
let _ = ctx.lookup_or_builtin(ident.name.as_str()); let _ = ctx.lookup_or_builtin(ident.name.as_str());
} }
} }
Expression::BinaryExpression(bin) => { Expression::BinaryExpression(bin) => {
self.pre_scan_builtin_expr(&bin.left, ctx); self.pre_scan_builtin_expr(&bin.left, excluded, ctx);
self.pre_scan_builtin_expr(&bin.right, ctx); self.pre_scan_builtin_expr(&bin.right, excluded, ctx);
} }
Expression::UnaryExpression(un) => { Expression::UnaryExpression(un) => {
self.pre_scan_builtin_expr(&un.argument, ctx); self.pre_scan_builtin_expr(&un.argument, excluded, ctx);
} }
Expression::CallExpression(call) => { Expression::CallExpression(call) => {
self.pre_scan_builtin_expr(&call.callee, ctx); self.pre_scan_builtin_expr(&call.callee, excluded, ctx);
for arg in &call.arguments { for arg in &call.arguments {
self.pre_scan_builtin_arg(arg, ctx); self.pre_scan_builtin_arg(arg, excluded, ctx);
} }
} }
Expression::NewExpression(ne) => { Expression::NewExpression(ne) => {
self.pre_scan_builtin_expr(&ne.callee, ctx); self.pre_scan_builtin_expr(&ne.callee, excluded, ctx);
for arg in &ne.arguments { for arg in &ne.arguments {
self.pre_scan_builtin_arg(arg, ctx); self.pre_scan_builtin_arg(arg, excluded, ctx);
} }
} }
Expression::LogicalExpression(log) => { Expression::LogicalExpression(log) => {
self.pre_scan_builtin_expr(&log.left, ctx); self.pre_scan_builtin_expr(&log.left, excluded, ctx);
self.pre_scan_builtin_expr(&log.right, ctx); self.pre_scan_builtin_expr(&log.right, excluded, ctx);
} }
Expression::ConditionalExpression(cond) => { Expression::ConditionalExpression(cond) => {
self.pre_scan_builtin_expr(&cond.test, ctx); self.pre_scan_builtin_expr(&cond.test, excluded, ctx);
self.pre_scan_builtin_expr(&cond.consequent, ctx); self.pre_scan_builtin_expr(&cond.consequent, excluded, ctx);
self.pre_scan_builtin_expr(&cond.alternate, ctx); self.pre_scan_builtin_expr(&cond.alternate, excluded, ctx);
} }
Expression::PrivateInExpression(pin) => { Expression::PrivateInExpression(pin) => {
self.pre_scan_builtin_expr(&pin.right, ctx); self.pre_scan_builtin_expr(&pin.right, excluded, ctx);
} }
Expression::SequenceExpression(seq) => { Expression::SequenceExpression(seq) => {
for e in &seq.expressions { for e in &seq.expressions {
self.pre_scan_builtin_expr(e, ctx); self.pre_scan_builtin_expr(e, excluded, ctx);
} }
} }
Expression::AssignmentExpression(assign) => { Expression::AssignmentExpression(assign) => {
if let Some(target) = assign.left.as_simple_assignment_target() { if let Some(target) = assign.left.as_simple_assignment_target() {
self.pre_scan_builtin_target(target, ctx); self.pre_scan_builtin_target(target, excluded, ctx);
} }
self.pre_scan_builtin_expr(&assign.right, ctx); self.pre_scan_builtin_expr(&assign.right, excluded, ctx);
} }
Expression::UpdateExpression(update) => { Expression::UpdateExpression(update) => {
self.pre_scan_builtin_target(&update.argument, ctx); self.pre_scan_builtin_target(&update.argument, excluded, ctx);
} }
Expression::TemplateLiteral(tl) => { Expression::TemplateLiteral(tl) => {
for e in &tl.expressions { for e in &tl.expressions {
self.pre_scan_builtin_expr(e, ctx); self.pre_scan_builtin_expr(e, excluded, ctx);
} }
} }
Expression::TaggedTemplateExpression(tt) => { Expression::TaggedTemplateExpression(tt) => {
self.pre_scan_builtin_expr(&tt.tag, ctx); self.pre_scan_builtin_expr(&tt.tag, excluded, ctx);
for e in &tt.quasi.expressions { for e in &tt.quasi.expressions {
self.pre_scan_builtin_expr(e, ctx); self.pre_scan_builtin_expr(e, excluded, ctx);
} }
} }
Expression::ObjectExpression(obj) => { Expression::ObjectExpression(obj) => {
@@ -223,12 +235,12 @@ impl Emitter {
match prop { match prop {
oxide_parser::ObjectPropertyKind::ObjectProperty(p) => { oxide_parser::ObjectPropertyKind::ObjectProperty(p) => {
if p.computed { if p.computed {
self.pre_scan_builtin_expr(p.key.to_expression(), ctx); self.pre_scan_builtin_expr(p.key.to_expression(), excluded, ctx);
} }
self.pre_scan_builtin_expr(&p.value, ctx); self.pre_scan_builtin_expr(&p.value, excluded, ctx);
} }
oxide_parser::ObjectPropertyKind::SpreadProperty(spread) => { oxide_parser::ObjectPropertyKind::SpreadProperty(spread) => {
self.pre_scan_builtin_expr(&spread.argument, ctx); self.pre_scan_builtin_expr(&spread.argument, excluded, ctx);
} }
} }
} }
@@ -236,30 +248,30 @@ impl Emitter {
Expression::ArrayExpression(arr) => { Expression::ArrayExpression(arr) => {
for e in &arr.elements { for e in &arr.elements {
if let Some(e) = e.as_expression() { if let Some(e) = e.as_expression() {
self.pre_scan_builtin_expr(e, ctx); self.pre_scan_builtin_expr(e, excluded, ctx);
} }
} }
} }
Expression::PrivateFieldExpression(member) => { Expression::PrivateFieldExpression(member) => {
self.pre_scan_builtin_expr(&member.object, ctx); self.pre_scan_builtin_expr(&member.object, excluded, ctx);
} }
Expression::StaticMemberExpression(member) => { Expression::StaticMemberExpression(member) => {
self.pre_scan_builtin_expr(&member.object, ctx); self.pre_scan_builtin_expr(&member.object, excluded, ctx);
} }
Expression::ComputedMemberExpression(member) => { Expression::ComputedMemberExpression(member) => {
self.pre_scan_builtin_expr(&member.object, ctx); self.pre_scan_builtin_expr(&member.object, excluded, ctx);
self.pre_scan_builtin_expr(&member.expression, ctx); self.pre_scan_builtin_expr(&member.expression, excluded, ctx);
} }
Expression::ChainExpression(chain) => { Expression::ChainExpression(chain) => {
self.pre_scan_builtin_chain(&chain.expression, ctx); self.pre_scan_builtin_chain(&chain.expression, excluded, ctx);
} }
Expression::ParenthesizedExpression(p) => self.pre_scan_builtin_expr(&p.expression, ctx), Expression::ParenthesizedExpression(p) => self.pre_scan_builtin_expr(&p.expression, excluded, ctx),
Expression::YieldExpression(ye) => { Expression::YieldExpression(ye) => {
if let Some(a) = &ye.argument { if let Some(a) = &ye.argument {
self.pre_scan_builtin_expr(a, ctx); self.pre_scan_builtin_expr(a, excluded, ctx);
} }
} }
Expression::AwaitExpression(ae) => self.pre_scan_builtin_expr(&ae.argument, ctx), Expression::AwaitExpression(ae) => self.pre_scan_builtin_expr(&ae.argument, excluded, ctx),
Expression::ArrowFunctionExpression(_) Expression::ArrowFunctionExpression(_)
| Expression::FunctionExpression(_) | Expression::FunctionExpression(_)
| Expression::ClassExpression(_) => {} | Expression::ClassExpression(_) => {}
@@ -269,47 +281,51 @@ impl Emitter {
/// 遍历赋值目标,登记其中的内置标识符引用:标识符目标直接登记,成员目标只扫描 /// 遍历赋值目标,登记其中的内置标识符引用:标识符目标直接登记,成员目标只扫描
/// 对象与计算键(属性名不是标识符引用)。 /// 对象与计算键(属性名不是标识符引用)。
fn pre_scan_builtin_target(&self, target: &oxide_parser::SimpleAssignmentTarget, ctx: &mut CompileCtx) { fn pre_scan_builtin_target(
&self, target: &oxide_parser::SimpleAssignmentTarget, excluded: &HashSet<String>, ctx: &mut CompileCtx,
) {
match target { match target {
oxide_parser::SimpleAssignmentTarget::AssignmentTargetIdentifier(id) => { oxide_parser::SimpleAssignmentTarget::AssignmentTargetIdentifier(id) => {
// 标识符目标与表达式位置标识符引用同口径预登记:目标为某内置名的 // 标识符目标与表达式位置标识符引用同口径预登记:目标为某内置名的
// 唯一出现处(无读侧引用)时缺预登记会解析成隐式全局新槽,旧值读 // 唯一出现处(无读侧引用)时缺预登记会解析成隐式全局新槽,旧值读
// 与短路判定拿到未预载值。 // 与短路判定拿到未预载值。本语句列表词法声明同名不登记(同表达式臂)。
if CompileCtx::is_known_builtin(id.name.as_str()) { if CompileCtx::is_known_builtin(id.name.as_str()) && !excluded.contains(id.name.as_str()) {
let _ = ctx.lookup_or_builtin(id.name.as_str()); let _ = ctx.lookup_or_builtin(id.name.as_str());
} }
} }
oxide_parser::SimpleAssignmentTarget::StaticMemberExpression(member) => { oxide_parser::SimpleAssignmentTarget::StaticMemberExpression(member) => {
self.pre_scan_builtin_expr(&member.object, ctx); self.pre_scan_builtin_expr(&member.object, excluded, ctx);
} }
oxide_parser::SimpleAssignmentTarget::ComputedMemberExpression(member) => { oxide_parser::SimpleAssignmentTarget::ComputedMemberExpression(member) => {
self.pre_scan_builtin_expr(&member.object, ctx); self.pre_scan_builtin_expr(&member.object, excluded, ctx);
self.pre_scan_builtin_expr(&member.expression, ctx); self.pre_scan_builtin_expr(&member.expression, excluded, ctx);
} }
oxide_parser::SimpleAssignmentTarget::PrivateFieldExpression(member) => { oxide_parser::SimpleAssignmentTarget::PrivateFieldExpression(member) => {
self.pre_scan_builtin_expr(&member.object, ctx); self.pre_scan_builtin_expr(&member.object, excluded, ctx);
} }
_ => {} _ => {}
} }
} }
/// 遍历可选链元素,登记链上成员访问、调用与实参中的内置标识符引用。 /// 遍历可选链元素,登记链上成员访问、调用与实参中的内置标识符引用。
fn pre_scan_builtin_chain(&self, element: &oxide_parser::ChainElement, ctx: &mut CompileCtx) { fn pre_scan_builtin_chain(
&self, element: &oxide_parser::ChainElement, excluded: &HashSet<String>, ctx: &mut CompileCtx,
) {
match element { match element {
oxide_parser::ChainElement::StaticMemberExpression(member) => { oxide_parser::ChainElement::StaticMemberExpression(member) => {
self.pre_scan_builtin_expr(&member.object, ctx); self.pre_scan_builtin_expr(&member.object, excluded, ctx);
} }
oxide_parser::ChainElement::ComputedMemberExpression(member) => { oxide_parser::ChainElement::ComputedMemberExpression(member) => {
self.pre_scan_builtin_expr(&member.object, ctx); self.pre_scan_builtin_expr(&member.object, excluded, ctx);
self.pre_scan_builtin_expr(&member.expression, ctx); self.pre_scan_builtin_expr(&member.expression, excluded, ctx);
} }
oxide_parser::ChainElement::PrivateFieldExpression(member) => { oxide_parser::ChainElement::PrivateFieldExpression(member) => {
self.pre_scan_builtin_expr(&member.object, ctx); self.pre_scan_builtin_expr(&member.object, excluded, ctx);
} }
oxide_parser::ChainElement::CallExpression(call) => { oxide_parser::ChainElement::CallExpression(call) => {
self.pre_scan_builtin_expr(&call.callee, ctx); self.pre_scan_builtin_expr(&call.callee, excluded, ctx);
for arg in &call.arguments { for arg in &call.arguments {
self.pre_scan_builtin_arg(arg, ctx); self.pre_scan_builtin_arg(arg, excluded, ctx);
} }
} }
_ => {} _ => {}
@@ -317,41 +333,41 @@ impl Emitter {
} }
/// 遍历调用实参:spread 内部表达式也纳入 builtin 预扫描。 /// 遍历调用实参:spread 内部表达式也纳入 builtin 预扫描。
fn pre_scan_builtin_arg(&self, arg: &oxide_parser::Argument, ctx: &mut CompileCtx) { fn pre_scan_builtin_arg(&self, arg: &oxide_parser::Argument, excluded: &HashSet<String>, ctx: &mut CompileCtx) {
if let Some(e) = arg.as_expression() { if let Some(e) = arg.as_expression() {
self.pre_scan_builtin_expr(e, ctx); self.pre_scan_builtin_expr(e, excluded, ctx);
} else if let oxide_parser::Argument::SpreadElement(sp) = arg { } else if let oxide_parser::Argument::SpreadElement(sp) = arg {
self.pre_scan_builtin_expr(&sp.argument, ctx); self.pre_scan_builtin_expr(&sp.argument, excluded, ctx);
} }
} }
/// 遍历绑定 pattern 的计算键表达式(`{[k]: a}` 的键)里的 builtin 引用: /// 遍历绑定 pattern 的计算键表达式(`{[k]: a}` 的键)里的 builtin 引用:
/// 模式键是运行时求值表达式,键内 builtin 标识符须预先登记固定槽位 /// 模式键是运行时求值表达式,键内 builtin 标识符须预先登记固定槽位
/// (与对象字面量计算键预扫描同口径)。 /// (与对象字面量计算键预扫描同口径)。
fn pre_scan_builtin_pattern(&self, pattern: &BindingPattern, ctx: &mut CompileCtx) { fn pre_scan_builtin_pattern(&self, pattern: &BindingPattern, excluded: &HashSet<String>, ctx: &mut CompileCtx) {
match pattern { match pattern {
BindingPattern::BindingIdentifier(_) => {} BindingPattern::BindingIdentifier(_) => {}
BindingPattern::ArrayPattern(ap) => { BindingPattern::ArrayPattern(ap) => {
for e in ap.elements.iter().flatten() { for e in ap.elements.iter().flatten() {
self.pre_scan_builtin_pattern(e, ctx); self.pre_scan_builtin_pattern(e, excluded, ctx);
} }
if let Some(rest) = &ap.rest { if let Some(rest) = &ap.rest {
self.pre_scan_builtin_pattern(&rest.argument, ctx); self.pre_scan_builtin_pattern(&rest.argument, excluded, ctx);
} }
} }
BindingPattern::ObjectPattern(op) => { BindingPattern::ObjectPattern(op) => {
for prop in &op.properties { for prop in &op.properties {
if prop.computed { if prop.computed {
self.pre_scan_builtin_expr(prop.key.to_expression(), ctx); self.pre_scan_builtin_expr(prop.key.to_expression(), excluded, ctx);
} }
self.pre_scan_builtin_pattern(&prop.value, ctx); self.pre_scan_builtin_pattern(&prop.value, excluded, ctx);
} }
if let Some(rest) = &op.rest { if let Some(rest) = &op.rest {
self.pre_scan_builtin_pattern(&rest.argument, ctx); self.pre_scan_builtin_pattern(&rest.argument, excluded, ctx);
} }
} }
BindingPattern::AssignmentPattern(ap) => { BindingPattern::AssignmentPattern(ap) => {
self.pre_scan_builtin_pattern(&ap.left, ctx); self.pre_scan_builtin_pattern(&ap.left, excluded, ctx);
} }
} }
} }
+4 -1
View File
@@ -301,7 +301,10 @@ impl Emitter {
self.predeclare_function_declarations(&program.body, &mut ctx); self.predeclare_function_declarations(&program.body, &mut ctx);
// 预注册 builtin 引用(先于任何临时寄存器),builtin 槽不进入临时寄存器池。 // 预注册 builtin 引用(先于任何临时寄存器),builtin 槽不进入临时寄存器池。
self.pre_register_builtin_references(&program.body, &mut ctx); // 顶层词法声明名(let/const/class)排除登记:词法绑定遮蔽同名全局属性,
// 镜像占位先建会与词法预声明撞 scope 0 致合法遮蔽形被编译期误拒。
let lexical_excluded = collect_direct_lexical_names(&program.body);
self.pre_register_builtin_references(&program.body, &lexical_excluded, &mut ctx);
// 预声明顶层 `var` 名,使首个 sub-pass 中提升的函数声明能解析外层 var。 // 预声明顶层 `var` 名,使首个 sub-pass 中提升的函数声明能解析外层 var。
self.predeclare_var_declarations(&program.body, &mut ctx); self.predeclare_var_declarations(&program.body, &mut ctx);
+11
View File
@@ -23,6 +23,10 @@ pub(crate) struct Binding {
pub(crate) reg: u32, pub(crate) reg: u32,
pub(crate) initialized: bool, pub(crate) initialized: bool,
pub(crate) is_const: bool, pub(crate) is_const: bool,
/// 词法(let/const/class/导入)绑定:写臂谓词据此拒绝全局内置槽解析——
/// 顶层词法绑定遮蔽同名全局属性,写不落全局对象(var/隐式全局/镜像占位
/// 不置位,其值存储本就是全局对象属性)。
pub(crate) lexical: bool,
/// 由块/函数级预声明(TDZ 占位)创建,声明点据此复用槽位。 /// 由块/函数级预声明(TDZ 占位)创建,声明点据此复用槽位。
/// 非预声明的同名绑定(如同 scope 的参数/var)不计,避免误复用。 /// 非预声明的同名绑定(如同 scope 的参数/var)不计,避免误复用。
pub(crate) predeclared: bool, pub(crate) predeclared: bool,
@@ -109,6 +113,7 @@ impl SymbolTable {
reg, reg,
initialized: false, initialized: false,
is_const: matches!(kind, VariableDeclarationKind::Const) || is_const, is_const: matches!(kind, VariableDeclarationKind::Const) || is_const,
lexical: !matches!(kind, VariableDeclarationKind::Var),
predeclared: false, predeclared: false,
}, },
); );
@@ -172,6 +177,7 @@ impl SymbolTable {
reg: reg_for_new, reg: reg_for_new,
initialized: true, initialized: true,
is_const: false, is_const: false,
lexical: false,
predeclared: false, predeclared: false,
}, },
); );
@@ -212,6 +218,7 @@ impl SymbolTable {
reg, reg,
initialized: true, initialized: true,
is_const: matches!(kind, VariableDeclarationKind::Const) || is_const, is_const: matches!(kind, VariableDeclarationKind::Const) || is_const,
lexical: !matches!(kind, VariableDeclarationKind::Var),
predeclared: false, predeclared: false,
}, },
); );
@@ -224,6 +231,7 @@ impl SymbolTable {
reg, reg,
initialized: true, initialized: true,
is_const: false, is_const: false,
lexical: false,
predeclared: false, predeclared: false,
}); });
} }
@@ -248,6 +256,7 @@ impl SymbolTable {
reg, reg,
initialized: false, initialized: false,
is_const: matches!(kind, VariableDeclarationKind::Const) || is_const, is_const: matches!(kind, VariableDeclarationKind::Const) || is_const,
lexical: !matches!(kind, VariableDeclarationKind::Var),
predeclared: true, predeclared: true,
}, },
); );
@@ -306,6 +315,8 @@ impl SymbolTable {
reg, reg,
initialized, initialized,
is_const: true, is_const: true,
// 导入绑定是模块作用域词法(const)绑定,同 let/const 置位。
lexical: true,
predeclared: false, predeclared: false,
}, },
); );
@@ -0,0 +1,244 @@
//! 顶层/模块词法声明遮蔽可配置全局内置名的合法化:let/const/class 声明名撞
//! 非受限 builtin 名(Math/Array/isNaN/Promise 等可配置全局属性)时,镜像槽
//! 不为其登记,声明合法建立遮蔽绑定——裸读读绑定槽、裸写/delete 不落全局
//! 对象(全局属性原值保留),声明点前裸读按 TDZ 运行期抛 ReferenceError。
//!
//! 回归约束:受限三常量(87 面)声明仍编译期拒绝;let+var / function+let
//! 撞 builtin 名的重复声明仍编译期拒绝(var 懒登记镜像与函数先登记撞点保留);
//! 未遮蔽 builtin 读、var 内置名写全局、函数内遮蔽读不回退。
use std::sync::Arc;
use oxide_compiler::compiler::Compiler;
use oxide_emit::module::{ModuleSourceLoader, ResolvedModule};
use oxide_types::value::JsValue;
use oxide_vm::vm::Vm;
fn eval(source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile: {}", e))?;
let mut vm = Vm::new();
vm.run(&Arc::new(module))
}
fn eval_str(source: &str) -> Result<String, String> {
let value = eval(source)?;
if value.is_string() {
// SAFETY: 值已确认字符串类别,指针指向 VM 存活期内的 JsString。
Ok(unsafe { &*value.as_string_ptr() }.as_str().to_string())
} else {
Err(format!("expected string, got {value:?}"))
}
}
/// 断言整程序编译失败且错消息为重复声明错形(声明实例化期拒绝)。
fn assert_compile_err(source: &str) {
let err = eval(source).unwrap_err();
assert!(err.contains("already been declared"), "got: {err}");
}
/// 断言编译 + 运行均成功,返回完成值。
fn assert_ok(source: &str) -> JsValue {
eval(source).unwrap_or_else(|e| panic!("expected ok, got: {e}\nsource: {source}"))
}
struct Loader;
impl ModuleSourceLoader for Loader {
fn resolve(
&mut self, _base_dir: &str, _specifier: &str, _attributes: &[(&str, &str)],
) -> Result<ResolvedModule, String> {
Err("no deps".into())
}
}
fn eval_module(source: &str) -> Result<JsValue, String> {
let allocator = oxide_parser::Allocator::default();
let program = oxide_parser::parse_module(&allocator, source).map_err(|e| format!("Parse: {:?}", e))?;
let module = Compiler::new()
.compile_module(&program, "test.mjs", &mut Loader)
.map_err(|e| format!("Compile: {}", e))?;
let mut vm = Vm::new();
vm.run(&Arc::new(module))
}
// ── 声明形 × builtin 名矩阵:编译过 + 读回声明值(修前全格编译期拒) ──
#[test]
fn top_level_let_math_shadow() {
let r = assert_ok("let Math=1; Math");
assert_eq!(r.as_int(), 1);
}
#[test]
fn top_level_const_math_shadow() {
let r = assert_ok("const Math=1; Math");
assert_eq!(r.as_int(), 1);
}
#[test]
fn top_level_class_math_shadow() {
assert_eq!(eval_str("class Math{} typeof Math").unwrap(), "function");
}
#[test]
fn top_level_let_isnan_shadow() {
// isNaN 是可配置全局函数名(非受限三常量),合法遮蔽。
let r = assert_ok("let isNaN=5; isNaN");
assert_eq!(r.as_int(), 5);
}
#[test]
fn top_level_const_array_shadow() {
// 语料钉 decl-lex-configurable-global.js 同形:可配置全局属性被遮蔽,
// 全局对象属性原值保留。
let r = assert_ok("const Array=7; Array");
assert_eq!(r.as_int(), 7);
}
#[test]
fn top_level_class_promise_shadow() {
assert_eq!(eval_str("class Promise{} typeof Promise").unwrap(), "function");
}
#[test]
fn top_level_let_destructured_builtin_shadow() {
// 解构叶子同属声明名,排除集覆盖。
let r = assert_ok("let {0: Math} = [3]; Math");
assert_eq!(r.as_int(), 3);
}
// ── 写臂 / delete 臂:值落绑定槽,全局对象属性不动 ──
#[test]
fn top_level_let_shadow_write_not_global() {
// 裸写与复合写都只更新绑定槽;globalThis.Math 保留原对象。
let r = assert_ok("let Math=1; Math=2; Math");
assert_eq!(r.as_int(), 2);
let r = assert_ok("let Math=1; Math+=1; Math");
assert_eq!(r.as_int(), 2);
assert_eq!(eval_str("let Math=1; Math=2; typeof globalThis.Math").unwrap(), "object");
}
#[test]
fn top_level_let_shadow_delete_not_global() {
// 词法绑定 delete 返 false(DeleteBinding 非属性引用),全局属性原值保留。
let r = assert_ok("let Math=1; delete Math");
assert!(r.is_bool() && !r.as_bool(), "实际 {r:?}");
let r = assert_ok("let Math=1; delete Math; Math");
assert_eq!(r.as_int(), 1);
assert_eq!(eval_str("let Math=1; delete Math; typeof globalThis.Math").unwrap(), "object");
}
#[test]
fn nested_fn_write_top_level_let_shadow() {
// 嵌套函数写顶层词法绑定经 upvalue cell,同样不落全局对象。
let r = assert_ok("let Math=1; (function(){Math=2})(); Math");
assert_eq!(r.as_int(), 2);
assert_eq!(eval_str("let Math=1; (function(){Math=2})(); typeof globalThis.Math").unwrap(), "object");
}
// ── TDZ 相位:声明点前裸读是运行期 ReferenceError(修前编译期拒) ──
#[test]
fn top_level_let_shadow_tdz_read_throws() {
let err = eval("Math; let Math=1;").unwrap_err();
assert!(err.contains("before initialization"), "got: {err}");
}
#[test]
fn top_level_let_shadow_tdz_second_read_throws() {
let err = eval("Math; let Math=1; Math").unwrap_err();
assert!(err.contains("before initialization"), "got: {err}");
}
// ── 回归约束:受限名与重复声明拒面不翻 ──
#[test]
fn top_level_let_restricted_names_still_rejected() {
// 受限三常量(87 面):非受限名修面不动此面,声明仍编译期拒绝。
assert_compile_err("let undefined;");
assert_compile_err("let NaN=1; NaN");
}
#[test]
fn let_then_var_builtin_name_still_rejected() {
// var 预声明懒登记镜像:排除集只挡预扫描臂,var 臂撞点保留。
assert_compile_err("let Math=1; var Math;");
}
#[test]
fn function_then_let_builtin_name_still_rejected() {
// 函数声明先登记(提升 var 绑定):撞点保留。
assert_compile_err("function Math(){} let Math=1;");
}
// ── 绿格回归:遮蔽不得回退未遮蔽面 ──
#[test]
fn closure_reads_top_level_let_shadow() {
let r = assert_ok("let Math=1; (function(){return Math})()");
assert_eq!(r.as_int(), 1);
}
#[test]
fn let_shadow_without_reference_compiles() {
let r = assert_ok("let Math=1; 42");
assert_eq!(r.as_int(), 42);
}
#[test]
fn fn_decl_before_let_shadow_reads_via_capture() {
let r = assert_ok("function f(){return Math} let Math=1; f()");
assert_eq!(r.as_int(), 1);
}
#[test]
fn var_builtin_name_local_read() {
// var 内置名的本地读值不受本修影响(var 臂不置 lexical 标志)。
let r = assert_ok("var Math=1; Math");
assert_eq!(r.as_int(), 1);
}
#[test]
fn unshadowed_builtin_read_unchanged() {
// 一元负号经 ToNumber 落 double 标签,断言按数值比。
let r = assert_ok("let x=1; Math.abs(-1)");
assert_eq!(r.as_double(), 1.0);
let r = assert_ok("let Math=1; parseInt('42')");
assert_eq!(r.as_int(), 42);
}
// ── 模块面:同形声明合法化,全局对象属性不动 ──
#[test]
fn module_let_math_shadow_runs() {
let r = eval_module("let Math=1; Math;").expect("module compile+run");
assert!(r.is_undefined(), "顶层模块完成值应为 undefined,实际 {r:?}");
}
#[test]
fn module_let_shadow_keeps_global() {
let r = eval_module("let Math=1; Math=2; Math;").expect("module compile+run");
assert!(r.is_undefined(), "实际 {r:?}");
assert_eq!(eval_str("typeof globalThis.Math").unwrap(), "object");
}
#[test]
fn module_const_array_shadow_runs() {
let r = eval_module("const Array=7; Array;").expect("module compile+run");
assert!(r.is_undefined(), "实际 {r:?}");
}
#[test]
fn module_class_promise_shadow_runs() {
let r = eval_module("class Promise{} Promise;").expect("module compile+run");
assert!(r.is_undefined(), "实际 {r:?}");
}
#[test]
fn module_let_shadow_tdz_read_throws() {
let err = eval_module("Math; let Math=1;").unwrap_err();
assert!(err.contains("before initialization"), "got: {err}");
}