diff --git a/Cargo.toml b/Cargo.toml index e203f8b4abc85..5cdb4c5928228 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -241,6 +241,12 @@ opt-level = 3 [profile.release.package.serde] opt-level = 3 +# Use a custom profile for CI where many tests are performance sensitive but we still want the additional validation of debug-assertions +[profile.release-with-assertions] +inherits = "release" +debug-assertions = true +overflow-checks = true + [workspace.dependencies] # Workspace crates next-api = { path = "crates/next-api" } diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 36a08ad5f3379..c39e3a35bc1e7 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -17,7 +17,7 @@ "rust-check-fmt": "cd ../..; cargo fmt -- --check", "rust-check-clippy": "cargo clippy --workspace --all-targets -- -D warnings -A deprecated", "rust-check-napi": "cargo check -p next-swc-napi", - "test-cargo-unit": "cargo nextest run --workspace --exclude next-swc-napi --exclude turbo-tasks-macros --release --no-fail-fast" + "test-cargo-unit": "cargo nextest run --workspace --exclude next-swc-napi --exclude turbo-tasks-macros --cargo-profile release-with-assertions --no-fail-fast" }, "napi": { "name": "next-swc", diff --git a/turbopack/crates/turbopack-core/src/resolve/pattern.rs b/turbopack/crates/turbopack-core/src/resolve/pattern.rs index 69d660906b9b8..0e19035d43113 100644 --- a/turbopack/crates/turbopack-core/src/resolve/pattern.rs +++ b/turbopack/crates/turbopack-core/src/resolve/pattern.rs @@ -532,17 +532,9 @@ impl Pattern { /// Order into Alternatives -> Concatenation -> Constant/Dynamic /// Merge when possible pub fn normalize(&mut self) { - let mut alternatives = [Vec::new()]; match self { - Pattern::Constant(c) => { - for alt in alternatives.iter_mut() { - alt.push(Pattern::Constant(c.clone())); - } - } - Pattern::Dynamic => { - for alt in alternatives.iter_mut() { - alt.push(Pattern::Dynamic); - } + Pattern::Dynamic | Pattern::Constant(_) => { + // already normalized } Pattern::Alternatives(list) => { for alt in list.iter_mut() { @@ -630,6 +622,7 @@ impl Pattern { }) .collect(), ); + // The recursive call will deduplicate the alternatives after simplifying them self.normalize(); } else { let mut new_parts = Vec::new(); diff --git a/turbopack/crates/turbopack-ecmascript/src/analyzer/mod.rs b/turbopack/crates/turbopack-ecmascript/src/analyzer/mod.rs index 7b65264324cf8..c173741e3b0d1 100644 --- a/turbopack/crates/turbopack-ecmascript/src/analyzer/mod.rs +++ b/turbopack/crates/turbopack-ecmascript/src/analyzer/mod.rs @@ -111,6 +111,13 @@ impl ConstantString { } } + pub fn as_rcstr(&self) -> RcStr { + match self { + Self::Atom(s) => RcStr::from(s.as_str()), + Self::RcStr(s) => s.clone(), + } + } + pub fn as_atom(&self) -> Cow { match self { Self::Atom(s) => Cow::Borrowed(s), diff --git a/turbopack/crates/turbopack-ecmascript/src/utils.rs b/turbopack/crates/turbopack-ecmascript/src/utils.rs index 78f5e711ea4ef..98156e26c29c4 100644 --- a/turbopack/crates/turbopack-ecmascript/src/utils.rs +++ b/turbopack/crates/turbopack-ecmascript/src/utils.rs @@ -6,6 +6,7 @@ use swc_core::{ visit::AstParentKind, }, }; +use turbo_rcstr::{RcStr, rcstr}; use turbo_tasks::{NonLocalValue, trace::TraceRawVcs}; use turbopack_core::{chunk::ModuleId, resolve::pattern::Pattern}; @@ -24,26 +25,42 @@ pub fn unparen(expr: &Expr) -> &Expr { expr } +/// Converts a js-value into a Pattern for matching resources. pub fn js_value_to_pattern(value: &JsValue) -> Pattern { - let mut result = match value { + match value { JsValue::Constant(v) => Pattern::Constant(match v { - ConstantValue::Str(str) => str.as_str().into(), - ConstantValue::True => "true".into(), - ConstantValue::False => "false".into(), - ConstantValue::Null => "null".into(), + ConstantValue::Str(str) => { + // Normalize windows file paths when constructing the pattern. + // See PACK-3279 + if str.as_str().contains("\\") { + RcStr::from(str.to_string().replace('\\', "/")) + } else { + str.as_rcstr() + } + } + ConstantValue::True => rcstr!("true"), + ConstantValue::False => rcstr!("false"), + ConstantValue::Null => rcstr!("null"), ConstantValue::Num(ConstantNumber(n)) => n.to_string().into(), ConstantValue::BigInt(n) => n.to_string().into(), ConstantValue::Regex(box (exp, flags)) => format!("/{exp}/{flags}").into(), - ConstantValue::Undefined => "undefined".into(), + ConstantValue::Undefined => rcstr!("undefined"), }), - JsValue::Url(v, JsValueUrlKind::Relative) => Pattern::Constant(v.as_str().into()), + JsValue::Url(v, JsValueUrlKind::Relative) => Pattern::Constant(v.as_rcstr()), JsValue::Alternatives { total_nodes: _, values, logical_property: _, - } => Pattern::Alternatives(values.iter().map(js_value_to_pattern).collect()), + } => { + let mut alts = Pattern::Alternatives(values.iter().map(js_value_to_pattern).collect()); + alts.normalize(); + alts + } JsValue::Concat(_, parts) => { - Pattern::Concatenation(parts.iter().map(js_value_to_pattern).collect()) + let mut concats = + Pattern::Concatenation(parts.iter().map(js_value_to_pattern).collect()); + concats.normalize(); + concats } JsValue::Add(..) => { // TODO do we need to handle that here @@ -51,9 +68,7 @@ pub fn js_value_to_pattern(value: &JsValue) -> Pattern { Pattern::Dynamic } _ => Pattern::Dynamic, - }; - result.normalize(); - result + } } const JS_MAX_SAFE_INTEGER: u64 = (1u64 << 53) - 1; @@ -200,3 +215,32 @@ pub fn module_value_to_well_known_object(module_value: &ModuleValue) -> Option return None, }) } + +#[cfg(test)] +mod tests { + use turbo_rcstr::rcstr; + use turbopack_core::resolve::pattern::Pattern; + + use crate::{ + analyzer::{ConstantString, ConstantValue, JsValue}, + utils::js_value_to_pattern, + }; + + #[test] + fn test_path_normalization_in_pattern() { + assert_eq!( + Pattern::Constant(rcstr!("hello/world")), + js_value_to_pattern(&JsValue::Constant(ConstantValue::Str( + ConstantString::RcStr(rcstr!("hello\\world")) + ))) + ); + + assert_eq!( + Pattern::Constant(rcstr!("hello/world")), + js_value_to_pattern(&JsValue::Concat( + 1, + vec!["hello".into(), "\\".into(), "world".into()] + )) + ); + } +} diff --git a/turbopack/crates/turbopack-tests/tests/snapshot.rs b/turbopack/crates/turbopack-tests/tests/snapshot.rs index f3c631c05ffe4..daecdfc83acfd 100644 --- a/turbopack/crates/turbopack-tests/tests/snapshot.rs +++ b/turbopack/crates/turbopack-tests/tests/snapshot.rs @@ -12,8 +12,7 @@ use serde::Deserialize; use serde_json::json; use turbo_rcstr::{RcStr, rcstr}; use turbo_tasks::{ - ReadConsistency, ReadRef, ResolvedVc, TryJoinIterExt, TurboTasks, ValueToString, Vc, - apply_effects, + ReadConsistency, ReadRef, ResolvedVc, TurboTasks, ValueToString, Vc, apply_effects, }; use turbo_tasks_backend::{BackendOptions, TurboTasksBackend, noop_backing_storage}; use turbo_tasks_env::DotenvProcessEnv; @@ -493,11 +492,7 @@ async fn walk_asset( .await? .iter() .copied() - .map(|asset| async move { Ok(ResolvedVc::try_downcast::>(asset)) }) - .try_join() - .await? - .into_iter() - .flatten(), + .flat_map(ResolvedVc::try_downcast::>), ); Ok(())