Skip to content

Commit

Permalink
smarter logical combination that keeps truthy/falsy/nullish property
Browse files Browse the repository at this point in the history
  • Loading branch information
sokra committed Jul 30, 2024
1 parent 59dce5d commit 00f9eec
Show file tree
Hide file tree
Showing 11 changed files with 206 additions and 20 deletions.
73 changes: 66 additions & 7 deletions crates/turbopack-ecmascript/src/analyzer/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use std::mem::take;

use swc_core::ecma::atoms::js_word;

use super::{ConstantNumber, ConstantValue, JsValue, LogicalOperator, ObjectPart};
use super::{
AdditionalProperty, ConstantNumber, ConstantValue, JsValue, LogicalOperator, ObjectPart,
};

/// Replaces some builtin values with their resulting values. Called early
/// without lazy nested values. This allows to skip a lot of work to process the
Expand Down Expand Up @@ -501,43 +503,100 @@ pub fn replace_builtin(value: &mut JsValue) -> bool {
// Reduce logical expressions to their final value(s)
JsValue::Logical(_, op, ref mut parts) => {
let len = parts.len();
for (i, part) in take(parts).into_iter().enumerate() {
let input_parts: Vec<JsValue> = take(parts);
*parts = Vec::with_capacity(len);
let mut part_properties = Vec::with_capacity(len);
for (i, part) in input_parts.into_iter().enumerate() {
// The last part is never skipped.
if i == len - 1 {
// We intentionally omit the part_properties for the last part.
// This isn't always needed so we only compute it when actually needed.
parts.push(part);
break;
}
// We might know at compile-time if a part is skipped or the final value.
let skip_part = match op {
let property = match op {
LogicalOperator::And => part.is_truthy(),
LogicalOperator::Or => part.is_falsy(),
LogicalOperator::NullishCoalescing => part.is_nullish(),
};
match skip_part {
// We might know at compile-time if a part is skipped or the final value.
match property {
Some(true) => {
// We known this part is skipped, so we can remove it.
continue;
}
Some(false) => {
// We known this part is the final value, so we can remove the rest.
part_properties.push(property);
parts.push(part);
break;
}
None => {
// We don't know if this part is skipped or the final value, so we keep it.
part_properties.push(property);
parts.push(part);
continue;
}
}
}
part_properties.truncate(parts.len());
// If we reduced the expression to a single value, we can replace it.
if parts.len() == 1 {
*value = parts.pop().unwrap();
true
} else {
// If not, we know that it will be one of the remaining values.
*value = JsValue::alternatives(take(parts));
true
let last_part = parts.last().unwrap();
let property = match op {
LogicalOperator::And => last_part.is_truthy(),
LogicalOperator::Or => last_part.is_falsy(),
LogicalOperator::NullishCoalescing => last_part.is_nullish(),
};
part_properties.push(property);
let (any_unset, all_set) =
part_properties
.iter()
.fold((false, true), |(any_unset, all_set), part| match part {
Some(true) => (any_unset, all_set),
Some(false) => (true, false),
None => (any_unset, false),
});
let property = match op {
LogicalOperator::Or => {
if any_unset {
Some(AdditionalProperty::Truthy)
} else if all_set {
Some(AdditionalProperty::Falsy)
} else {
None
}
}
LogicalOperator::And => {
if any_unset {
Some(AdditionalProperty::Falsy)
} else if all_set {
Some(AdditionalProperty::Truthy)
} else {
None
}
}
LogicalOperator::NullishCoalescing => {
if any_unset {
Some(AdditionalProperty::NonNullish)
} else if all_set {
Some(AdditionalProperty::Nullish)
} else {
None
}
}
};
if let Some(property) = property {
*value = JsValue::alternatives_with_addtional_property(take(parts), property);
true
} else {
*value = JsValue::alternatives(take(parts));
true
}
}
}
JsValue::Tenary(_, test, cons, alt) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,4 +275,84 @@
span: 323..329#1,
in_try: false,
},
FreeVar {
var: FreeVar(
"global",
),
ast_path: [
Program(
Script,
),
Script(
Body(
13,
),
),
Stmt(
Decl,
),
Decl(
Var,
),
VarDecl(
Decls(
0,
),
),
VarDeclarator(
Init,
),
Expr(
Bin,
),
BinExpr(
Left,
),
Expr(
Ident,
),
],
span: 346..352#1,
in_try: false,
},
FreeVar {
var: FreeVar(
"global",
),
ast_path: [
Program(
Script,
),
Script(
Body(
14,
),
),
Stmt(
Decl,
),
Decl(
Var,
),
VarDecl(
Decls(
0,
),
),
VarDeclarator(
Init,
),
Expr(
Bin,
),
BinExpr(
Right,
),
Expr(
Ident,
),
],
span: 387..393#1,
in_try: false,
},
]
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ resolve3 = (FreeVar(global) || true)

resolve4 = (true || FreeVar(global))

resolve5 = (FreeVar(global) && false)

resolve6 = (false && FreeVar(global))

x = true

y = false
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,36 @@
],
),
),
(
"resolve5",
Logical(
3,
And,
[
FreeVar(
"global",
),
Constant(
False,
),
],
),
),
(
"resolve6",
Logical(
3,
And,
[
Constant(
False,
),
FreeVar(
"global",
),
],
),
),
(
"x",
Constant(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ let resolve1 = 1 && 2 && global && 3 && 4;
let resolve2 = 1 && 2 && 0 && global && 4;
let resolve3 = global || true;
let resolve4 = true || global;
let resolve5 = global && false;
let resolve6 = false && global;
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@
0 -> 5 free var = FreeVar(global)

0 -> 6 free var = FreeVar(global)

0 -> 7 free var = FreeVar(global)

0 -> 8 free var = FreeVar(global)
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ chain1 = ???*0*
⚠️ unknown global
⚠️ This value might have side effects

chain2 = (???*0* | 3)
chain2 = (???*0* | 3){truthy}
- *0* FreeVar(global)
⚠️ unknown global
⚠️ This value might have side effects
Expand All @@ -25,13 +25,20 @@ resolve1 = (???*0* | 4)

resolve2 = 0

resolve3 = (???*0* | true)
resolve3 = (???*0* | true){truthy}
- *0* FreeVar(global)
⚠️ unknown global
⚠️ This value might have side effects

resolve4 = true

resolve5 = (???*0* | false){falsy}
- *0* FreeVar(global)
⚠️ unknown global
⚠️ This value might have side effects

resolve6 = false

x = true

y = false
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
0 -> 3 free var = FreeVar(require)

0 -> 4 call = require*0*(
`${(???*1* | "./drivers/node-mongodb-native")}/connection`
`${(???*1* | "./drivers/node-mongodb-native"){truthy}}/connection`
)
- *0* require: The require method from CommonJS
- *1* ???*2*["MONGOOSE_DRIVER_PATH"]
Expand All @@ -16,7 +16,7 @@
0 -> 5 free var = FreeVar(require)

0 -> 6 call = require*0*(
`${(???*1* | "./drivers/node-mongodb-native")}/collection`
`${(???*1* | "./drivers/node-mongodb-native"){truthy}}/collection`
)
- *0* require: The require method from CommonJS
- *1* ???*2*["MONGOOSE_DRIVER_PATH"]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Collection = ???*0*
- *0* require*1*(
`${(???*2* | "./drivers/node-mongodb-native")}/collection`
`${(???*2* | "./drivers/node-mongodb-native"){truthy}}/collection`
)
⚠️ only constant argument is supported
⚠️ This value might have side effects
Expand All @@ -14,7 +14,7 @@ Collection = ???*0*

Connection = ???*0*
- *0* require*1*(
`${(???*2* | "./drivers/node-mongodb-native")}/connection`
`${(???*2* | "./drivers/node-mongodb-native"){truthy}}/connection`
)
⚠️ only constant argument is supported
⚠️ This value might have side effects
Expand All @@ -26,7 +26,7 @@ Connection = ???*0*
⚠️ unknown global
⚠️ This value might have side effects

driver = (???*0* | "./drivers/node-mongodb-native")
driver = (???*0* | "./drivers/node-mongodb-native"){truthy}
- *0* ???*1*["MONGOOSE_DRIVER_PATH"]
⚠️ unknown object
⚠️ This value might have side effects
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8411,7 +8411,7 @@ ${(???*45* | ???*46* | ???*50* | "")}${(???*54* | ???*56*)}`
"abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange resize seeked seeking stalled suspend timeupdate volumechange waiting"["split"](" ")
)

0 -> 1572 call = (...) => undefined((???*0* | "unknown-event"), ???*2*, ???*3*, ???*4*)
0 -> 1572 call = (...) => undefined((???*0* | "unknown-event"){truthy}, ???*2*, ???*3*, ???*4*)
- *0* ???*1*["type"]
⚠️ unknown object
- *1* arguments[0]
Expand Down Expand Up @@ -14864,7 +14864,7 @@ ${(???*45* | ???*46* | ???*50* | "")}${(???*54* | ???*56*)}`
- *3* arguments[3]
⚠️ function calls are not analysed yet

0 -> 2562 call = (...) => a((???*0* | ???*1* | ???*3* | ???*4*), (???*5* | []))
0 -> 2562 call = (...) => a((???*0* | ???*1* | ???*3* | ???*4*), (???*5* | []){truthy})
- *0* arguments[1]
⚠️ function calls are not analysed yet
- *1* ???*2*["mode"]
Expand Down Expand Up @@ -16392,7 +16392,7 @@ ${(???*45* | ???*46* | ???*50* | "")}${(???*54* | ???*56*)}`
- *1* max number of linking steps reached
⚠️ This value might have side effects

2809 -> 2813 call = (...) => a(???*0*, (???*1* | []))
2809 -> 2813 call = (...) => a(???*0*, (???*1* | []){truthy})
- *0* max number of linking steps reached
⚠️ This value might have side effects
- *1* ???*2*["children"]
Expand Down Expand Up @@ -36859,7 +36859,7 @@ ${(???*45* | ???*46* | ???*50* | "")}${(???*54* | ???*56*)}`
"scheduleUpdate": null,
"currentDispatcherRef": module<react, {}>["__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED"]["ReactCurrentDispatcher"],
"findHostInstanceByFiber": (...) => ((null === a) ? null : a["stateNode"]),
"findFiberByHostInstance": ((...) => (b | c | null) | ???*6* | (...) => null),
"findFiberByHostInstance": ((...) => (b | c | null) | ???*6* | (...) => null){truthy},
"findHostInstancesForRefresh": null,
"scheduleRefresh": null,
"scheduleRoot": null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12260,7 +12260,7 @@ d#269 = ???*0*
- *0* max number of linking steps reached
⚠️ This value might have side effects

d#274 = (???*0* | "unknown-event")
d#274 = (???*0* | "unknown-event"){truthy}
- *0* ???*1*["type"]
⚠️ unknown object
- *1* arguments[0]
Expand Down Expand Up @@ -19903,7 +19903,7 @@ vl = {
"scheduleUpdate": null,
"currentDispatcherRef": module<react, {}>["__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED"]["ReactCurrentDispatcher"],
"findHostInstanceByFiber": (...) => ((null === a) ? null : a["stateNode"]),
"findFiberByHostInstance": ((...) => (b | c | null) | ???*5* | (...) => null),
"findFiberByHostInstance": ((...) => (b | c | null) | ???*5* | (...) => null){truthy},
"findHostInstancesForRefresh": null,
"scheduleRefresh": null,
"scheduleRoot": null,
Expand Down

0 comments on commit 00f9eec

Please sign in to comment.