Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a2328a1
initial work for compile-time evaluation
sokra Jan 26, 2023
ab9eebe
add logical operations
sokra Jan 26, 2023
735fb2f
organize, comment, simplify
sokra Jan 27, 2023
91dd467
bugfixes and improvements
sokra Jan 27, 2023
1a5cc04
cleanup, review
sokra Jan 30, 2023
f557ee3
add react-dom test case
sokra Jan 30, 2023
49c65b4
fix test case
sokra Jan 30, 2023
7ba8e87
update snapshots
sokra Jan 30, 2023
a1df5d5
early evaluate operations besed on partial info for performance
sokra Jan 30, 2023
5afa09e
make alternatives duplication detection cheaper
sokra Jan 30, 2023
a5965d3
clippy, update snapshots
sokra Jan 30, 2023
33bc831
heavvy refactoring, fixes arguments problem, removes cache
sokra Jan 31, 2023
b199016
snapshot effects in analyzer tests
sokra Feb 1, 2023
f3dd2bd
refactor to use nested effects in closures
sokra Feb 1, 2023
5069bc8
add special behavior for array methods called with closures
sokra Feb 1, 2023
f32943a
fix test case
sokra Feb 1, 2023
d573980
remove println
sokra Feb 1, 2023
ab246b8
handle closures for unknown calls too
sokra Feb 1, 2023
641312a
more debug checks, fix node update
sokra Feb 1, 2023
7a27fef
clippy
sokra Feb 1, 2023
25d5d7a
function might implict return undefined
sokra Feb 1, 2023
4ce3efc
Merge branch 'main' into sokra/web-492-handle-if-statements
sokra Feb 2, 2023
e49eef1
Merge remote-tracking branch 'origin/main' into sokra/web-492-handle-…
sokra Feb 3, 2023
e731362
Merge remote-tracking branch 'origin/main' into sokra/web-492-handle-…
sokra Feb 3, 2023
7c1798f
clippy
sokra Feb 3, 2023
b986c17
review, bugfixes, comments
sokra Feb 3, 2023
f584071
fix fn name
sokra Feb 3, 2023
b593ef6
remove println
sokra Feb 3, 2023
0c4871b
add comment
sokra Feb 3, 2023
f985370
move test code into input folder
sokra Feb 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
it("importing a not existing file should throw", () => {
// This is a check to make sure that the following tests would fail if they require("fail")
expect(() => {
require("./not-existing-file");
}).toThrow();
});

