Skip to content

Commit

Permalink
fix(es/compat): Fix new.target in a nested scope (#6296)
Browse files Browse the repository at this point in the history
  • Loading branch information
Austaras committed Oct 31, 2022
1 parent 4f353ac commit aa18612
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 200 deletions.
20 changes: 10 additions & 10 deletions crates/swc/tests/tsc-references/newTarget.es5.1.normal.js
Expand Up @@ -5,14 +5,14 @@ import _instanceof from "@swc/helpers/src/_instanceof.mjs";
import _create_super from "@swc/helpers/src/_create_super.mjs";
var A = function A() {
"use strict";
var _newtarget = _instanceof(this, A) ? this.constructor : void 0;
var _this = this;
_class_call_check(this, A);
this.d = function _target() {
return _instanceof(this, _target) ? this.constructor : void 0;
};
var a = _instanceof(this, A) ? this.constructor : void 0;
var b = function() {
return _newtarget;
return _instanceof(_this, A) ? _this.constructor : void 0;
};
};
A.c = function _target() {
Expand All @@ -23,29 +23,29 @@ var B = /*#__PURE__*/ function _target(A) {
_inherits(B, A);
var _super = _create_super(B);
function B() {
var _newtarget = _instanceof(this, B) ? this.constructor : void 0;
var _this = this;
_class_call_check(this, B);
var _this = _super.call(this);
var _this1 = _super.call(this);
var e = _instanceof(this, B) ? this.constructor : void 0;
var f = function() {
return _newtarget;
return _instanceof(_this, B) ? _this.constructor : void 0;
};
return _this;
return _this1;
}
return B;
}(A);
function f1() {
var _newtarget = _instanceof(this, f1) ? this.constructor : void 0;
var _this = this;
var g = _instanceof(this, f1) ? this.constructor : void 0;
var h = function() {
return _newtarget;
return _instanceof(_this, f1) ? _this.constructor : void 0;
};
}
var f2 = function _target() {
var _newtarget = _instanceof(this, _target) ? this.constructor : void 0;
var _this = this;
var i = _instanceof(this, _target) ? this.constructor : void 0;
var j = function() {
return _newtarget;
return _instanceof(_this, _target) ? _this.constructor : void 0;
};
};
var O = {
Expand Down
153 changes: 29 additions & 124 deletions crates/swc_ecma_transforms_compat/src/es2015/new_target.rs
@@ -1,142 +1,85 @@
use std::borrow::Cow;
use std::{borrow::Cow, mem};

use swc_common::{pass::CompilerPass, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_transforms_base::perf::{should_work, Check};
use swc_ecma_utils::{prepend_stmt, private_ident, quote_ident, undefined, ExprFactory};
use swc_ecma_utils::{private_ident, quote_ident, undefined, ExprFactory};
use swc_ecma_visit::{
as_folder, noop_visit_mut_type, noop_visit_type, Fold, Visit, VisitMut, VisitMutWith,
};
use swc_trace_macro::swc_trace;

#[tracing::instrument(level = "info", skip_all)]
pub fn new_target() -> impl Fold + VisitMut + CompilerPass {
as_folder(NewTarget::default())
as_folder(NewTarget {
ctx: Ctx::Constructor,
})
}

#[derive(Default)]

struct NewTarget {
cur: Option<Ident>,

in_constructor: bool,
in_method: bool,
in_arrow_expr: bool,
ctx: Ctx,
}

var: Option<VarDeclarator>,
enum Ctx {
Constructor,
Method,
Function(Ident),
}

impl NewTarget {
fn visit_mut_method<T: VisitMutWith<Self>>(&mut self, c: &mut T) {
let old = self.in_method;

self.in_method = true;
let old = mem::replace(&mut self.ctx, Ctx::Method);

c.visit_mut_with(self);

self.in_method = old;
self.ctx = old;
}
}

#[swc_trace]
impl VisitMut for NewTarget {
noop_visit_mut_type!();

fn visit_mut_arrow_expr(&mut self, e: &mut ArrowExpr) {
// Ensure that `e` contains new.target
if !should_work::<ShouldWork, _>(&*e) {
return;
}

let old = self.in_arrow_expr;
if self.var.is_none() {
let mut v = Expr::MetaProp(MetaPropExpr {
span: DUMMY_SP,
kind: MetaPropKind::NewTarget,
});
v.visit_mut_with(self);
self.var.get_or_insert_with(|| VarDeclarator {
span: DUMMY_SP,
name: private_ident!("_newtarget").into(),
init: Some(Box::new(v)),
definite: Default::default(),
});
}
self.in_arrow_expr = true;
e.visit_mut_children_with(self);

self.in_arrow_expr = old;
}

fn visit_mut_class_decl(&mut self, class: &mut ClassDecl) {
let old = self.cur.take();
self.cur = Some(class.ident.clone());

class.visit_mut_children_with(self);

self.cur = old;
}

fn visit_mut_class_expr(&mut self, class: &mut ClassExpr) {
let old = self.cur.take();
self.cur = class.ident.clone();

class.visit_mut_children_with(self);

self.cur = old;
}

fn visit_mut_class_method(&mut self, c: &mut ClassMethod) {
c.key.visit_mut_with(self);

self.visit_mut_method(&mut c.function)
}

fn visit_mut_constructor(&mut self, c: &mut Constructor) {
let old = self.in_constructor;

self.in_constructor = true;
self.in_arrow_expr = false;
self.var = None;
let old = mem::replace(&mut self.ctx, Ctx::Constructor);

c.visit_mut_children_with(self);

self.in_constructor = old;
self.ctx = old;
}

fn visit_mut_expr(&mut self, e: &mut Expr) {
e.visit_mut_children_with(self);

if let Expr::MetaProp(MetaPropExpr {
kind: MetaPropKind::NewTarget,
..
span,
}) = e
{
if self.in_arrow_expr {
*e = Expr::Ident(self.var.as_ref().unwrap().name.clone().ident().unwrap().id);
} else if self.in_method {
*e = *undefined(DUMMY_SP)
} else if let Some(cur) = self.cur.clone() {
let c = ThisExpr { span: DUMMY_SP }.make_member(quote_ident!("constructor"));

if self.in_constructor {
*e = c;
} else {
// (this instanceof Foo ? this.constructor : void 0)
let this_ctor = |span| ThisExpr { span }.make_member(quote_ident!("constructor"));
match &self.ctx {
Ctx::Constructor => *e = this_ctor(*span),
Ctx::Method => *e = *undefined(DUMMY_SP),
Ctx::Function(i) => {
*e = Expr::Cond(CondExpr {
span: DUMMY_SP,
span: *span,
// this instanceof Foo
test: Box::new(Expr::Bin(BinExpr {
span: DUMMY_SP,
op: op!("instanceof"),
left: Box::new(Expr::This(ThisExpr { span: DUMMY_SP })),
right: Box::new(Expr::Ident(cur)),
right: Box::new(Expr::Ident(i.clone())),
})),
// this.constructor
cons: Box::new(c),
cons: Box::new(this_ctor(DUMMY_SP)),
// void 0
alt: undefined(DUMMY_SP),
});
})
}
}
}
Expand All @@ -148,12 +91,11 @@ impl VisitMut for NewTarget {
return;
}

let old = self.cur.take();
self.cur = Some(f.ident.clone());
let old = mem::replace(&mut self.ctx, Ctx::Function(f.ident.clone()));

f.visit_mut_children_with(self);

self.cur = old;
self.ctx = old;
}

fn visit_mut_fn_expr(&mut self, f: &mut FnExpr) {
Expand All @@ -167,12 +109,11 @@ impl VisitMut for NewTarget {
.get_or_insert_with(|| private_ident!("_target"))
.clone();

let old = self.cur.take();
self.cur = Some(i);
let old = mem::replace(&mut self.ctx, Ctx::Function(i));

f.visit_mut_children_with(self);

self.cur = old;
self.ctx = old;
}

fn visit_mut_method_prop(&mut self, m: &mut MethodProp) {
Expand All @@ -189,42 +130,6 @@ impl VisitMut for NewTarget {
m.key.visit_mut_with(self);
self.visit_mut_method(&mut m.body)
}

fn visit_mut_module_items(&mut self, stmts: &mut Vec<ModuleItem>) {
stmts.visit_mut_children_with(self);

if let Some(var) = self.var.take() {
prepend_stmt(
stmts,
VarDecl {
span: DUMMY_SP,
kind: VarDeclKind::Var,
declare: false,
decls: vec![var],
}
.into(),
)
}
}

fn visit_mut_stmts(&mut self, stmts: &mut Vec<Stmt>) {
stmts.visit_mut_children_with(self);

if !self.in_arrow_expr {
if let Some(var) = self.var.take() {
prepend_stmt(
stmts,
VarDecl {
span: DUMMY_SP,
kind: VarDeclKind::Var,
declare: false,
decls: vec![var],
}
.into(),
)
}
}
}
}

impl CompilerPass for NewTarget {
Expand Down

1 comment on commit aa18612

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: aa18612 Previous: a27392a Ratio
es/full/bugs-1 351971 ns/iter (± 20548) 344901 ns/iter (± 19080) 1.02
es/full/minify/libraries/antd 1875886032 ns/iter (± 53111060) 1850563958 ns/iter (± 28224724) 1.01
es/full/minify/libraries/d3 411103145 ns/iter (± 12359547) 418588860 ns/iter (± 19747342) 0.98
es/full/minify/libraries/echarts 1624703672 ns/iter (± 79742447) 1585651210 ns/iter (± 29271089) 1.02
es/full/minify/libraries/jquery 102824100 ns/iter (± 5093030) 96055461 ns/iter (± 3158109) 1.07
es/full/minify/libraries/lodash 119810701 ns/iter (± 9080479) 118473201 ns/iter (± 3286074) 1.01
es/full/minify/libraries/moment 61544495 ns/iter (± 5829520) 59382237 ns/iter (± 1652427) 1.04
es/full/minify/libraries/react 20428021 ns/iter (± 311051) 20159284 ns/iter (± 477236) 1.01
es/full/minify/libraries/terser 315736125 ns/iter (± 17896768) 305561389 ns/iter (± 9296521) 1.03
es/full/minify/libraries/three 586047547 ns/iter (± 66980698) 559008719 ns/iter (± 14668052) 1.05
es/full/minify/libraries/typescript 3793645317 ns/iter (± 261847808) 3473317368 ns/iter (± 19811735) 1.09
es/full/minify/libraries/victory 917659503 ns/iter (± 73381197) 826905747 ns/iter (± 8589207) 1.11
es/full/minify/libraries/vue 176434100 ns/iter (± 29706781) 153275973 ns/iter (± 4584184) 1.15
es/full/codegen/es3 35629 ns/iter (± 2791) 33579 ns/iter (± 1023) 1.06
es/full/codegen/es5 36172 ns/iter (± 4660) 33654 ns/iter (± 460) 1.07
es/full/codegen/es2015 36916 ns/iter (± 8757) 33682 ns/iter (± 760) 1.10
es/full/codegen/es2016 36001 ns/iter (± 3381) 33715 ns/iter (± 520) 1.07
es/full/codegen/es2017 35587 ns/iter (± 1271) 33556 ns/iter (± 819) 1.06
es/full/codegen/es2018 36276 ns/iter (± 4130) 33578 ns/iter (± 1054) 1.08
es/full/codegen/es2019 36033 ns/iter (± 6125) 33546 ns/iter (± 1032) 1.07
es/full/codegen/es2020 36128 ns/iter (± 3438) 33579 ns/iter (± 758) 1.08
es/full/all/es3 195972167 ns/iter (± 50631928) 190862022 ns/iter (± 5666350) 1.03
es/full/all/es5 183622475 ns/iter (± 29222935) 185485596 ns/iter (± 6618037) 0.99
es/full/all/es2015 147974242 ns/iter (± 31207476) 145531348 ns/iter (± 4491505) 1.02
es/full/all/es2016 146424274 ns/iter (± 33058729) 145919692 ns/iter (± 6444791) 1.00
es/full/all/es2017 145490592 ns/iter (± 25626012) 139031641 ns/iter (± 4964042) 1.05
es/full/all/es2018 145401391 ns/iter (± 43498030) 138092431 ns/iter (± 3814047) 1.05
es/full/all/es2019 144939270 ns/iter (± 42058843) 137047490 ns/iter (± 3260987) 1.06
es/full/all/es2020 140576784 ns/iter (± 30344529) 135193740 ns/iter (± 8330172) 1.04
es/full/parser 731535 ns/iter (± 190700) 721489 ns/iter (± 24919) 1.01
es/full/base/fixer 26958 ns/iter (± 2345) 26226 ns/iter (± 942) 1.03
es/full/base/resolver_and_hygiene 93331 ns/iter (± 7559) 91943 ns/iter (± 2121) 1.02
serialization of ast node 216 ns/iter (± 12) 213 ns/iter (± 3) 1.01
serialization of serde 219 ns/iter (± 18) 214 ns/iter (± 3) 1.02

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.