Skip to content

Commit

Permalink
feat(ecma-analyzer): support super() call in class ctor
Browse files Browse the repository at this point in the history
  • Loading branch information
kwonoj committed Jun 27, 2023
1 parent 41ac57a commit 9ccc415
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 2 deletions.
23 changes: 22 additions & 1 deletion crates/turbopack-ecmascript/src/analyzer/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,21 @@ impl EvalContext {
}
}

Expr::Call(CallExpr {
callee: Callee::Super(_),
args,
..
}) => {
// We currently do not handle spreads.
if args.iter().any(|arg| arg.spread.is_some()) {
return JsValue::unknown_empty("spread in function calls is not supported");
}

let args = args.iter().map(|arg| self.eval(&arg.expr)).collect();

JsValue::callee_super(args)
}

Expr::Call(CallExpr {
callee: Callee::Import(_),
args,
Expand Down Expand Up @@ -898,7 +913,13 @@ impl Analyzer<'_> {
});
}
}
_ => {}
Callee::Super(_) => self.add_effect(Effect::Call {
func: JsValue::FreeVar(js_word!("super")),
args,
ast_path: as_parent_path(ast_path),
span: n.span(),
in_try: is_in_try(ast_path),
}),
}
}

Expand Down
79 changes: 78 additions & 1 deletion crates/turbopack-ecmascript/src/analyzer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,9 @@ pub enum JsValue {
/// A function call without a this context.
/// `(total_node_count, callee, args)`
Call(usize, Box<JsValue>, Vec<JsValue>),
/// A super call to the parent constructor.
/// `(total_node_count, args)`
Super(usize, Vec<JsValue>),
/// A function call with a this context.
/// `(total_node_count, obj, prop, args)`
MemberCall(usize, Box<JsValue>, Box<JsValue>, Vec<JsValue>),
Expand Down Expand Up @@ -586,6 +589,14 @@ impl Display for JsValue {
.collect::<Vec<_>>()
.join(", ")
),
JsValue::Super(_, list) => write!(
f,
"super({})",
list.iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join(", ")
),
JsValue::MemberCall(_, obj, prop, list) => write!(
f,
"{}[{}]({})",
Expand Down Expand Up @@ -680,6 +691,7 @@ impl JsValue {
| JsValue::Logical(..)
| JsValue::Binary(..)
| JsValue::Call(..)
| JsValue::Super(..)
| JsValue::MemberCall(..) => JsValueMetaKind::Operation,
JsValue::Variable(..)
| JsValue::Argument(..)
Expand Down Expand Up @@ -811,6 +823,10 @@ impl JsValue {
Self::Call(1 + f.total_nodes() + total_nodes(&args), f, args)
}

pub fn callee_super(args: Vec<JsValue>) -> Self {
Self::Super(1 + total_nodes(&args), args)
}

pub fn member_call(o: Box<JsValue>, p: Box<JsValue>, args: Vec<JsValue>) -> Self {
Self::MemberCall(
1 + o.total_nodes() + p.total_nodes() + total_nodes(&args),
Expand Down Expand Up @@ -856,6 +872,7 @@ impl JsValue {
| JsValue::Logical(c, _, _)
| JsValue::Binary(c, _, _, _)
| JsValue::Call(c, _, _)
| JsValue::Super(c, _)
| JsValue::MemberCall(c, _, _, _)
| JsValue::Member(c, _, _)
| JsValue::Function(c, _, _) => *c,
Expand Down Expand Up @@ -909,6 +926,9 @@ impl JsValue {
JsValue::Call(c, f, list) => {
*c = 1 + f.total_nodes() + total_nodes(list);
}
JsValue::Super(c, list) => {
*c = 1 + total_nodes(list);
}
JsValue::MemberCall(c, o, m, list) => {
*c = 1 + o.total_nodes() + m.total_nodes() + total_nodes(list);
}
Expand Down Expand Up @@ -988,6 +1008,10 @@ impl JsValue {
make_max_unknown([&mut **f].into_iter().chain(args.iter_mut()));
self.update_total_nodes();
}
JsValue::Super(_, args) => {
make_max_unknown(args.iter_mut());
self.update_total_nodes();
}
JsValue::MemberCall(_, o, p, args) => {
make_max_unknown([&mut **o, &mut **p].into_iter().chain(args.iter_mut()));
self.update_total_nodes();
Expand Down Expand Up @@ -1232,6 +1256,26 @@ impl JsValue {
)
)
}
JsValue::Super(_, list) => {
format!(
"super({})",
pretty_join(
&list
.iter()
.map(|v| v.explain_internal_inner(
hints,
indent_depth + 1,
depth,
unknown_depth
))
.collect::<Vec<_>>(),
indent_depth,
", ",
",",
""
)
)
}
JsValue::MemberCall(_, obj, prop, list) => {
format!(
"{}[{}]({})",
Expand Down Expand Up @@ -1831,7 +1875,8 @@ impl JsValue {
| JsValue::Argument(..)
| JsValue::Call(..)
| JsValue::MemberCall(..)
| JsValue::Member(..) => None,
| JsValue::Member(..)
| JsValue::Super(..) => None,
}
}

Expand Down Expand Up @@ -2035,6 +2080,18 @@ macro_rules! for_each_children_async {
$value.update_total_nodes();
($value, modified)
}
JsValue::Super(_, list) => {
let mut modified = false;
for item in list.iter_mut() {
let (v, m) = $visit_fn(take(item), $($args),+).await?;
*item = v;
if m {
modified = true
}
}
$value.update_total_nodes();
($value, modified)
}
JsValue::MemberCall(_, box obj, box prop, list) => {
let (new_callee, m1) = $visit_fn(take(obj), $($args),+).await?;
*obj = new_callee;
Expand Down Expand Up @@ -2301,6 +2358,18 @@ impl JsValue {
}
modified
}
JsValue::Super(_, list) => {
let mut modified = false;
for item in list.iter_mut() {
if visitor(item) {
modified = true
}
}
if modified {
self.update_total_nodes();
}
modified
}
JsValue::MemberCall(_, obj, prop, list) => {
let m1 = visitor(obj);
let m2 = visitor(prop);
Expand Down Expand Up @@ -2469,6 +2538,11 @@ impl JsValue {
visitor(item);
}
}
JsValue::Super(_, list) => {
for item in list.iter() {
visitor(item);
}
}
JsValue::MemberCall(_, obj, prop, list) => {
visitor(obj);
visitor(prop);
Expand Down Expand Up @@ -2805,6 +2879,9 @@ impl JsValue {
a.similar_hash(state, depth - 1);
all_similar_hash(b, state, depth - 1);
}
JsValue::Super(_, a) => {
all_similar_hash(a, state, depth - 1);
}
JsValue::MemberCall(_, a, b, c) => {
a.similar_hash(state, depth - 1);
b.similar_hash(state, depth - 1);
Expand Down

0 comments on commit 9ccc415

Please sign in to comment.