function maybeReturn(x) {
if (x) {
return true;
Expand Down
2 changes: 1 addition & 1 deletion crates/turbopack-core/src/reference_type.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fmt::Display;

// These enums list well known types, which we use internally. Plugins might add
// These enums list well-known types, which we use internally. Plugins might add
// custom types too.

// TODO when plugins are supported, replace u8 with a trait that defines the
Expand Down
162 changes: 133 additions & 29 deletions crates/turbopack-ecmascript/src/analyzer/builtin.rs

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions crates/turbopack-ecmascript/src/analyzer/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -983,7 +983,7 @@ impl VisitAstPath for Analyzer<'_> {
if arg.spread.is_none() {
let value = self.eval_context.eval(&arg.expr);

if let Some(path) = match &*arg.expr {
let block_path = match &*arg.expr {
Expr::Fn(FnExpr { .. }) => {
let mut path = as_parent_path(ast_path);
path.push(AstParentKind::ExprOrSpread(
Expand Down Expand Up @@ -1025,7 +1025,8 @@ impl VisitAstPath for Analyzer<'_> {
Some(path)
}
_ => None,
} {
};
if let Some(path) = block_path {
let old_effects = take(&mut self.effects);
arg.visit_with_path(self, ast_path);
let effects = replace(&mut self.effects, old_effects);
Expand Down
82 changes: 40 additions & 42 deletions crates/turbopack-ecmascript/src/analyzer/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ where
LeaveCall(u32),
}

let mut queue: Vec<Step> = Vec::new();
let mut work_queue_stack: Vec<Step> = Vec::new();
let mut done: Vec<JsValue> = Vec::new();
// Tracks the number of nodes in the queue and done combined
let mut total_nodes = 0;
Expand All @@ -65,9 +65,9 @@ where
let mut steps = 0;

total_nodes += val.total_nodes();
queue.push(Step::Enter(val));
work_queue_stack.push(Step::Enter(val));

while let Some(step) = queue.pop() {
while let Some(step) = work_queue_stack.pop() {
steps += 1;

match step {
Expand All @@ -86,9 +86,9 @@ where
total_nodes -= 1;
if let Some(val) = graph.values.get(&var) {
cycle_stack.insert(var.clone());
queue.push(Step::LeaveVar(var));
work_queue_stack.push(Step::LeaveVar(var));
total_nodes += val.total_nodes();
queue.push(Step::Enter(val.clone()));
work_queue_stack.push(Step::Enter(val.clone()));
} else {
total_nodes += 1;
done.push(JsValue::Unknown(
Expand All @@ -100,9 +100,7 @@ where
}
// Leave a variable
Step::LeaveVar(var) => {
let val = done.pop().unwrap();
cycle_stack.remove(&var);
done.push(val);
}
// Enter a function argument
// We want to replace the argument with the value from the function call
Expand Down Expand Up @@ -142,8 +140,8 @@ where
total_nodes -= arg.total_nodes();
}
entry.insert(args);
queue.push(Step::LeaveCall(func_ident));
queue.push(Step::Enter(*return_value));
work_queue_stack.push(Step::LeaveCall(func_ident));
work_queue_stack.push(Step::Enter(*return_value));
} else {
total_nodes -= return_value.total_nodes();
for arg in args.iter() {
Expand Down Expand Up @@ -175,36 +173,35 @@ where
// - take and queue children for processing
// - on leave: insert children again and optimize
Step::Enter(mut val) => {
let i = queue.len();
queue.push(Step::Leave(JsValue::default()));
let i = work_queue_stack.len();
work_queue_stack.push(Step::Leave(JsValue::default()));
let mut has_early_children = false;
val.for_each_early_children_mut(true, &mut |child| {
val.for_each_early_children_mut(&mut |child| {
has_early_children = true;
queue.push(Step::Enter(take(child)));
work_queue_stack.push(Step::Enter(take(child)));
false
});
if has_early_children {
queue[i] = Step::EarlyVisit(val);
work_queue_stack[i] = Step::EarlyVisit(val);
} else {
val.for_each_children_mut(&mut |child| {
queue.push(Step::Enter(take(child)));
work_queue_stack.push(Step::Enter(take(child)));
false
});
queue[i] = Step::Leave(val);
work_queue_stack[i] = Step::Leave(val);
}
}
// Early visit a value
// - reconstruct the value from early children
// - visit the value
// - insert late children and process for Leave
Step::EarlyVisit(mut val) => {
val.for_each_early_children_mut(true, &mut |child| {
val.for_each_early_children_mut(&mut |child| {
let val = done.pop().unwrap();
*child = val;
true
});
#[cfg(debug_assertions)]
val.assert_total_nodes_up_to_date();
val.debug_assert_total_nodes_up_to_date();
total_nodes -= val.total_nodes();
if val.total_nodes() > LIMIT_NODE_SIZE {
total_nodes += 1;
Expand All @@ -213,8 +210,7 @@ where
}

let (mut val, visit_modified) = early_visitor(val).await?;
#[cfg(debug_assertions)]
val.assert_total_nodes_up_to_date();
val.debug_assert_total_nodes_up_to_date();
if visit_modified && val.total_nodes() > LIMIT_NODE_SIZE {
total_nodes += 1;
done.push(JsValue::Unknown(None, "node limit reached"));
Expand All @@ -231,13 +227,19 @@ where
}
total_nodes += count;

let i = queue.len();
queue.push(Step::LeaveLate(JsValue::default()));
val.for_each_early_children_mut(false, &mut |child| {
queue.push(Step::Enter(take(child)));
false
});
queue[i] = Step::LeaveLate(val);
if visit_modified {
// When the early visitor has changed the value, we need to enter it again
work_queue_stack.push(Step::Enter(val));
} else {
// Otherwise we can just process the late children
let i = work_queue_stack.len();
work_queue_stack.push(Step::LeaveLate(JsValue::default()));
val.for_each_late_children_mut(&mut |child| {
work_queue_stack.push(Step::Enter(take(child)));
false
});
work_queue_stack[i] = Step::LeaveLate(val);
}
}
// Leave a value
Step::Leave(mut val) => {
Expand All @@ -246,8 +248,7 @@ where
*child = val;
true
});
#[cfg(debug_assertions)]
val.assert_total_nodes_up_to_date();
val.debug_assert_total_nodes_up_to_date();

total_nodes -= val.total_nodes();

Expand All @@ -258,21 +259,19 @@ where
}
val.normalize_shallow();

#[cfg(debug_assertions)]
val.assert_total_nodes_up_to_date();
val.debug_assert_total_nodes_up_to_date();

total_nodes += val.total_nodes();
queue.push(Step::Visit(val));
work_queue_stack.push(Step::Visit(val));
}
// Leave a value from EarlyVisit
Step::LeaveLate(mut val) => {
val.for_each_early_children_mut(false, &mut |child| {
val.for_each_late_children_mut(&mut |child| {
let val = done.pop().unwrap();
*child = val;
true
});
#[cfg(debug_assertions)]
val.assert_total_nodes_up_to_date();
val.debug_assert_total_nodes_up_to_date();

total_nodes -= val.total_nodes();

Expand All @@ -283,11 +282,10 @@ where
}
val.normalize_shallow();

#[cfg(debug_assertions)]
val.assert_total_nodes_up_to_date();
val.debug_assert_total_nodes_up_to_date();

total_nodes += val.total_nodes();
queue.push(Step::Visit(val));
work_queue_stack.push(Step::Visit(val));
}
// Visit a value with the visitor
// - visited value is put into done
Expand All @@ -298,7 +296,7 @@ where
if visit_modified {
val.normalize_shallow();
#[cfg(debug_assertions)]
val.assert_total_nodes_up_to_date();
val.debug_assert_total_nodes_up_to_date();
if val.total_nodes() > LIMIT_NODE_SIZE {
total_nodes += 1;
done.push(JsValue::Unknown(None, "node limit reached"));
Expand All @@ -316,7 +314,7 @@ where
}
total_nodes += count;
if visit_modified {
queue.push(Step::Enter(val));
work_queue_stack.push(Step::Enter(val));
} else {
done.push(val);
}
Expand All @@ -332,7 +330,7 @@ where

let final_value = done.pop().unwrap();

debug_assert!(queue.is_empty());
debug_assert!(work_queue_stack.is_empty());
debug_assert_eq!(total_nodes, final_value.total_nodes());

Ok(final_value)
Expand Down
Loading