mirror of
https://github.com/hanzoai/react.git
synced 2026-09-24 17:02:27 +00:00
[rust-compiler] Use rustc-hash FxHasher for all maps and sets (#36811)
Swaps the default hashers across the Rust compiler crates for rustc-hash's faster `FxHasher`. ## Why `FxHasher` is a simple, fast, non-cryptographic hasher. std's default (SipHash) is DoS-resistant but heavy — the compiler keys maps/sets almost entirely on small integer IDs (`IdentifierId`, `BlockId`, `ScopeId`, …) where that protection buys nothing. Switching gives: - **Performance** — faster hashing on the hot ID-keyed maps/sets used throughout the passes. - **Slight binary size reduction** — drops the heavy SipHash hasher pulled in by std's `HashMap`/`HashSet`. ## Changes - `std::collections::HashMap`/`HashSet` → `rustc_hash::FxHashMap`/`FxHashSet` - `indexmap` `IndexMap`/`IndexSet` now use `FxBuildHasher`, inlined as `IndexMap<K, V, FxBuildHasher>` (no `FxIndexMap` type aliases) - `rustc-hash = "2"` added to all 12 crate manifests - `rustc_hash`/`indexmap` imports consolidated into single brace imports at the top of each file The change is serde-neutral: `FxHashMap` and `IndexMap<_, _, FxBuildHasher>` serialize to byte-identical JSON, and `IndexMap` keeps insertion order. `cargo check`, `cargo fmt --check`, and `cargo test` all pass with no warnings.
This commit is contained in:
Generated
+12
@@ -287,6 +287,7 @@ dependencies = [
|
||||
"react_compiler_ssa",
|
||||
"react_compiler_typeinference",
|
||||
"react_compiler_validation",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
@@ -297,6 +298,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"react_compiler_diagnostics",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde-transcode",
|
||||
"serde_json",
|
||||
@@ -308,6 +310,7 @@ dependencies = [
|
||||
name = "react_compiler_diagnostics"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@@ -317,6 +320,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"react_compiler_diagnostics",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
@@ -332,6 +336,7 @@ dependencies = [
|
||||
"react_compiler_optimization",
|
||||
"react_compiler_ssa",
|
||||
"react_compiler_utils",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -342,6 +347,7 @@ dependencies = [
|
||||
"react_compiler_ast",
|
||||
"react_compiler_diagnostics",
|
||||
"react_compiler_hir",
|
||||
"rustc-hash",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
@@ -367,6 +373,7 @@ dependencies = [
|
||||
"react_compiler_hir",
|
||||
"react_compiler_lowering",
|
||||
"react_compiler_ssa",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -378,6 +385,7 @@ dependencies = [
|
||||
"react_compiler_ast",
|
||||
"react_compiler_diagnostics",
|
||||
"react_compiler_hir",
|
||||
"rustc-hash",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
@@ -388,6 +396,7 @@ dependencies = [
|
||||
"indexmap",
|
||||
"react_compiler_diagnostics",
|
||||
"react_compiler_hir",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -397,6 +406,7 @@ dependencies = [
|
||||
"react_compiler_diagnostics",
|
||||
"react_compiler_hir",
|
||||
"react_compiler_ssa",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -404,6 +414,7 @@ name = "react_compiler_utils"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -413,6 +424,7 @@ dependencies = [
|
||||
"indexmap",
|
||||
"react_compiler_diagnostics",
|
||||
"react_compiler_hir",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -15,5 +15,6 @@ react_compiler_ssa = { path = "../react_compiler_ssa" }
|
||||
react_compiler_typeinference = { path = "../react_compiler_typeinference" }
|
||||
react_compiler_validation = { path = "../react_compiler_validation" }
|
||||
indexmap = "2"
|
||||
rustc-hash = "2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1", features = ["raw_value"] }
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_ast::common::BaseNode;
|
||||
use react_compiler_ast::declarations::{
|
||||
@@ -72,9 +72,9 @@ pub struct ProgramContext {
|
||||
pub debug_enabled: bool,
|
||||
|
||||
// Internal state
|
||||
already_compiled: HashSet<u32>,
|
||||
known_referenced_names: HashSet<String>,
|
||||
imports: HashMap<String, HashMap<String, NonLocalImportSpecifier>>,
|
||||
already_compiled: FxHashSet<u32>,
|
||||
known_referenced_names: FxHashSet<String>,
|
||||
imports: FxHashMap<String, FxHashMap<String, NonLocalImportSpecifier>>,
|
||||
}
|
||||
|
||||
impl ProgramContext {
|
||||
@@ -104,9 +104,9 @@ impl ProgramContext {
|
||||
renames: Vec::new(),
|
||||
timing: TimingData::new(profiling),
|
||||
debug_enabled,
|
||||
already_compiled: HashSet::new(),
|
||||
known_referenced_names: HashSet::new(),
|
||||
imports: HashMap::new(),
|
||||
already_compiled: FxHashSet::default(),
|
||||
known_referenced_names: FxHashSet::default(),
|
||||
imports: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,13 +230,13 @@ impl ProgramContext {
|
||||
}
|
||||
|
||||
/// Get the set of known referenced names for seeding per-function Environment UID generation.
|
||||
pub fn known_referenced_names(&self) -> &HashSet<String> {
|
||||
pub fn known_referenced_names(&self) -> &FxHashSet<String> {
|
||||
&self.known_referenced_names
|
||||
}
|
||||
|
||||
/// Merge UID names generated during a function compilation back into the program context,
|
||||
/// so subsequent function compilations avoid collisions.
|
||||
pub fn merge_uid_known_names(&mut self, names: &HashSet<String>) {
|
||||
pub fn merge_uid_known_names(&mut self, names: &FxHashSet<String>) {
|
||||
self.known_referenced_names.extend(names.iter().cloned());
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ impl ProgramContext {
|
||||
}
|
||||
|
||||
/// Get an immutable view of the generated imports.
|
||||
pub fn imports(&self) -> &HashMap<String, HashMap<String, NonLocalImportSpecifier>> {
|
||||
pub fn imports(&self) -> &FxHashMap<String, FxHashMap<String, NonLocalImportSpecifier>> {
|
||||
&self.imports
|
||||
}
|
||||
}
|
||||
@@ -274,7 +274,7 @@ pub fn validate_restricted_imports(
|
||||
Some(b) if !b.is_empty() => b,
|
||||
_ => return None,
|
||||
};
|
||||
let restricted: HashSet<&str> = blocklisted.iter().map(|s| s.as_str()).collect();
|
||||
let restricted: FxHashSet<&str> = blocklisted.iter().map(|s| s.as_str()).collect();
|
||||
let mut error = CompilerError::new();
|
||||
|
||||
for stmt in &program.body {
|
||||
@@ -326,7 +326,7 @@ pub fn add_imports_to_program(program: &mut Program, context: &ProgramContext) {
|
||||
}
|
||||
|
||||
// Collect existing non-namespaced imports by module name
|
||||
let existing_import_indices: HashMap<String, usize> = program
|
||||
let existing_import_indices: FxHashMap<String, usize> = program
|
||||
.body
|
||||
.iter()
|
||||
.enumerate()
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
//! Analogous to TS `Pipeline.ts` (`compileFn` → `run` → `runWithEnvironment`).
|
||||
//! Currently runs BuildHIR (lowering) and PruneMaybeThrows.
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use react_compiler_ast::scope::ScopeInfo;
|
||||
use react_compiler_diagnostics::CompilerError;
|
||||
use react_compiler_hir::ReactFunctionType;
|
||||
@@ -15,6 +16,7 @@ use react_compiler_hir::environment::Environment;
|
||||
use react_compiler_hir::environment::OutputMode;
|
||||
use react_compiler_hir::environment_config::EnvironmentConfig;
|
||||
use react_compiler_lowering::FunctionNode;
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap};
|
||||
|
||||
use super::compile_result::CodegenFunction;
|
||||
use super::compile_result::CompilerErrorDetailInfo;
|
||||
@@ -1229,25 +1231,23 @@ pub fn compile_outlined_fn(
|
||||
fn build_outlined_scope_info(
|
||||
func: &mut react_compiler_ast::statements::FunctionDeclaration,
|
||||
) -> react_compiler_ast::scope::ScopeInfo {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use react_compiler_ast::scope::*;
|
||||
|
||||
let mut pos: u32 = 1; // reserve 0 for the function itself
|
||||
func.base.start = Some(0);
|
||||
|
||||
let mut fn_bindings: HashMap<String, BindingId> = HashMap::new();
|
||||
let mut fn_bindings: FxHashMap<String, BindingId> = FxHashMap::default();
|
||||
let mut bindings_list: Vec<BindingData> = Vec::new();
|
||||
let mut ref_to_binding: indexmap::IndexMap<u32, BindingId> = indexmap::IndexMap::new();
|
||||
let mut ref_to_binding: IndexMap<u32, BindingId, FxBuildHasher> = IndexMap::default();
|
||||
|
||||
// Helper to add a binding
|
||||
let _add_binding =
|
||||
|name: &str,
|
||||
kind: BindingKind,
|
||||
p: u32,
|
||||
fn_bindings: &mut HashMap<String, BindingId>,
|
||||
fn_bindings: &mut FxHashMap<String, BindingId>,
|
||||
bindings_list: &mut Vec<BindingData>,
|
||||
ref_to_binding: &mut indexmap::IndexMap<u32, BindingId>| {
|
||||
ref_to_binding: &mut IndexMap<u32, BindingId, FxBuildHasher>| {
|
||||
if fn_bindings.contains_key(name) {
|
||||
// Already exists, just add reference
|
||||
let bid = fn_bindings[name];
|
||||
@@ -1296,7 +1296,7 @@ fn build_outlined_scope_info(
|
||||
id: ScopeId(0),
|
||||
parent: None,
|
||||
kind: ScopeKind::Program,
|
||||
bindings: HashMap::new(),
|
||||
bindings: FxHashMap::default(),
|
||||
};
|
||||
let fn_scope = ScopeData {
|
||||
id: ScopeId(1),
|
||||
@@ -1305,21 +1305,21 @@ fn build_outlined_scope_info(
|
||||
bindings: fn_bindings,
|
||||
};
|
||||
|
||||
let mut node_to_scope: HashMap<u32, ScopeId> = HashMap::new();
|
||||
let mut node_to_scope: FxHashMap<u32, ScopeId> = FxHashMap::default();
|
||||
node_to_scope.insert(0, ScopeId(1));
|
||||
|
||||
// Mirror position maps into node-ID maps for outlined functions
|
||||
let mut node_id_to_scope: HashMap<u32, ScopeId> = HashMap::new();
|
||||
let mut node_id_to_scope: FxHashMap<u32, ScopeId> = FxHashMap::default();
|
||||
node_id_to_scope.insert(0, ScopeId(1));
|
||||
let ref_node_id_to_binding: indexmap::IndexMap<u32, BindingId> =
|
||||
let ref_node_id_to_binding: IndexMap<u32, BindingId, FxBuildHasher> =
|
||||
ref_to_binding.iter().map(|(&k, &v)| (k, v)).collect();
|
||||
|
||||
ScopeInfo {
|
||||
scopes: vec![program_scope, fn_scope],
|
||||
bindings: bindings_list,
|
||||
node_to_scope,
|
||||
node_to_scope_end: HashMap::new(),
|
||||
reference_to_binding: indexmap::IndexMap::new(),
|
||||
node_to_scope_end: FxHashMap::default(),
|
||||
reference_to_binding: IndexMap::default(),
|
||||
ref_node_id_to_binding,
|
||||
node_id_to_scope,
|
||||
program_scope: ScopeId(0),
|
||||
@@ -1331,9 +1331,9 @@ fn outlined_assign_pattern_positions(
|
||||
pattern: &mut react_compiler_ast::patterns::PatternLike,
|
||||
pos: &mut u32,
|
||||
kind: react_compiler_ast::scope::BindingKind,
|
||||
fn_bindings: &mut std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
|
||||
fn_bindings: &mut rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,
|
||||
bindings_list: &mut Vec<react_compiler_ast::scope::BindingData>,
|
||||
ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
|
||||
ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,
|
||||
) {
|
||||
use react_compiler_ast::patterns::PatternLike;
|
||||
use react_compiler_ast::scope::*;
|
||||
@@ -1432,9 +1432,9 @@ fn outlined_assign_pattern_positions(
|
||||
fn outlined_assign_stmt_positions(
|
||||
stmt: &mut react_compiler_ast::statements::Statement,
|
||||
pos: &mut u32,
|
||||
fn_bindings: &mut std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
|
||||
fn_bindings: &mut rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,
|
||||
bindings_list: &mut Vec<react_compiler_ast::scope::BindingData>,
|
||||
ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
|
||||
ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,
|
||||
) {
|
||||
use react_compiler_ast::statements::Statement;
|
||||
|
||||
@@ -1477,8 +1477,8 @@ fn outlined_assign_stmt_positions(
|
||||
fn outlined_assign_expr_positions(
|
||||
expr: &mut react_compiler_ast::expressions::Expression,
|
||||
pos: &mut u32,
|
||||
fn_bindings: &std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
|
||||
ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
|
||||
fn_bindings: &rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,
|
||||
ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,
|
||||
) {
|
||||
use react_compiler_ast::expressions::*;
|
||||
|
||||
@@ -1538,8 +1538,8 @@ fn outlined_assign_expr_positions(
|
||||
fn outlined_assign_jsx_name_positions(
|
||||
name: &mut react_compiler_ast::jsx::JSXElementName,
|
||||
pos: &mut u32,
|
||||
fn_bindings: &std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
|
||||
ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
|
||||
fn_bindings: &rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,
|
||||
ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,
|
||||
) {
|
||||
match name {
|
||||
react_compiler_ast::jsx::JSXElementName::JSXIdentifier(id) => {
|
||||
@@ -1561,8 +1561,8 @@ fn outlined_assign_jsx_name_positions(
|
||||
fn outlined_assign_jsx_member_positions(
|
||||
member: &mut react_compiler_ast::jsx::JSXMemberExpression,
|
||||
pos: &mut u32,
|
||||
fn_bindings: &std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
|
||||
ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
|
||||
fn_bindings: &rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,
|
||||
ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,
|
||||
) {
|
||||
match &mut *member.object {
|
||||
react_compiler_ast::jsx::JSXMemberExprObject::JSXIdentifier(id) => {
|
||||
@@ -1583,8 +1583,8 @@ fn outlined_assign_jsx_member_positions(
|
||||
fn outlined_assign_jsx_val_positions(
|
||||
val: &mut react_compiler_ast::jsx::JSXAttributeValue,
|
||||
pos: &mut u32,
|
||||
fn_bindings: &std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
|
||||
ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
|
||||
fn_bindings: &rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,
|
||||
ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,
|
||||
) {
|
||||
match val {
|
||||
react_compiler_ast::jsx::JSXAttributeValue::JSXExpressionContainer(c) => {
|
||||
@@ -1608,8 +1608,8 @@ fn outlined_assign_jsx_val_positions(
|
||||
fn outlined_assign_jsx_child_positions(
|
||||
child: &mut react_compiler_ast::jsx::JSXChild,
|
||||
pos: &mut u32,
|
||||
fn_bindings: &std::collections::HashMap<String, react_compiler_ast::scope::BindingId>,
|
||||
ref_to_binding: &mut indexmap::IndexMap<u32, react_compiler_ast::scope::BindingId>,
|
||||
fn_bindings: &rustc_hash::FxHashMap<String, react_compiler_ast::scope::BindingId>,
|
||||
ref_to_binding: &mut IndexMap<u32, react_compiler_ast::scope::BindingId, FxBuildHasher>,
|
||||
) {
|
||||
match child {
|
||||
react_compiler_ast::jsx::JSXChild::JSXExpressionContainer(c) => {
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
//! 5. Processing each function through the compilation pipeline
|
||||
//! 6. Applying compiled functions back to the AST
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_ast::File;
|
||||
use react_compiler_ast::Program;
|
||||
@@ -2084,9 +2083,9 @@ struct CompiledFnForReplacement {
|
||||
fn get_functions_referenced_before_declaration(
|
||||
program: &Program,
|
||||
compiled_fns: &[CompiledFnForReplacement],
|
||||
) -> HashSet<u32> {
|
||||
) -> FxHashSet<u32> {
|
||||
// Collect function names and their node_ids for compiled FunctionDeclarations
|
||||
let mut fn_names: HashMap<String, u32> = HashMap::new();
|
||||
let mut fn_names: FxHashMap<String, u32> = FxHashMap::default();
|
||||
for compiled in compiled_fns {
|
||||
if compiled.original_kind == OriginalFnKind::FunctionDeclaration {
|
||||
if let Some(ref name) = compiled.fn_name {
|
||||
@@ -2098,10 +2097,10 @@ fn get_functions_referenced_before_declaration(
|
||||
}
|
||||
|
||||
if fn_names.is_empty() {
|
||||
return HashSet::new();
|
||||
return FxHashSet::default();
|
||||
}
|
||||
|
||||
let mut referenced_before_decl: HashSet<u32> = HashSet::new();
|
||||
let mut referenced_before_decl: FxHashSet<u32> = FxHashSet::default();
|
||||
|
||||
// Walk through program body in order. For each statement, check if it references
|
||||
// any of the function names before the function's declaration.
|
||||
@@ -2597,7 +2596,7 @@ fn apply_compiled_functions(
|
||||
let referenced_before_decl = if has_gating {
|
||||
get_functions_referenced_before_declaration(program, compiled_fns)
|
||||
} else {
|
||||
HashSet::new()
|
||||
FxHashSet::default()
|
||||
};
|
||||
|
||||
// For gated functions, we need to clone the original function expressions
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
//!
|
||||
//! Analogous to TS `ValidateSourceLocations.ts`.
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_ast::common::SourceLocation as AstSourceLocation;
|
||||
use react_compiler_ast::expressions::{
|
||||
@@ -38,14 +38,14 @@ pub fn validate_source_locations(
|
||||
let important_original = collect_important_original_locations(func);
|
||||
|
||||
// Step 2: Collect all locations from the generated AST
|
||||
let mut generated = HashMap::<String, HashSet<String>>::new();
|
||||
let mut generated = FxHashMap::<String, FxHashSet<String>>::default();
|
||||
collect_generated_from_block(&codegen.body.body, &mut generated);
|
||||
for outlined in &codegen.outlined {
|
||||
collect_generated_from_block(&outlined.func.body.body, &mut generated);
|
||||
}
|
||||
|
||||
// Step 3: Validate that all important locations are preserved
|
||||
let strict_node_types: HashSet<&str> =
|
||||
let strict_node_types: FxHashSet<&str> =
|
||||
["VariableDeclaration", "VariableDeclarator", "Identifier"]
|
||||
.into_iter()
|
||||
.collect();
|
||||
@@ -101,7 +101,7 @@ pub fn validate_source_locations(
|
||||
struct ImportantLocation {
|
||||
key: String,
|
||||
loc: AstSourceLocation,
|
||||
node_types: HashSet<&'static str>,
|
||||
node_types: FxHashSet<&'static str>,
|
||||
}
|
||||
|
||||
// ---- Location key ----
|
||||
@@ -157,7 +157,7 @@ fn report_wrong_node_type(
|
||||
env: &mut Environment,
|
||||
loc: &AstSourceLocation,
|
||||
expected_type: &str,
|
||||
actual_types: &HashSet<String>,
|
||||
actual_types: &FxHashSet<String>,
|
||||
) {
|
||||
let diag_loc = ast_to_diag_loc(loc);
|
||||
let mut actual: Vec<&str> = actual_types.iter().map(|s| s.as_str()).collect();
|
||||
@@ -249,8 +249,8 @@ fn is_manual_memoization(expr: &Expression) -> bool {
|
||||
|
||||
fn collect_important_original_locations(
|
||||
func: &FunctionNode<'_>,
|
||||
) -> HashMap<String, ImportantLocation> {
|
||||
let mut locations = HashMap::new();
|
||||
) -> FxHashMap<String, ImportantLocation> {
|
||||
let mut locations = FxHashMap::default();
|
||||
|
||||
// Note: TS uses func.traverse() which visits DESCENDANTS only, not the root
|
||||
// function node itself. So we don't record the root function as important.
|
||||
@@ -294,14 +294,14 @@ fn collect_important_original_locations(
|
||||
fn record_important(
|
||||
node_type: &'static str,
|
||||
loc: &Option<AstSourceLocation>,
|
||||
locations: &mut HashMap<String, ImportantLocation>,
|
||||
locations: &mut FxHashMap<String, ImportantLocation>,
|
||||
) {
|
||||
if let Some(loc) = loc {
|
||||
let key = location_key(loc);
|
||||
if let Some(existing) = locations.get_mut(&key) {
|
||||
existing.node_types.insert(node_type);
|
||||
} else {
|
||||
let mut node_types = HashSet::new();
|
||||
let mut node_types = FxHashSet::default();
|
||||
node_types.insert(node_type);
|
||||
locations.insert(
|
||||
key.clone(),
|
||||
@@ -318,7 +318,7 @@ fn record_important(
|
||||
fn collect_original_block(
|
||||
stmts: &[Statement],
|
||||
in_single_return_arrow: bool,
|
||||
locations: &mut HashMap<String, ImportantLocation>,
|
||||
locations: &mut FxHashMap<String, ImportantLocation>,
|
||||
) {
|
||||
for stmt in stmts {
|
||||
collect_original_statement(stmt, in_single_return_arrow, locations);
|
||||
@@ -328,7 +328,7 @@ fn collect_original_block(
|
||||
fn collect_original_statement(
|
||||
stmt: &Statement,
|
||||
in_single_return_arrow: bool,
|
||||
locations: &mut HashMap<String, ImportantLocation>,
|
||||
locations: &mut FxHashMap<String, ImportantLocation>,
|
||||
) {
|
||||
// Record this statement if it's an important type
|
||||
if let Some(type_name) = important_statement_type(stmt) {
|
||||
@@ -476,7 +476,7 @@ fn collect_original_statement(
|
||||
|
||||
fn collect_original_var_declaration(
|
||||
decl: &VariableDeclaration,
|
||||
locations: &mut HashMap<String, ImportantLocation>,
|
||||
locations: &mut FxHashMap<String, ImportantLocation>,
|
||||
) {
|
||||
for declarator in &decl.declarations {
|
||||
// VariableDeclarator is an important type
|
||||
@@ -490,7 +490,7 @@ fn collect_original_var_declaration(
|
||||
|
||||
fn collect_original_expression(
|
||||
expr: &Expression,
|
||||
locations: &mut HashMap<String, ImportantLocation>,
|
||||
locations: &mut FxHashMap<String, ImportantLocation>,
|
||||
) {
|
||||
// Record this expression if it's an important type
|
||||
if let Some(type_name) = important_expression_type(expr) {
|
||||
@@ -667,7 +667,7 @@ fn collect_original_expression(
|
||||
|
||||
fn collect_original_arrow_children(
|
||||
arrow: &ArrowFunctionExpression,
|
||||
locations: &mut HashMap<String, ImportantLocation>,
|
||||
locations: &mut FxHashMap<String, ImportantLocation>,
|
||||
) {
|
||||
for param in &arrow.params {
|
||||
collect_original_pattern(param, locations);
|
||||
@@ -685,7 +685,7 @@ fn collect_original_arrow_children(
|
||||
|
||||
fn collect_original_fn_expr_children(
|
||||
func: &FunctionExpression,
|
||||
locations: &mut HashMap<String, ImportantLocation>,
|
||||
locations: &mut FxHashMap<String, ImportantLocation>,
|
||||
) {
|
||||
if let Some(id) = &func.id {
|
||||
record_important("Identifier", &id.base.loc, locations);
|
||||
@@ -698,7 +698,7 @@ fn collect_original_fn_expr_children(
|
||||
|
||||
fn collect_original_pattern(
|
||||
pattern: &PatternLike,
|
||||
locations: &mut HashMap<String, ImportantLocation>,
|
||||
locations: &mut FxHashMap<String, ImportantLocation>,
|
||||
) {
|
||||
match pattern {
|
||||
PatternLike::Identifier(id) => {
|
||||
@@ -852,7 +852,7 @@ fn expression_loc(expr: &Expression) -> &Option<AstSourceLocation> {
|
||||
|
||||
fn collect_generated_from_block(
|
||||
stmts: &[Statement],
|
||||
locations: &mut HashMap<String, HashSet<String>>,
|
||||
locations: &mut FxHashMap<String, FxHashSet<String>>,
|
||||
) {
|
||||
for stmt in stmts {
|
||||
collect_generated_statement(stmt, locations);
|
||||
@@ -862,7 +862,7 @@ fn collect_generated_from_block(
|
||||
fn record_generated(
|
||||
type_name: &str,
|
||||
loc: &Option<AstSourceLocation>,
|
||||
locations: &mut HashMap<String, HashSet<String>>,
|
||||
locations: &mut FxHashMap<String, FxHashSet<String>>,
|
||||
) {
|
||||
if let Some(loc) = loc {
|
||||
let key = location_key(loc);
|
||||
@@ -873,7 +873,10 @@ fn record_generated(
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_generated_statement(stmt: &Statement, locations: &mut HashMap<String, HashSet<String>>) {
|
||||
fn collect_generated_statement(
|
||||
stmt: &Statement,
|
||||
locations: &mut FxHashMap<String, FxHashSet<String>>,
|
||||
) {
|
||||
// Record this statement's location
|
||||
let type_name = statement_type_name(stmt);
|
||||
record_generated(type_name, statement_loc(stmt), locations);
|
||||
@@ -1008,7 +1011,7 @@ fn collect_generated_statement(stmt: &Statement, locations: &mut HashMap<String,
|
||||
|
||||
fn collect_generated_var_declaration(
|
||||
decl: &VariableDeclaration,
|
||||
locations: &mut HashMap<String, HashSet<String>>,
|
||||
locations: &mut FxHashMap<String, FxHashSet<String>>,
|
||||
) {
|
||||
for declarator in &decl.declarations {
|
||||
record_generated("VariableDeclarator", &declarator.base.loc, locations);
|
||||
@@ -1021,7 +1024,7 @@ fn collect_generated_var_declaration(
|
||||
|
||||
fn collect_generated_expression(
|
||||
expr: &Expression,
|
||||
locations: &mut HashMap<String, HashSet<String>>,
|
||||
locations: &mut FxHashMap<String, FxHashSet<String>>,
|
||||
) {
|
||||
let type_name = expression_type_name(expr);
|
||||
record_generated(type_name, expression_loc(expr), locations);
|
||||
@@ -1188,7 +1191,7 @@ fn collect_generated_expression(
|
||||
|
||||
fn collect_generated_pattern(
|
||||
pattern: &PatternLike,
|
||||
locations: &mut HashMap<String, HashSet<String>>,
|
||||
locations: &mut FxHashMap<String, FxHashSet<String>>,
|
||||
) {
|
||||
match pattern {
|
||||
PatternLike::Identifier(id) => {
|
||||
|
||||
@@ -9,6 +9,7 @@ serde = { version = "1", features = ["derive"] }
|
||||
serde_json = { version = "1", features = ["raw_value", "unbounded_depth"] }
|
||||
serde-transcode = "1"
|
||||
indexmap = { version = "2", features = ["serde"] }
|
||||
rustc-hash = "2"
|
||||
|
||||
[dev-dependencies]
|
||||
walkdir = "2"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use serde::Deserialize;
|
||||
@@ -20,7 +20,7 @@ pub struct ScopeData {
|
||||
pub kind: ScopeKind,
|
||||
/// Bindings declared directly in this scope, keyed by name.
|
||||
/// Maps to BindingId for lookup in the binding table.
|
||||
pub bindings: HashMap<String, BindingId>,
|
||||
pub bindings: FxHashMap<String, BindingId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@@ -113,18 +113,18 @@ pub struct ScopeInfo {
|
||||
/// **NOT for identity lookups** — use `node_id_to_scope` (via `resolve_scope_for_node`)
|
||||
/// instead. Retained only for position-range containment queries
|
||||
/// (e.g., "is reference R inside function scope S?").
|
||||
pub node_to_scope: HashMap<u32, ScopeId>,
|
||||
pub node_to_scope: FxHashMap<u32, ScopeId>,
|
||||
|
||||
/// Maps an AST node's start offset to the node's end offset.
|
||||
/// Parallel to `node_to_scope` — used for position-range containment checks.
|
||||
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
|
||||
pub node_to_scope_end: HashMap<u32, u32>,
|
||||
#[serde(default, skip_serializing_if = "FxHashMap::is_empty")]
|
||||
pub node_to_scope_end: FxHashMap<u32, u32>,
|
||||
|
||||
/// **DEPRECATED** — retained only for Babel bridge JSON deserialization.
|
||||
/// All backends pass empty maps; only the Babel bridge populates this.
|
||||
/// Use `ref_node_id_to_binding` for all lookups and iteration.
|
||||
#[serde(default)]
|
||||
pub reference_to_binding: IndexMap<u32, BindingId>,
|
||||
pub reference_to_binding: IndexMap<u32, BindingId, FxBuildHasher>,
|
||||
|
||||
/// Maps an identifier reference's node-ID to the binding it resolves to.
|
||||
/// Only present for identifiers that resolve to a binding (not globals).
|
||||
@@ -134,15 +134,15 @@ pub struct ScopeInfo {
|
||||
skip_serializing_if = "IndexMap::is_empty",
|
||||
rename = "refNodeIdToBinding"
|
||||
)]
|
||||
pub ref_node_id_to_binding: IndexMap<u32, BindingId>,
|
||||
pub ref_node_id_to_binding: IndexMap<u32, BindingId, FxBuildHasher>,
|
||||
|
||||
/// Maps a scope-creating AST node's node-ID to the scope it creates.
|
||||
#[serde(
|
||||
default,
|
||||
skip_serializing_if = "HashMap::is_empty",
|
||||
skip_serializing_if = "FxHashMap::is_empty",
|
||||
rename = "nodeIdToScope"
|
||||
)]
|
||||
pub node_id_to_scope: HashMap<u32, ScopeId>,
|
||||
pub node_id_to_scope: FxHashMap<u32, ScopeId>,
|
||||
|
||||
/// The program-level (module) scope. Always scopes[0].
|
||||
pub program_scope: ScopeId,
|
||||
@@ -207,7 +207,7 @@ impl ScopeInfo {
|
||||
name: &str,
|
||||
ancestor: ScopeId,
|
||||
) -> Option<&BindingData> {
|
||||
let mut descendants = std::collections::HashSet::new();
|
||||
let mut descendants = rustc_hash::FxHashSet::default();
|
||||
descendants.insert(ancestor);
|
||||
let mut changed = true;
|
||||
while changed {
|
||||
@@ -238,7 +238,7 @@ impl ScopeInfo {
|
||||
name: &str,
|
||||
ancestor: ScopeId,
|
||||
) -> Option<(BindingId, &BindingData)> {
|
||||
let mut descendants = std::collections::HashSet::new();
|
||||
let mut descendants = rustc_hash::FxHashSet::default();
|
||||
descendants.insert(ancestor);
|
||||
let mut changed = true;
|
||||
while changed {
|
||||
@@ -306,7 +306,7 @@ impl ScopeInfo {
|
||||
ancestor: ScopeId,
|
||||
is_claimed: impl Fn(ScopeId) -> bool,
|
||||
) -> Option<ScopeId> {
|
||||
let mut descendants = std::collections::HashSet::new();
|
||||
let mut descendants = rustc_hash::FxHashSet::default();
|
||||
descendants.insert(ancestor);
|
||||
let mut changed = true;
|
||||
while changed {
|
||||
|
||||
@@ -4,4 +4,5 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
rustc-hash = "2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
|
||||
@@ -158,8 +158,8 @@ pub fn code_frame_columns(
|
||||
let number_max_width = format!("{}", end).len();
|
||||
|
||||
// Build a lookup map for marker lines
|
||||
let mut marker_map: std::collections::HashMap<usize, MarkerEntry> =
|
||||
std::collections::HashMap::new();
|
||||
let mut marker_map: rustc_hash::FxHashMap<usize, MarkerEntry> =
|
||||
rustc_hash::FxHashMap::default();
|
||||
let line_diff = end_line as usize - start_line as usize;
|
||||
for (line_number, entry) in marker_lines_raw {
|
||||
// Resolve placeholder lengths using actual source lines
|
||||
|
||||
@@ -6,5 +6,6 @@ edition = "2024"
|
||||
[dependencies]
|
||||
react_compiler_diagnostics = { path = "../react_compiler_diagnostics" }
|
||||
indexmap = { version = "2", features = ["serde"] }
|
||||
rustc-hash = "2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
|
||||
@@ -20,11 +20,11 @@ use crate::type_config::{
|
||||
pub fn default_module_type_provider(module_name: &str) -> Option<TypeConfig> {
|
||||
match module_name {
|
||||
"react-hook-form" => Some(TypeConfig::Object(ObjectTypeConfig {
|
||||
properties: Some(IndexMap::from([(
|
||||
properties: Some(IndexMap::from_iter([(
|
||||
"useForm".to_string(),
|
||||
TypeConfig::Hook(HookTypeConfig {
|
||||
return_type: Box::new(TypeConfig::Object(ObjectTypeConfig {
|
||||
properties: Some(IndexMap::from([(
|
||||
properties: Some(IndexMap::from_iter([(
|
||||
"watch".to_string(),
|
||||
TypeConfig::Function(FunctionTypeConfig {
|
||||
positional_params: Vec::new(),
|
||||
@@ -58,7 +58,7 @@ pub fn default_module_type_provider(module_name: &str) -> Option<TypeConfig> {
|
||||
})),
|
||||
|
||||
"@tanstack/react-table" => Some(TypeConfig::Object(ObjectTypeConfig {
|
||||
properties: Some(IndexMap::from([(
|
||||
properties: Some(IndexMap::from_iter([(
|
||||
"useReactTable".to_string(),
|
||||
TypeConfig::Hook(HookTypeConfig {
|
||||
positional_params: Some(Vec::new()),
|
||||
@@ -77,7 +77,7 @@ pub fn default_module_type_provider(module_name: &str) -> Option<TypeConfig> {
|
||||
})),
|
||||
|
||||
"@tanstack/react-virtual" => Some(TypeConfig::Object(ObjectTypeConfig {
|
||||
properties: Some(IndexMap::from([(
|
||||
properties: Some(IndexMap::from_iter([(
|
||||
"useVirtualizer".to_string(),
|
||||
TypeConfig::Hook(HookTypeConfig {
|
||||
positional_params: Some(Vec::new()),
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
//! Uses the Cooper/Harvey/Kennedy algorithm from
|
||||
//! https://www.cs.rice.edu/~keith/Embed/dom.pdf
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_diagnostics::{CompilerDiagnostic, ErrorCategory};
|
||||
|
||||
@@ -24,7 +24,7 @@ use crate::{BlockId, HirFunction, Terminal};
|
||||
pub struct PostDominator {
|
||||
/// The exit node (synthetic node representing function exit).
|
||||
pub exit: BlockId,
|
||||
nodes: HashMap<BlockId, BlockId>,
|
||||
nodes: FxHashMap<BlockId, BlockId>,
|
||||
}
|
||||
|
||||
impl PostDominator {
|
||||
@@ -50,8 +50,8 @@ impl PostDominator {
|
||||
struct Node {
|
||||
id: BlockId,
|
||||
index: usize,
|
||||
preds: HashSet<BlockId>,
|
||||
succs: HashSet<BlockId>,
|
||||
preds: FxHashSet<BlockId>,
|
||||
succs: FxHashSet<BlockId>,
|
||||
}
|
||||
|
||||
struct Graph {
|
||||
@@ -59,7 +59,7 @@ struct Graph {
|
||||
/// Nodes stored in iteration order (RPO for reverse graph).
|
||||
nodes: Vec<Node>,
|
||||
/// Map from BlockId to index in the nodes vec.
|
||||
node_index: HashMap<BlockId, usize>,
|
||||
node_index: FxHashMap<BlockId, usize>,
|
||||
}
|
||||
|
||||
impl Graph {
|
||||
@@ -112,7 +112,7 @@ fn build_reverse_graph(
|
||||
let exit_id = BlockId(next_block_id_counter);
|
||||
|
||||
// Build initial nodes with reversed edges
|
||||
let mut raw_nodes: HashMap<BlockId, Node> = HashMap::new();
|
||||
let mut raw_nodes: FxHashMap<BlockId, Node> = FxHashMap::default();
|
||||
|
||||
// Create exit node
|
||||
raw_nodes.insert(
|
||||
@@ -120,15 +120,15 @@ fn build_reverse_graph(
|
||||
Node {
|
||||
id: exit_id,
|
||||
index: 0,
|
||||
preds: HashSet::new(),
|
||||
succs: HashSet::new(),
|
||||
preds: FxHashSet::default(),
|
||||
succs: FxHashSet::default(),
|
||||
},
|
||||
);
|
||||
|
||||
for (id, block) in &func.body.blocks {
|
||||
let successors = each_terminal_successor(&block.terminal);
|
||||
let mut preds_set: HashSet<BlockId> = successors.into_iter().collect();
|
||||
let succs_set: HashSet<BlockId> = block.preds.iter().copied().collect();
|
||||
let mut preds_set: FxHashSet<BlockId> = successors.into_iter().collect();
|
||||
let succs_set: FxHashSet<BlockId> = block.preds.iter().copied().collect();
|
||||
|
||||
let is_return = matches!(&block.terminal, Terminal::Return { .. });
|
||||
let is_throw = matches!(&block.terminal, Terminal::Throw { .. });
|
||||
@@ -150,7 +150,7 @@ fn build_reverse_graph(
|
||||
}
|
||||
|
||||
// DFS from exit to compute RPO
|
||||
let mut visited = HashSet::new();
|
||||
let mut visited = FxHashSet::default();
|
||||
let mut postorder = Vec::new();
|
||||
dfs_postorder(exit_id, &raw_nodes, &mut visited, &mut postorder);
|
||||
|
||||
@@ -158,7 +158,7 @@ fn build_reverse_graph(
|
||||
postorder.reverse();
|
||||
|
||||
let mut nodes = Vec::with_capacity(postorder.len());
|
||||
let mut node_index = HashMap::new();
|
||||
let mut node_index = FxHashMap::default();
|
||||
for (idx, id) in postorder.into_iter().enumerate() {
|
||||
let mut node = raw_nodes.remove(&id).unwrap();
|
||||
node.index = idx;
|
||||
@@ -175,8 +175,8 @@ fn build_reverse_graph(
|
||||
|
||||
fn dfs_postorder(
|
||||
id: BlockId,
|
||||
nodes: &HashMap<BlockId, Node>,
|
||||
visited: &mut HashSet<BlockId>,
|
||||
nodes: &FxHashMap<BlockId, Node>,
|
||||
visited: &mut FxHashSet<BlockId>,
|
||||
postorder: &mut Vec<BlockId>,
|
||||
) {
|
||||
if !visited.insert(id) {
|
||||
@@ -196,8 +196,8 @@ fn dfs_postorder(
|
||||
|
||||
fn compute_immediate_dominators(
|
||||
graph: &Graph,
|
||||
) -> Result<HashMap<BlockId, BlockId>, CompilerDiagnostic> {
|
||||
let mut doms: HashMap<BlockId, BlockId> = HashMap::new();
|
||||
) -> Result<FxHashMap<BlockId, BlockId>, CompilerDiagnostic> {
|
||||
let mut doms: FxHashMap<BlockId, BlockId> = FxHashMap::default();
|
||||
doms.insert(graph.entry, graph.entry);
|
||||
|
||||
let mut changed = true;
|
||||
@@ -249,7 +249,7 @@ fn compute_immediate_dominators(
|
||||
Ok(doms)
|
||||
}
|
||||
|
||||
fn intersect(a: BlockId, b: BlockId, graph: &Graph, doms: &HashMap<BlockId, BlockId>) -> BlockId {
|
||||
fn intersect(a: BlockId, b: BlockId, graph: &Graph, doms: &FxHashMap<BlockId, BlockId>) -> BlockId {
|
||||
let mut block1 = graph.get_node(a);
|
||||
let mut block2 = graph.get_node(b);
|
||||
while block1.id != block2.id {
|
||||
@@ -277,10 +277,10 @@ pub fn post_dominator_frontier(
|
||||
func: &HirFunction,
|
||||
post_dominators: &PostDominator,
|
||||
target_id: BlockId,
|
||||
) -> HashSet<BlockId> {
|
||||
) -> FxHashSet<BlockId> {
|
||||
let target_post_dominators = post_dominators_of(func, post_dominators, target_id);
|
||||
let mut visited = HashSet::new();
|
||||
let mut frontier = HashSet::new();
|
||||
let mut visited = FxHashSet::default();
|
||||
let mut frontier = FxHashSet::default();
|
||||
|
||||
let mut to_visit: Vec<BlockId> = target_post_dominators.iter().copied().collect();
|
||||
to_visit.push(target_id);
|
||||
@@ -305,9 +305,9 @@ pub fn post_dominators_of(
|
||||
func: &HirFunction,
|
||||
post_dominators: &PostDominator,
|
||||
target_id: BlockId,
|
||||
) -> HashSet<BlockId> {
|
||||
let mut result = HashSet::new();
|
||||
let mut visited = HashSet::new();
|
||||
) -> FxHashSet<BlockId> {
|
||||
let mut result = FxHashSet::default();
|
||||
let mut visited = FxHashSet::default();
|
||||
let mut queue = vec![target_id];
|
||||
|
||||
while let Some(current_id) = queue.pop() {
|
||||
@@ -339,8 +339,8 @@ pub fn post_dominators_of(
|
||||
pub fn compute_unconditional_blocks(
|
||||
func: &HirFunction,
|
||||
next_block_id_counter: u32,
|
||||
) -> Result<HashSet<BlockId>, CompilerDiagnostic> {
|
||||
let mut unconditional = HashSet::new();
|
||||
) -> Result<FxHashSet<BlockId>, CompilerDiagnostic> {
|
||||
let mut unconditional = FxHashSet::default();
|
||||
let dominators = compute_post_dominator_tree(func, next_block_id_counter, false)?;
|
||||
let exit = dominators.exit;
|
||||
let mut current: Option<BlockId> = Some(func.body.entry);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_diagnostics::CompilerDiagnostic;
|
||||
use react_compiler_diagnostics::CompilerError;
|
||||
@@ -80,12 +79,12 @@ pub struct Environment {
|
||||
// Used by codegen to filter type annotation renames — only rename identifiers
|
||||
// whose node_id is in this set (type labels like ObjectTypeIndexer params
|
||||
// are NOT in this set and should keep their original names).
|
||||
pub reference_node_ids: HashSet<u32>,
|
||||
pub reference_node_ids: FxHashSet<u32>,
|
||||
|
||||
// Hoisted identifiers: tracks which bindings have already been hoisted
|
||||
// via DeclareContext to avoid duplicate hoisting.
|
||||
// Uses u32 to avoid depending on react_compiler_ast types.
|
||||
hoisted_identifiers: HashSet<u32>,
|
||||
hoisted_identifiers: FxHashSet<u32>,
|
||||
|
||||
// Config flags for validation passes (kept for backwards compat with existing pipeline code)
|
||||
pub validate_preserve_existing_memoization_guarantees: bool,
|
||||
@@ -95,8 +94,8 @@ pub struct Environment {
|
||||
// Type system registries
|
||||
globals: GlobalRegistry,
|
||||
pub shapes: ShapeRegistry,
|
||||
module_types: HashMap<String, Option<Global>>,
|
||||
module_type_errors: HashMap<String, Vec<String>>,
|
||||
module_types: FxHashMap<String, Option<Global>>,
|
||||
module_type_errors: FxHashMap<String, Vec<String>>,
|
||||
|
||||
// Environment configuration (feature flags, custom hooks, etc.)
|
||||
pub config: EnvironmentConfig,
|
||||
@@ -111,7 +110,7 @@ pub struct Environment {
|
||||
// Known names for collision-aware UID generation. Lazily populated from
|
||||
// identifiers on first use, then updated with each generated name.
|
||||
// Matches Babel's generateUid behavior of checking hasBinding/hasReference.
|
||||
uid_known_names: Option<HashSet<String>>,
|
||||
uid_known_names: Option<FxHashSet<String>>,
|
||||
}
|
||||
|
||||
/// An outlined function entry, stored on Environment during compilation.
|
||||
@@ -164,7 +163,7 @@ impl Environment {
|
||||
}
|
||||
|
||||
// Register reanimated module type when enabled
|
||||
let mut module_types: HashMap<String, Option<Global>> = HashMap::new();
|
||||
let mut module_types: FxHashMap<String, Option<Global>> = FxHashMap::default();
|
||||
if config.enable_custom_type_definition_for_reanimated {
|
||||
let reanimated_module_type = globals::get_reanimated_module_type(&mut shapes);
|
||||
module_types.insert(
|
||||
@@ -190,8 +189,8 @@ impl Environment {
|
||||
instrument_gating_name: None,
|
||||
hook_guard_name: None,
|
||||
renames: Vec::new(),
|
||||
reference_node_ids: HashSet::new(),
|
||||
hoisted_identifiers: HashSet::new(),
|
||||
reference_node_ids: FxHashSet::default(),
|
||||
hoisted_identifiers: FxHashSet::default(),
|
||||
validate_preserve_existing_memoization_guarantees: config
|
||||
.validate_preserve_existing_memoization_guarantees,
|
||||
validate_no_set_state_in_render: config.validate_no_set_state_in_render,
|
||||
@@ -200,7 +199,7 @@ impl Environment {
|
||||
globals: global_registry,
|
||||
shapes,
|
||||
module_types,
|
||||
module_type_errors: HashMap::new(),
|
||||
module_type_errors: FxHashMap::default(),
|
||||
default_nonmutating_hook: None,
|
||||
default_mutating_hook: None,
|
||||
outlined_functions: Vec::new(),
|
||||
@@ -237,8 +236,8 @@ impl Environment {
|
||||
instrument_gating_name: self.instrument_gating_name.clone(),
|
||||
hook_guard_name: self.hook_guard_name.clone(),
|
||||
renames: Vec::new(),
|
||||
reference_node_ids: HashSet::new(),
|
||||
hoisted_identifiers: HashSet::new(),
|
||||
reference_node_ids: FxHashSet::default(),
|
||||
hoisted_identifiers: FxHashSet::default(),
|
||||
validate_preserve_existing_memoization_guarantees: self
|
||||
.validate_preserve_existing_memoization_guarantees,
|
||||
validate_no_set_state_in_render: self.validate_no_set_state_in_render,
|
||||
@@ -897,7 +896,7 @@ impl Environment {
|
||||
// Lazily build the set of known names from existing identifiers.
|
||||
// This approximates Babel's hasBinding/hasGlobal/hasReference checks.
|
||||
if self.uid_known_names.is_none() {
|
||||
let mut known = HashSet::new();
|
||||
let mut known = FxHashSet::default();
|
||||
for id in &self.identifiers {
|
||||
if let Some(name) = &id.name {
|
||||
known.insert(name.value().to_string());
|
||||
@@ -929,7 +928,7 @@ impl Environment {
|
||||
/// Seed the UID known names set with external names (e.g. from ProgramContext).
|
||||
/// This ensures UID generation avoids names generated by previous function compilations,
|
||||
/// matching Babel's behavior where the program scope accumulates all generated UIDs.
|
||||
pub fn seed_uid_known_names(&mut self, names: &HashSet<String>) {
|
||||
pub fn seed_uid_known_names(&mut self, names: &FxHashSet<String>) {
|
||||
match &mut self.uid_known_names {
|
||||
Some(existing) => existing.extend(names.iter().cloned()),
|
||||
None => self.uid_known_names = Some(names.clone()),
|
||||
@@ -937,7 +936,7 @@ impl Environment {
|
||||
}
|
||||
|
||||
/// Return the UID known names accumulated during this compilation.
|
||||
pub fn take_uid_known_names(&mut self) -> Option<HashSet<String>> {
|
||||
pub fn take_uid_known_names(&mut self) -> Option<FxHashSet<String>> {
|
||||
self.uid_known_names.take()
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
//!
|
||||
//! Contains feature flags and custom hook definitions that control compiler behavior.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use indexmap::IndexMap;
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -80,12 +81,12 @@ fn default_true() -> bool {
|
||||
pub struct EnvironmentConfig {
|
||||
/// Custom hook type definitions, keyed by hook name.
|
||||
#[serde(default)]
|
||||
pub custom_hooks: HashMap<String, HookConfig>,
|
||||
pub custom_hooks: FxHashMap<String, HookConfig>,
|
||||
|
||||
/// Pre-resolved module type provider results.
|
||||
/// Map from module name to TypeConfig, computed by the JS shim.
|
||||
#[serde(default)]
|
||||
pub module_type_provider: Option<indexmap::IndexMap<String, TypeConfig>>,
|
||||
pub module_type_provider: Option<IndexMap<String, TypeConfig, FxBuildHasher>>,
|
||||
|
||||
/// Custom macro-like function names that should have their operands
|
||||
/// memoized in the same scope (similar to fbt).
|
||||
@@ -185,7 +186,7 @@ pub struct EnvironmentConfig {
|
||||
impl Default for EnvironmentConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
custom_hooks: HashMap::new(),
|
||||
custom_hooks: FxHashMap::default(),
|
||||
enable_reset_cache_on_source_file_changes: None,
|
||||
module_type_provider: None,
|
||||
enable_preserve_existing_memoization_guarantees: true,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//! Provides `DEFAULT_SHAPES` (built-in object shapes) and `DEFAULT_GLOBALS`
|
||||
//! (global variable types including React hooks and JS built-ins).
|
||||
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use crate::Effect;
|
||||
@@ -31,14 +31,14 @@ pub type Global = Type;
|
||||
/// Registry mapping global names to their types.
|
||||
///
|
||||
/// Supports two modes:
|
||||
/// - **Builder mode** (`base=None`): wraps a single HashMap, used during
|
||||
/// - **Builder mode** (`base=None`): wraps a single FxHashMap, used during
|
||||
/// `build_default_globals` to construct the static base.
|
||||
/// - **Overlay mode** (`base=Some`): holds a `&'static HashMap` base plus a small
|
||||
/// extras HashMap. Lookups check extras first, then base. Inserts go into extras.
|
||||
/// - **Overlay mode** (`base=Some`): holds a `&'static FxHashMap` base plus a small
|
||||
/// extras FxHashMap. Lookups check extras first, then base. Inserts go into extras.
|
||||
/// Cloning only copies the extras map (the base pointer is shared).
|
||||
pub struct GlobalRegistry {
|
||||
base: Option<&'static HashMap<String, Global>>,
|
||||
entries: HashMap<String, Global>,
|
||||
base: Option<&'static FxHashMap<String, Global>>,
|
||||
entries: FxHashMap<String, Global>,
|
||||
}
|
||||
|
||||
impl GlobalRegistry {
|
||||
@@ -46,15 +46,15 @@ impl GlobalRegistry {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
base: None,
|
||||
entries: HashMap::new(),
|
||||
entries: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an overlay-mode registry backed by a static base.
|
||||
pub fn with_base(base: &'static HashMap<String, Global>) -> Self {
|
||||
pub fn with_base(base: &'static FxHashMap<String, Global>) -> Self {
|
||||
Self {
|
||||
base: Some(base),
|
||||
entries: HashMap::new(),
|
||||
entries: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,9 +83,9 @@ impl GlobalRegistry {
|
||||
self.entries.keys().chain(base_keys)
|
||||
}
|
||||
|
||||
/// Consume the registry and return the inner HashMap.
|
||||
/// Consume the registry and return the inner FxHashMap.
|
||||
/// Only valid in builder mode (no base).
|
||||
pub fn into_inner(self) -> HashMap<String, Global> {
|
||||
pub fn into_inner(self) -> FxHashMap<String, Global> {
|
||||
debug_assert!(
|
||||
self.base.is_none(),
|
||||
"into_inner() called on overlay-mode GlobalRegistry"
|
||||
@@ -108,8 +108,8 @@ impl Clone for GlobalRegistry {
|
||||
// =============================================================================
|
||||
|
||||
struct BaseRegistries {
|
||||
shapes: HashMap<String, ObjectShape>,
|
||||
globals: HashMap<String, Global>,
|
||||
shapes: FxHashMap<String, ObjectShape>,
|
||||
globals: FxHashMap<String, Global>,
|
||||
}
|
||||
|
||||
static BASE: LazyLock<BaseRegistries> = LazyLock::new(|| {
|
||||
@@ -122,12 +122,12 @@ static BASE: LazyLock<BaseRegistries> = LazyLock::new(|| {
|
||||
});
|
||||
|
||||
/// Get a reference to the static base shapes registry.
|
||||
pub fn base_shapes() -> &'static HashMap<String, ObjectShape> {
|
||||
pub fn base_shapes() -> &'static FxHashMap<String, ObjectShape> {
|
||||
&BASE.shapes
|
||||
}
|
||||
|
||||
/// Get a reference to the static base globals registry.
|
||||
pub fn base_globals() -> &'static HashMap<String, Global> {
|
||||
pub fn base_globals() -> &'static FxHashMap<String, Global> {
|
||||
&BASE.globals
|
||||
}
|
||||
|
||||
@@ -1332,7 +1332,7 @@ fn build_object_shape(shapes: &mut ShapeRegistry) {
|
||||
None,
|
||||
false,
|
||||
);
|
||||
let mut mixed_props = HashMap::new();
|
||||
let mut mixed_props = FxHashMap::default();
|
||||
mixed_props.insert("toString".to_string(), mixed_to_string);
|
||||
mixed_props.insert("indexOf".to_string(), mixed_index_of);
|
||||
mixed_props.insert("includes".to_string(), mixed_includes);
|
||||
|
||||
@@ -9,14 +9,14 @@ pub mod reactive;
|
||||
pub mod type_config;
|
||||
pub mod visitors;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use indexmap::IndexSet;
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
pub use react_compiler_diagnostics::CompilerDiagnostic;
|
||||
pub use react_compiler_diagnostics::ErrorCategory;
|
||||
pub use react_compiler_diagnostics::GENERATED_SOURCE;
|
||||
pub use react_compiler_diagnostics::Position;
|
||||
pub use react_compiler_diagnostics::SourceLocation;
|
||||
pub use reactive::*;
|
||||
use rustc_hash::FxBuildHasher;
|
||||
|
||||
// =============================================================================
|
||||
// ID newtypes
|
||||
@@ -57,7 +57,7 @@ pub struct MutableRangeId(pub u32);
|
||||
// =============================================================================
|
||||
|
||||
/// Wrapper around f64 that stores raw bytes for deterministic equality and hashing.
|
||||
/// This allows use in HashMap keys and ensures NaN == NaN (bitwise comparison).
|
||||
/// This allows use in FxHashMap keys and ensures NaN == NaN (bitwise comparison).
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct FloatValue(u64);
|
||||
|
||||
@@ -190,7 +190,7 @@ pub enum ParamPattern {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HIR {
|
||||
pub entry: BlockId,
|
||||
pub blocks: IndexMap<BlockId, BasicBlock>,
|
||||
pub blocks: IndexMap<BlockId, BasicBlock, FxBuildHasher>,
|
||||
}
|
||||
|
||||
/// Block kinds
|
||||
@@ -222,7 +222,7 @@ pub struct BasicBlock {
|
||||
pub id: BlockId,
|
||||
pub instructions: Vec<InstructionId>,
|
||||
pub terminal: Terminal,
|
||||
pub preds: IndexSet<BlockId>,
|
||||
pub preds: IndexSet<BlockId, FxBuildHasher>,
|
||||
pub phis: Vec<Phi>,
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ pub struct BasicBlock {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Phi {
|
||||
pub place: Place,
|
||||
pub operands: IndexMap<BlockId, Place>,
|
||||
pub operands: IndexMap<BlockId, Place, FxBuildHasher>,
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//! Defines the shape registry used by Environment to resolve property types
|
||||
//! and function call signatures for built-in objects, hooks, and user-defined types.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::Effect;
|
||||
use crate::Type;
|
||||
@@ -119,21 +119,21 @@ pub struct FunctionSignature {
|
||||
/// Ported from TS `ObjectShape`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ObjectShape {
|
||||
pub properties: HashMap<String, Type>,
|
||||
pub properties: FxHashMap<String, Type>,
|
||||
pub function_type: Option<FunctionSignature>,
|
||||
}
|
||||
|
||||
/// Registry mapping shape IDs to their ObjectShape definitions.
|
||||
///
|
||||
/// Supports two modes:
|
||||
/// - **Builder mode** (`base=None`): wraps a single HashMap, used during
|
||||
/// - **Builder mode** (`base=None`): wraps a single FxHashMap, used during
|
||||
/// `build_builtin_shapes` / `build_default_globals` to construct the static base.
|
||||
/// - **Overlay mode** (`base=Some`): holds a `&'static HashMap` base plus a small
|
||||
/// extras HashMap. Lookups check extras first, then base. Inserts go into extras.
|
||||
/// - **Overlay mode** (`base=Some`): holds a `&'static FxHashMap` base plus a small
|
||||
/// extras FxHashMap. Lookups check extras first, then base. Inserts go into extras.
|
||||
/// Cloning only copies the extras map (the base pointer is shared).
|
||||
pub struct ShapeRegistry {
|
||||
base: Option<&'static HashMap<String, ObjectShape>>,
|
||||
entries: HashMap<String, ObjectShape>,
|
||||
base: Option<&'static FxHashMap<String, ObjectShape>>,
|
||||
entries: FxHashMap<String, ObjectShape>,
|
||||
}
|
||||
|
||||
impl ShapeRegistry {
|
||||
@@ -141,15 +141,15 @@ impl ShapeRegistry {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
base: None,
|
||||
entries: HashMap::new(),
|
||||
entries: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an overlay-mode registry backed by a static base.
|
||||
pub fn with_base(base: &'static HashMap<String, ObjectShape>) -> Self {
|
||||
pub fn with_base(base: &'static FxHashMap<String, ObjectShape>) -> Self {
|
||||
Self {
|
||||
base: Some(base),
|
||||
entries: HashMap::new(),
|
||||
entries: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,9 +163,9 @@ impl ShapeRegistry {
|
||||
self.entries.insert(key, value);
|
||||
}
|
||||
|
||||
/// Consume the registry and return the inner HashMap.
|
||||
/// Consume the registry and return the inner FxHashMap.
|
||||
/// Only valid in builder mode (no base).
|
||||
pub fn into_inner(self) -> HashMap<String, ObjectShape> {
|
||||
pub fn into_inner(self) -> FxHashMap<String, ObjectShape> {
|
||||
debug_assert!(
|
||||
self.base.is_none(),
|
||||
"into_inner() called on overlay-mode ShapeRegistry"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//! It also exports standalone formatting functions (format_loc, format_primitive, etc.)
|
||||
//! that require no state.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use react_compiler_diagnostics::CompilerError;
|
||||
use react_compiler_diagnostics::CompilerErrorOrDiagnostic;
|
||||
@@ -223,8 +223,8 @@ pub fn format_value_reason(reason: ValueReason) -> &'static str {
|
||||
/// like Places, Identifiers, Scopes, Types, InstructionValues, etc.
|
||||
pub struct PrintFormatter<'a> {
|
||||
pub env: &'a Environment,
|
||||
pub seen_identifiers: HashSet<IdentifierId>,
|
||||
pub seen_scopes: HashSet<ScopeId>,
|
||||
pub seen_identifiers: FxHashSet<IdentifierId>,
|
||||
pub seen_scopes: FxHashSet<ScopeId>,
|
||||
pub output: Vec<String>,
|
||||
pub indent_level: usize,
|
||||
}
|
||||
@@ -233,8 +233,8 @@ impl<'a> PrintFormatter<'a> {
|
||||
pub fn new(env: &'a Environment) -> Self {
|
||||
Self {
|
||||
env,
|
||||
seen_identifiers: HashSet::new(),
|
||||
seen_scopes: HashSet::new(),
|
||||
seen_identifiers: FxHashSet::default(),
|
||||
seen_scopes: FxHashSet::default(),
|
||||
output: Vec::new(),
|
||||
indent_level: 0,
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
//! and `installTypeConfig` to describe module/function/hook types.
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use rustc_hash::FxBuildHasher;
|
||||
|
||||
use crate::Effect;
|
||||
|
||||
@@ -166,7 +167,7 @@ pub enum TypeConfig {
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct ObjectTypeConfig {
|
||||
pub properties: Option<IndexMap<String, TypeConfig>>,
|
||||
pub properties: Option<IndexMap<String, TypeConfig, FxBuildHasher>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::environment::Environment;
|
||||
use crate::{
|
||||
@@ -1289,14 +1289,14 @@ pub struct ScopeBlockTraversal {
|
||||
/// Live stack of active scopes
|
||||
active_scopes: Vec<ScopeId>,
|
||||
/// Map from block ID to scope block info
|
||||
pub block_infos: HashMap<BlockId, ScopeBlockInfo>,
|
||||
pub block_infos: FxHashMap<BlockId, ScopeBlockInfo>,
|
||||
}
|
||||
|
||||
impl ScopeBlockTraversal {
|
||||
pub fn new() -> Self {
|
||||
ScopeBlockTraversal {
|
||||
active_scopes: Vec::new(),
|
||||
block_infos: HashMap::new(),
|
||||
block_infos: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,3 +11,4 @@ react_compiler_optimization = { path = "../react_compiler_optimization" }
|
||||
react_compiler_ssa = { path = "../react_compiler_ssa" }
|
||||
react_compiler_utils = { path = "../react_compiler_utils" }
|
||||
indexmap = "2"
|
||||
rustc-hash = "2"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
//!
|
||||
//! Ported from TypeScript `src/ReactiveScopes/AlignMethodCallScopes.ts`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use react_compiler_hir::environment::Environment;
|
||||
use react_compiler_hir::{EvaluationOrder, HirFunction, IdentifierId, InstructionValue, ScopeId};
|
||||
@@ -25,7 +25,7 @@ use react_compiler_utils::DisjointSet;
|
||||
/// Corresponds to TS `alignMethodCallScopes(fn: HIRFunction): void`.
|
||||
pub fn align_method_call_scopes(func: &mut HirFunction, env: &mut Environment) {
|
||||
// Maps an identifier to the scope it should be assigned to (or None to remove scope)
|
||||
let mut scope_mapping: HashMap<IdentifierId, Option<ScopeId>> = HashMap::new();
|
||||
let mut scope_mapping: FxHashMap<IdentifierId, Option<ScopeId>> = FxHashMap::default();
|
||||
let mut merged_scopes = DisjointSet::<ScopeId>::new();
|
||||
|
||||
// Phase 1: Walk instructions and collect scope relationships
|
||||
@@ -74,9 +74,10 @@ pub fn align_method_call_scopes(func: &mut HirFunction, env: &mut Environment) {
|
||||
}
|
||||
|
||||
// Phase 2: Merge scope ranges for unioned scopes.
|
||||
// Use a HashMap to accumulate min/max across all scopes mapping to the same root,
|
||||
// Use a FxHashMap to accumulate min/max across all scopes mapping to the same root,
|
||||
// matching TS behavior where root.range is updated in-place during iteration.
|
||||
let mut range_updates: HashMap<ScopeId, (EvaluationOrder, EvaluationOrder)> = HashMap::new();
|
||||
let mut range_updates: FxHashMap<ScopeId, (EvaluationOrder, EvaluationOrder)> =
|
||||
FxHashMap::default();
|
||||
|
||||
merged_scopes.for_each(|scope_id, root_id| {
|
||||
if scope_id == root_id {
|
||||
@@ -93,7 +94,7 @@ pub fn align_method_call_scopes(func: &mut HirFunction, env: &mut Environment) {
|
||||
});
|
||||
|
||||
// Save original scope range IDs before updating
|
||||
let original_range_ids: HashMap<ScopeId, react_compiler_hir::MutableRangeId> = range_updates
|
||||
let original_range_ids: FxHashMap<ScopeId, react_compiler_hir::MutableRangeId> = range_updates
|
||||
.keys()
|
||||
.map(|&root_id| {
|
||||
let range_id = env.scopes[root_id.0 as usize].range.id;
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
//!
|
||||
//! Ported from TypeScript `src/ReactiveScopes/AlignObjectMethodScopes.ts`.
|
||||
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use std::cmp;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use react_compiler_hir::environment::Environment;
|
||||
use react_compiler_hir::{
|
||||
@@ -26,7 +26,7 @@ use react_compiler_utils::DisjointSet;
|
||||
/// instructions whose operands reference those methods. Returns a disjoint set
|
||||
/// of scopes that must be merged.
|
||||
fn find_scopes_to_merge(func: &HirFunction, env: &Environment) -> DisjointSet<ScopeId> {
|
||||
let mut object_method_decls: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut object_method_decls: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
let mut merged_scopes = DisjointSet::<ScopeId>::new();
|
||||
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
@@ -99,9 +99,10 @@ pub fn align_object_method_scopes(func: &mut HirFunction, env: &mut Environment)
|
||||
let mut merged_scopes = find_scopes_to_merge(func, env);
|
||||
|
||||
// Step 1: Merge affected scopes to their canonical root.
|
||||
// Use a HashMap to accumulate min/max across all scopes mapping to the same root,
|
||||
// Use a FxHashMap to accumulate min/max across all scopes mapping to the same root,
|
||||
// matching TS behavior where root.range is updated in-place during iteration.
|
||||
let mut range_updates: HashMap<ScopeId, (EvaluationOrder, EvaluationOrder)> = HashMap::new();
|
||||
let mut range_updates: FxHashMap<ScopeId, (EvaluationOrder, EvaluationOrder)> =
|
||||
FxHashMap::default();
|
||||
|
||||
merged_scopes.for_each(|scope_id, root_id| {
|
||||
if scope_id == root_id {
|
||||
@@ -118,7 +119,7 @@ pub fn align_object_method_scopes(func: &mut HirFunction, env: &mut Environment)
|
||||
});
|
||||
|
||||
// Save original scope range IDs before updating
|
||||
let original_range_ids: HashMap<ScopeId, react_compiler_hir::MutableRangeId> = range_updates
|
||||
let original_range_ids: FxHashMap<ScopeId, react_compiler_hir::MutableRangeId> = range_updates
|
||||
.keys()
|
||||
.map(|&root_id| {
|
||||
let range_id = env.scopes[root_id.0 as usize].range.id;
|
||||
@@ -147,7 +148,7 @@ pub fn align_object_method_scopes(func: &mut HirFunction, env: &mut Environment)
|
||||
|
||||
// Step 2: Repoint identifiers whose scopes were merged
|
||||
// Build a map from old scope -> root scope for quick lookup
|
||||
let mut scope_remap: HashMap<ScopeId, ScopeId> = HashMap::new();
|
||||
let mut scope_remap: FxHashMap<ScopeId, ScopeId> = FxHashMap::default();
|
||||
merged_scopes.for_each(|scope_id, root_id| {
|
||||
if scope_id != root_id {
|
||||
scope_remap.insert(scope_id, root_id);
|
||||
|
||||
+6
-7
@@ -22,8 +22,7 @@
|
||||
//! instructions in each scope, the scopes must be aligned to block-scope
|
||||
//! boundaries — we can't memoize half of a loop!
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_hir::BlockId;
|
||||
use react_compiler_hir::BlockKind;
|
||||
@@ -99,9 +98,9 @@ pub fn align_reactive_scopes_to_block_scopes_hir(func: &mut HirFunction, env: &m
|
||||
env.scopes.iter().map(|s| s.range.clone()).collect();
|
||||
|
||||
let mut active_block_fallthrough_ranges: Vec<BlockFallthroughRange> = Vec::new();
|
||||
let mut active_scopes: HashSet<ScopeId> = HashSet::new();
|
||||
let mut seen: HashSet<ScopeId> = HashSet::new();
|
||||
let mut value_block_nodes: HashMap<BlockId, ValueBlockNode> = HashMap::new();
|
||||
let mut active_scopes: FxHashSet<ScopeId> = FxHashSet::default();
|
||||
let mut seen: FxHashSet<ScopeId> = FxHashSet::default();
|
||||
let mut value_block_nodes: FxHashMap<BlockId, ValueBlockNode> = FxHashMap::default();
|
||||
|
||||
let block_ids: Vec<BlockId> = func.body.blocks.keys().copied().collect();
|
||||
|
||||
@@ -301,8 +300,8 @@ fn record_place_id(
|
||||
identifier_id: IdentifierId,
|
||||
node: &Option<ValueBlockNode>,
|
||||
env: &mut Environment,
|
||||
active_scopes: &mut HashSet<ScopeId>,
|
||||
seen: &mut HashSet<ScopeId>,
|
||||
active_scopes: &mut FxHashSet<ScopeId>,
|
||||
seen: &mut FxHashSet<ScopeId>,
|
||||
) {
|
||||
// Get the scope for this identifier, if active at this instruction
|
||||
let scope_id = match env.identifiers[identifier_id.0 as usize].scope {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
use indexmap::IndexMap;
|
||||
use react_compiler_diagnostics::{CompilerDiagnostic, ErrorCategory};
|
||||
use react_compiler_hir::environment::Environment;
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use react_compiler_hir::{
|
||||
AliasingEffect, BlockId, Effect, EvaluationOrder, FunctionId, HIR, HirFunction, IdentifierId,
|
||||
@@ -138,7 +138,7 @@ where
|
||||
|
||||
// Phase 2: Populate the Effect of each context variable to use in inferring
|
||||
// the outer function. Corresponds to TS Phase 2 in lowerWithMutationAliasing.
|
||||
let mut captured_or_mutated: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut captured_or_mutated: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
for effect in &function_effects {
|
||||
match effect {
|
||||
AliasingEffect::Assign { from, .. }
|
||||
@@ -208,7 +208,7 @@ fn placeholder_function() -> HirFunction {
|
||||
context: Vec::new(),
|
||||
body: HIR {
|
||||
entry: BlockId(0),
|
||||
blocks: IndexMap::new(),
|
||||
blocks: IndexMap::default(),
|
||||
},
|
||||
instructions: Vec::new(),
|
||||
generator: false,
|
||||
|
||||
@@ -11,10 +11,9 @@
|
||||
//!
|
||||
//! Ported from TypeScript `src/HIR/BuildReactiveScopeTerminalsHIR.ts`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use react_compiler_hir::BasicBlock;
|
||||
use react_compiler_hir::BlockId;
|
||||
use react_compiler_hir::EvaluationOrder;
|
||||
@@ -38,7 +37,7 @@ use react_compiler_lowering::mark_predecessors;
|
||||
/// Collect all unique scopes from places in the function that have non-empty ranges.
|
||||
/// Corresponds to TS `getScopes(fn)`.
|
||||
fn get_scopes(func: &HirFunction, env: &Environment) -> Vec<ScopeId> {
|
||||
let mut scope_ids: HashSet<ScopeId> = HashSet::new();
|
||||
let mut scope_ids: FxHashSet<ScopeId> = FxHashSet::default();
|
||||
|
||||
let mut visit_place = |identifier_id: IdentifierId| {
|
||||
if let Some(scope_id) = env.identifiers[identifier_id.0 as usize].scope {
|
||||
@@ -117,7 +116,7 @@ fn collect_scope_rewrites(func: &HirFunction, env: &mut Environment) -> Vec<Term
|
||||
});
|
||||
|
||||
let mut rewrites: Vec<TerminalRewriteInfo> = Vec::new();
|
||||
let mut fallthroughs: HashMap<ScopeId, BlockId> = HashMap::new();
|
||||
let mut fallthroughs: FxHashMap<ScopeId, BlockId> = FxHashMap::default();
|
||||
let mut active_items: Vec<ScopeId> = Vec::new();
|
||||
|
||||
for i in 0..items.len() {
|
||||
@@ -222,7 +221,7 @@ fn handle_rewrite(
|
||||
};
|
||||
|
||||
let curr_block_id = context.next_block_id;
|
||||
let mut preds = indexmap::IndexSet::new();
|
||||
let mut preds = IndexSet::default();
|
||||
for &p in &context.next_preds {
|
||||
preds.insert(p);
|
||||
}
|
||||
@@ -264,8 +263,8 @@ pub fn build_reactive_scope_terminals_hir(func: &mut HirFunction, env: &mut Envi
|
||||
let mut queued_rewrites = collect_scope_rewrites(func, env);
|
||||
|
||||
// Step 2: Apply rewrites by splitting blocks
|
||||
let mut rewritten_final_blocks: HashMap<BlockId, BlockId> = HashMap::new();
|
||||
let mut next_blocks: IndexMap<BlockId, BasicBlock> = IndexMap::new();
|
||||
let mut rewritten_final_blocks: FxHashMap<BlockId, BlockId> = FxHashMap::default();
|
||||
let mut next_blocks: IndexMap<BlockId, BasicBlock, FxBuildHasher> = IndexMap::default();
|
||||
|
||||
// Reverse so we can pop from the end while traversing in ascending order
|
||||
queued_rewrites.reverse();
|
||||
@@ -300,7 +299,7 @@ pub fn build_reactive_scope_terminals_hir(func: &mut HirFunction, env: &mut Envi
|
||||
}
|
||||
|
||||
if !context.rewrites.is_empty() {
|
||||
let mut final_preds = indexmap::IndexSet::new();
|
||||
let mut final_preds = IndexSet::default();
|
||||
for &p in &context.next_preds {
|
||||
final_preds.insert(p);
|
||||
}
|
||||
|
||||
@@ -11,10 +11,9 @@
|
||||
//! creation, aliasing, mutation, freezing, and error conditions for each
|
||||
//! instruction and terminal in the HIR.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
|
||||
|
||||
use indexmap::IndexSet;
|
||||
use react_compiler_diagnostics::CompilerDiagnostic;
|
||||
use react_compiler_diagnostics::CompilerDiagnosticDetail;
|
||||
use react_compiler_diagnostics::ErrorCategory;
|
||||
@@ -61,7 +60,7 @@ pub fn infer_mutation_aliasing_effects(
|
||||
let mut initial_state = InferenceState::empty(env, is_function_expression);
|
||||
|
||||
// Map of blocks to the last (merged) incoming state that was processed
|
||||
let mut states_by_block: HashMap<BlockId, InferenceState> = HashMap::new();
|
||||
let mut states_by_block: FxHashMap<BlockId, InferenceState> = FxHashMap::default();
|
||||
|
||||
// Initialize context variables
|
||||
for ctx_place in &func.context {
|
||||
@@ -115,12 +114,12 @@ pub fn infer_mutation_aliasing_effects(
|
||||
}
|
||||
}
|
||||
|
||||
let mut queued_states: indexmap::IndexMap<BlockId, InferenceState> = indexmap::IndexMap::new();
|
||||
let mut queued_states: IndexMap<BlockId, InferenceState, FxBuildHasher> = IndexMap::default();
|
||||
|
||||
// Queue helper
|
||||
fn queue(
|
||||
queued_states: &mut indexmap::IndexMap<BlockId, InferenceState>,
|
||||
states_by_block: &HashMap<BlockId, InferenceState>,
|
||||
queued_states: &mut IndexMap<BlockId, InferenceState, FxBuildHasher>,
|
||||
states_by_block: &FxHashMap<BlockId, InferenceState>,
|
||||
block_id: BlockId,
|
||||
state: InferenceState,
|
||||
) {
|
||||
@@ -152,16 +151,16 @@ pub fn infer_mutation_aliasing_effects(
|
||||
let non_mutating_spreads = find_non_mutated_destructure_spreads(func, env);
|
||||
|
||||
let mut context = Context {
|
||||
interned_effects: HashMap::new(),
|
||||
instruction_signature_cache: HashMap::new(),
|
||||
catch_handlers: HashMap::new(),
|
||||
interned_effects: FxHashMap::default(),
|
||||
instruction_signature_cache: FxHashMap::default(),
|
||||
catch_handlers: FxHashMap::default(),
|
||||
is_function_expression,
|
||||
hoisted_context_declarations,
|
||||
non_mutating_spreads,
|
||||
effect_value_id_cache: HashMap::new(),
|
||||
function_values: HashMap::new(),
|
||||
function_signature_cache: HashMap::new(),
|
||||
aliasing_config_temp_cache: HashMap::new(),
|
||||
effect_value_id_cache: FxHashMap::default(),
|
||||
function_values: FxHashMap::default(),
|
||||
function_signature_cache: FxHashMap::default(),
|
||||
aliasing_config_temp_cache: FxHashMap::default(),
|
||||
};
|
||||
|
||||
let mut iteration_count = 0;
|
||||
@@ -262,11 +261,11 @@ impl ValueId {
|
||||
#[derive(Debug, Clone)]
|
||||
struct AbstractValue {
|
||||
kind: ValueKind,
|
||||
reason: IndexSet<ValueReason>,
|
||||
reason: IndexSet<ValueReason, FxBuildHasher>,
|
||||
}
|
||||
|
||||
fn hashset_of(r: ValueReason) -> IndexSet<ValueReason> {
|
||||
let mut s = IndexSet::new();
|
||||
fn hashset_of(r: ValueReason) -> IndexSet<ValueReason, FxBuildHasher> {
|
||||
let mut s = IndexSet::default();
|
||||
s.insert(r);
|
||||
s
|
||||
}
|
||||
@@ -282,9 +281,9 @@ fn hashset_of(r: ValueReason) -> IndexSet<ValueReason> {
|
||||
struct InferenceState {
|
||||
is_function_expression: bool,
|
||||
/// The kind of each value, based on its allocation site
|
||||
values: HashMap<ValueId, AbstractValue>,
|
||||
values: FxHashMap<ValueId, AbstractValue>,
|
||||
/// The set of values pointed to by each identifier
|
||||
variables: HashMap<IdentifierId, HashSet<ValueId>>,
|
||||
variables: FxHashMap<IdentifierId, FxHashSet<ValueId>>,
|
||||
/// Tracks uninitialized identifier access errors (matches TS invariant).
|
||||
/// Uses Cell so it can be set from `&self` methods like `kind()`.
|
||||
/// Stores (IdentifierId, usage_loc) where usage_loc is the source location
|
||||
@@ -296,8 +295,8 @@ impl InferenceState {
|
||||
fn empty(_env: &Environment, is_function_expression: bool) -> Self {
|
||||
InferenceState {
|
||||
is_function_expression,
|
||||
values: HashMap::new(),
|
||||
variables: HashMap::new(),
|
||||
values: FxHashMap::default(),
|
||||
variables: FxHashMap::default(),
|
||||
uninitialized_access: std::cell::Cell::new(None),
|
||||
}
|
||||
}
|
||||
@@ -342,7 +341,7 @@ impl InferenceState {
|
||||
}
|
||||
|
||||
fn define(&mut self, place_id: IdentifierId, value_id: ValueId) {
|
||||
let mut set = HashSet::new();
|
||||
let mut set = FxHashSet::default();
|
||||
set.insert(value_id);
|
||||
self.variables.insert(place_id, set);
|
||||
}
|
||||
@@ -354,7 +353,7 @@ impl InferenceState {
|
||||
// Create a stable value for uninitialized identifiers
|
||||
// Use a deterministic ID based on the from identifier
|
||||
let vid = ValueId(from.0 | 0x80000000);
|
||||
let mut set = HashSet::new();
|
||||
let mut set = FxHashSet::default();
|
||||
set.insert(vid);
|
||||
if !self.values.contains_key(&vid) {
|
||||
self.values.insert(
|
||||
@@ -380,7 +379,7 @@ impl InferenceState {
|
||||
Some(v) => v.clone(),
|
||||
None => return,
|
||||
};
|
||||
let merged: HashSet<ValueId> = prev_values.union(&new_values).copied().collect();
|
||||
let merged: FxHashSet<ValueId> = prev_values.union(&new_values).copied().collect();
|
||||
self.variables.insert(place, merged);
|
||||
}
|
||||
|
||||
@@ -486,8 +485,8 @@ impl InferenceState {
|
||||
}
|
||||
|
||||
fn merge(&self, other: &InferenceState) -> Option<InferenceState> {
|
||||
let mut next_values: Option<HashMap<ValueId, AbstractValue>> = None;
|
||||
let mut next_variables: Option<HashMap<IdentifierId, HashSet<ValueId>>> = None;
|
||||
let mut next_values: Option<FxHashMap<ValueId, AbstractValue>> = None;
|
||||
let mut next_variables: Option<FxHashMap<IdentifierId, FxHashSet<ValueId>>> = None;
|
||||
|
||||
// Merge values present in both
|
||||
for (id, this_value) in &self.values {
|
||||
@@ -521,7 +520,7 @@ impl InferenceState {
|
||||
}
|
||||
if has_new {
|
||||
let nvars = next_variables.get_or_insert_with(|| self.variables.clone());
|
||||
let merged: HashSet<ValueId> =
|
||||
let merged: FxHashSet<ValueId> =
|
||||
this_values.union(other_values).copied().collect();
|
||||
nvars.insert(*id, merged);
|
||||
}
|
||||
@@ -550,9 +549,9 @@ impl InferenceState {
|
||||
fn infer_phi(
|
||||
&mut self,
|
||||
phi_place_id: IdentifierId,
|
||||
phi_operands: &indexmap::IndexMap<BlockId, Place>,
|
||||
phi_operands: &IndexMap<BlockId, Place, FxBuildHasher>,
|
||||
) {
|
||||
let mut values: HashSet<ValueId> = HashSet::new();
|
||||
let mut values: FxHashSet<ValueId> = FxHashSet::default();
|
||||
for (_, operand) in phi_operands {
|
||||
if let Some(operand_values) = self.variables.get(&operand.identifier) {
|
||||
for v in operand_values {
|
||||
@@ -567,7 +566,10 @@ impl InferenceState {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_superset(a: &IndexSet<ValueReason>, b: &IndexSet<ValueReason>) -> bool {
|
||||
fn is_superset(
|
||||
a: &IndexSet<ValueReason, FxBuildHasher>,
|
||||
b: &IndexSet<ValueReason, FxBuildHasher>,
|
||||
) -> bool {
|
||||
b.iter().all(|x| a.contains(x))
|
||||
}
|
||||
|
||||
@@ -593,24 +595,24 @@ enum MutationResult {
|
||||
// =============================================================================
|
||||
|
||||
struct Context {
|
||||
interned_effects: HashMap<String, AliasingEffect>,
|
||||
instruction_signature_cache: HashMap<u32, InstructionSignature>,
|
||||
catch_handlers: HashMap<BlockId, Place>,
|
||||
interned_effects: FxHashMap<String, AliasingEffect>,
|
||||
instruction_signature_cache: FxHashMap<u32, InstructionSignature>,
|
||||
catch_handlers: FxHashMap<BlockId, Place>,
|
||||
is_function_expression: bool,
|
||||
hoisted_context_declarations: HashMap<DeclarationId, Option<Place>>,
|
||||
non_mutating_spreads: HashSet<IdentifierId>,
|
||||
hoisted_context_declarations: FxHashMap<DeclarationId, Option<Place>>,
|
||||
non_mutating_spreads: FxHashSet<IdentifierId>,
|
||||
/// Cache of ValueIds keyed by effect hash, ensuring stable allocation-site identity
|
||||
/// across fixpoint iterations. Mirrors TS `effectInstructionValueCache`.
|
||||
effect_value_id_cache: HashMap<String, ValueId>,
|
||||
effect_value_id_cache: FxHashMap<String, ValueId>,
|
||||
/// Maps ValueId to FunctionId for function expressions, so we can look up
|
||||
/// locally-declared functions when processing Apply effects.
|
||||
function_values: HashMap<ValueId, FunctionId>,
|
||||
function_values: FxHashMap<ValueId, FunctionId>,
|
||||
/// Cache of function expression signatures, keyed by FunctionId
|
||||
function_signature_cache: HashMap<FunctionId, AliasingSignature>,
|
||||
function_signature_cache: FxHashMap<FunctionId, AliasingSignature>,
|
||||
/// Cache of temporary places created for aliasing signature config temporaries.
|
||||
/// Keyed by (lvalue_identifier_id, temp_name) to ensure stable allocation
|
||||
/// across fixpoint iterations.
|
||||
aliasing_config_temp_cache: HashMap<(IdentifierId, String), Place>,
|
||||
aliasing_config_temp_cache: FxHashMap<(IdentifierId, String), Place>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
@@ -785,11 +787,11 @@ fn merge_value_kinds(a: ValueKind, b: ValueKind) -> ValueKind {
|
||||
fn find_hoisted_context_declarations(
|
||||
func: &HirFunction,
|
||||
env: &Environment,
|
||||
) -> HashMap<DeclarationId, Option<Place>> {
|
||||
let mut hoisted: HashMap<DeclarationId, Option<Place>> = HashMap::new();
|
||||
) -> FxHashMap<DeclarationId, Option<Place>> {
|
||||
let mut hoisted: FxHashMap<DeclarationId, Option<Place>> = FxHashMap::default();
|
||||
|
||||
fn visit(
|
||||
hoisted: &mut HashMap<DeclarationId, Option<Place>>,
|
||||
hoisted: &mut FxHashMap<DeclarationId, Option<Place>>,
|
||||
place: &Place,
|
||||
env: &Environment,
|
||||
) {
|
||||
@@ -831,8 +833,8 @@ fn find_hoisted_context_declarations(
|
||||
fn find_non_mutated_destructure_spreads(
|
||||
func: &HirFunction,
|
||||
env: &Environment,
|
||||
) -> HashSet<IdentifierId> {
|
||||
let mut known_frozen: HashSet<IdentifierId> = HashSet::new();
|
||||
) -> FxHashSet<IdentifierId> {
|
||||
let mut known_frozen: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
if func.fn_type == ReactFunctionType::Component {
|
||||
if let Some(param) = func.params.first() {
|
||||
if let ParamPattern::Place(p) = param {
|
||||
@@ -847,7 +849,8 @@ fn find_non_mutated_destructure_spreads(
|
||||
}
|
||||
}
|
||||
|
||||
let mut candidate_non_mutating_spreads: HashMap<IdentifierId, IdentifierId> = HashMap::new();
|
||||
let mut candidate_non_mutating_spreads: FxHashMap<IdentifierId, IdentifierId> =
|
||||
FxHashMap::default();
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
if !candidate_non_mutating_spreads.is_empty() {
|
||||
for phi in &block.phis {
|
||||
@@ -954,7 +957,7 @@ fn find_non_mutated_destructure_spreads(
|
||||
}
|
||||
}
|
||||
|
||||
let mut non_mutating: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut non_mutating: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
for (key, value) in &candidate_non_mutating_spreads {
|
||||
if key == value {
|
||||
non_mutating.insert(*key);
|
||||
@@ -991,7 +994,7 @@ fn infer_block(
|
||||
let block = &func.body.blocks[&block_id];
|
||||
|
||||
// Process phis
|
||||
let phis: Vec<(IdentifierId, indexmap::IndexMap<BlockId, Place>)> = block
|
||||
let phis: Vec<(IdentifierId, IndexMap<BlockId, Place, FxBuildHasher>)> = block
|
||||
.phis
|
||||
.iter()
|
||||
.map(|phi| (phi.place.identifier, phi.operands.clone()))
|
||||
@@ -1144,7 +1147,7 @@ fn apply_signature(
|
||||
| InstructionValue::ObjectMethod { lowered_func, .. } => {
|
||||
let inner_func = &env.functions[lowered_func.func.0 as usize];
|
||||
if let Some(ref aliasing_effects) = inner_func.aliasing_effects {
|
||||
let context_ids: HashSet<IdentifierId> =
|
||||
let context_ids: FxHashSet<IdentifierId> =
|
||||
inner_func.context.iter().map(|p| p.identifier).collect();
|
||||
for effect in aliasing_effects {
|
||||
let (mutate_value, is_mutate) = match effect {
|
||||
@@ -1203,7 +1206,7 @@ fn apply_signature(
|
||||
}
|
||||
|
||||
// Track which values we've already initialized
|
||||
let mut initialized: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut initialized: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
|
||||
// Get the cached signature effects
|
||||
let sig = context.instruction_signature_cache.get(&instr_idx).unwrap();
|
||||
@@ -1296,7 +1299,7 @@ fn apply_effect(
|
||||
context: &mut Context,
|
||||
state: &mut InferenceState,
|
||||
effect: AliasingEffect,
|
||||
initialized: &mut HashSet<IdentifierId>,
|
||||
initialized: &mut FxHashSet<IdentifierId>,
|
||||
effects: &mut Vec<AliasingEffect>,
|
||||
env: &mut Environment,
|
||||
func: &HirFunction,
|
||||
@@ -1484,7 +1487,7 @@ fn apply_effect(
|
||||
} else {
|
||||
ValueKind::Frozen
|
||||
},
|
||||
reason: IndexSet::new(),
|
||||
reason: IndexSet::default(),
|
||||
},
|
||||
);
|
||||
state.define(into.identifier, value_id);
|
||||
@@ -2582,7 +2585,7 @@ fn compute_effects_for_legacy_signature(
|
||||
args: &[PlaceOrSpreadOrHole],
|
||||
_loc: Option<&SourceLocation>,
|
||||
env: &Environment,
|
||||
function_values: &HashMap<ValueId, FunctionId>,
|
||||
function_values: &FxHashMap<ValueId, FunctionId>,
|
||||
todo_errors: &mut Vec<react_compiler_diagnostics::CompilerErrorDetail>,
|
||||
) -> Vec<AliasingEffect> {
|
||||
let return_value_reason = signature.return_value_reason.unwrap_or(ValueReason::Other);
|
||||
@@ -2786,7 +2789,7 @@ fn are_arguments_immutable_and_non_mutating(
|
||||
state: &InferenceState,
|
||||
args: &[PlaceOrSpreadOrHole],
|
||||
env: &Environment,
|
||||
function_values: &HashMap<ValueId, FunctionId>,
|
||||
function_values: &FxHashMap<ValueId, FunctionId>,
|
||||
) -> bool {
|
||||
for arg in args {
|
||||
match arg {
|
||||
@@ -2870,14 +2873,14 @@ fn compute_effects_for_aliasing_signature_config(
|
||||
args: &[PlaceOrSpreadOrHole],
|
||||
context: &[Place],
|
||||
_loc: Option<&SourceLocation>,
|
||||
temp_cache: &mut HashMap<(IdentifierId, String), Place>,
|
||||
temp_cache: &mut FxHashMap<(IdentifierId, String), Place>,
|
||||
) -> Result<Option<Vec<AliasingEffect>>, CompilerDiagnostic> {
|
||||
// Build substitutions from config strings to places
|
||||
let mut substitutions: HashMap<String, Vec<Place>> = HashMap::new();
|
||||
let mut substitutions: FxHashMap<String, Vec<Place>> = FxHashMap::default();
|
||||
substitutions.insert(config.receiver.clone(), vec![receiver.clone()]);
|
||||
substitutions.insert(config.returns.clone(), vec![lvalue.clone()]);
|
||||
|
||||
let mut mutable_spreads: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut mutable_spreads: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
match arg {
|
||||
@@ -3113,8 +3116,8 @@ fn compute_effects_for_aliasing_signature(
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut mutable_spreads: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut substitutions: HashMap<IdentifierId, Vec<Place>> = HashMap::new();
|
||||
let mut mutable_spreads: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
let mut substitutions: FxHashMap<IdentifierId, Vec<Place>> = FxHashMap::default();
|
||||
substitutions.insert(signature.receiver, vec![receiver.clone()]);
|
||||
substitutions.insert(signature.returns, vec![lvalue.clone()]);
|
||||
|
||||
@@ -3407,7 +3410,7 @@ fn compute_effects_for_aliasing_signature(
|
||||
/// since the primary reason is always inserted first, this effectively
|
||||
/// picks the most specific non-Other reason. We replicate this by
|
||||
/// preferring any non-Other reason over Other.
|
||||
fn primary_reason(reasons: &IndexSet<ValueReason>) -> ValueReason {
|
||||
fn primary_reason(reasons: &IndexSet<ValueReason, FxBuildHasher>) -> ValueReason {
|
||||
for &r in reasons {
|
||||
if r != ValueReason::Other {
|
||||
return r;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
//! vars, aliasing between params/context-vars/return-value)
|
||||
//! - The legacy `Effect` to store on each Place
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
@@ -76,10 +76,10 @@ enum NodeValue {
|
||||
#[derive(Debug, Clone)]
|
||||
struct Node {
|
||||
id: IdentifierId,
|
||||
created_from: IndexMap<IdentifierId, usize>,
|
||||
captures: IndexMap<IdentifierId, usize>,
|
||||
aliases: IndexMap<IdentifierId, usize>,
|
||||
maybe_aliases: IndexMap<IdentifierId, usize>,
|
||||
created_from: IndexMap<IdentifierId, usize, FxBuildHasher>,
|
||||
captures: IndexMap<IdentifierId, usize, FxBuildHasher>,
|
||||
aliases: IndexMap<IdentifierId, usize, FxBuildHasher>,
|
||||
maybe_aliases: IndexMap<IdentifierId, usize, FxBuildHasher>,
|
||||
edges: Vec<Edge>,
|
||||
transitive: Option<MutationInfo>,
|
||||
local: Option<MutationInfo>,
|
||||
@@ -92,10 +92,10 @@ impl Node {
|
||||
fn new(id: IdentifierId, value: NodeValue) -> Self {
|
||||
Node {
|
||||
id,
|
||||
created_from: IndexMap::new(),
|
||||
captures: IndexMap::new(),
|
||||
aliases: IndexMap::new(),
|
||||
maybe_aliases: IndexMap::new(),
|
||||
created_from: IndexMap::default(),
|
||||
captures: IndexMap::default(),
|
||||
aliases: IndexMap::default(),
|
||||
maybe_aliases: IndexMap::default(),
|
||||
edges: Vec::new(),
|
||||
transitive: None,
|
||||
local: None,
|
||||
@@ -107,13 +107,13 @@ impl Node {
|
||||
}
|
||||
|
||||
struct AliasingState {
|
||||
nodes: IndexMap<IdentifierId, Node>,
|
||||
nodes: IndexMap<IdentifierId, Node, FxBuildHasher>,
|
||||
}
|
||||
|
||||
impl AliasingState {
|
||||
fn new() -> Self {
|
||||
AliasingState {
|
||||
nodes: IndexMap::new(),
|
||||
nodes: IndexMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ impl AliasingState {
|
||||
}
|
||||
|
||||
fn render(&self, index: usize, start: IdentifierId, env: &mut Environment) {
|
||||
let mut seen = HashSet::new();
|
||||
let mut seen = FxHashSet::default();
|
||||
let mut queue: Vec<IdentifierId> = vec![start];
|
||||
while let Some(current) = queue.pop() {
|
||||
if !seen.insert(current) {
|
||||
@@ -260,7 +260,7 @@ impl AliasingState {
|
||||
Forwards,
|
||||
}
|
||||
|
||||
let mut seen: HashMap<IdentifierId, MutationKind> = HashMap::new();
|
||||
let mut seen: FxHashMap<IdentifierId, MutationKind> = FxHashMap::default();
|
||||
let mut queue: Vec<QueueEntry> = vec![QueueEntry {
|
||||
place: start,
|
||||
transitive,
|
||||
@@ -475,7 +475,7 @@ pub fn infer_mutation_aliasing_ranges(
|
||||
into: Place,
|
||||
index: usize,
|
||||
}
|
||||
let mut pending_phis: HashMap<BlockId, Vec<PendingPhiOperand>> = HashMap::new();
|
||||
let mut pending_phis: FxHashMap<BlockId, Vec<PendingPhiOperand>> = FxHashMap::default();
|
||||
|
||||
struct PendingMutation {
|
||||
index: usize,
|
||||
@@ -510,7 +510,7 @@ pub fn infer_mutation_aliasing_ranges(
|
||||
}
|
||||
state.create(&func.returns, NodeValue::Object);
|
||||
|
||||
let mut seen_blocks: HashSet<BlockId> = HashSet::new();
|
||||
let mut seen_blocks: FxHashSet<BlockId> = FxHashSet::default();
|
||||
|
||||
// Collect block iteration data to avoid borrow conflicts
|
||||
let block_order: Vec<BlockId> = func.body.blocks.keys().cloned().collect();
|
||||
@@ -734,7 +734,7 @@ pub fn infer_mutation_aliasing_ranges(
|
||||
// Set effect on mutated params/context vars
|
||||
// We need to do this in a separate pass because we need to know which params
|
||||
// were mutated before setting effects
|
||||
let mut captured_params: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut captured_params: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
for param in &func.params {
|
||||
let place = match param {
|
||||
react_compiler_hir::ParamPattern::Place(p) => p,
|
||||
@@ -892,7 +892,7 @@ pub fn infer_mutation_aliasing_ranges(
|
||||
|
||||
// Compute operand effects from instruction effects
|
||||
let effects = instr.effects.as_ref().unwrap().clone();
|
||||
let mut operand_effects: HashMap<IdentifierId, Effect> = HashMap::new();
|
||||
let mut operand_effects: FxHashMap<IdentifierId, Effect> = FxHashMap::default();
|
||||
|
||||
for effect in &effects {
|
||||
match effect {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
//! 4. Mutation with reactive operands
|
||||
//! 5. Conditional assignment based on reactive control flow
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_diagnostics::{CompilerDiagnostic, ErrorCategory};
|
||||
use react_compiler_hir::dominator::post_dominator_frontier;
|
||||
@@ -69,7 +69,7 @@ pub fn infer_reactive_places(
|
||||
// is already reactive, the TS `continue`s and skips operand processing.
|
||||
// We track which phi operand Places should be marked reactive.
|
||||
// Key: (block_id, phi_idx, operand_idx), Value: should be reactive
|
||||
let mut phi_operand_reactive: HashMap<(BlockId, usize, usize), bool> = HashMap::new();
|
||||
let mut phi_operand_reactive: FxHashMap<(BlockId, usize, usize), bool> = FxHashMap::default();
|
||||
|
||||
// Fixpoint iteration — compute reactive set
|
||||
loop {
|
||||
@@ -235,7 +235,7 @@ pub fn infer_reactive_places(
|
||||
|
||||
struct ReactivityMap<'a> {
|
||||
has_changes: bool,
|
||||
reactive: HashSet<IdentifierId>,
|
||||
reactive: FxHashSet<IdentifierId>,
|
||||
aliased_identifiers: &'a mut DisjointSet<IdentifierId>,
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ impl<'a> ReactivityMap<'a> {
|
||||
fn new(aliased_identifiers: &'a mut DisjointSet<IdentifierId>) -> Self {
|
||||
ReactivityMap {
|
||||
has_changes: false,
|
||||
reactive: HashSet::new(),
|
||||
reactive: FxHashSet::default(),
|
||||
aliased_identifiers,
|
||||
}
|
||||
}
|
||||
@@ -273,13 +273,13 @@ impl<'a> ReactivityMap<'a> {
|
||||
// =============================================================================
|
||||
|
||||
struct StableSidemap {
|
||||
map: HashMap<IdentifierId, bool>,
|
||||
map: FxHashMap<IdentifierId, bool>,
|
||||
}
|
||||
|
||||
impl StableSidemap {
|
||||
fn new() -> Self {
|
||||
StableSidemap {
|
||||
map: HashMap::new(),
|
||||
map: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,7 +538,7 @@ fn apply_reactive_flags_replay(
|
||||
env: &mut Environment,
|
||||
reactive_map: &mut ReactivityMap,
|
||||
stable_sidemap: &mut StableSidemap,
|
||||
phi_operand_reactive: &HashMap<(BlockId, usize, usize), bool>,
|
||||
phi_operand_reactive: &FxHashMap<(BlockId, usize, usize), bool>,
|
||||
) {
|
||||
let reactive_ids = build_reactive_id_set(reactive_map);
|
||||
|
||||
@@ -697,8 +697,8 @@ fn apply_reactive_flags_replay(
|
||||
apply_reactive_flags_to_inner_functions(func, env, &reactive_ids);
|
||||
}
|
||||
|
||||
fn build_reactive_id_set(reactive_map: &mut ReactivityMap) -> HashSet<IdentifierId> {
|
||||
let mut result = HashSet::new();
|
||||
fn build_reactive_id_set(reactive_map: &mut ReactivityMap) -> FxHashSet<IdentifierId> {
|
||||
let mut result = FxHashSet::default();
|
||||
for &id in &reactive_map.reactive {
|
||||
result.insert(id);
|
||||
}
|
||||
@@ -714,7 +714,7 @@ fn build_reactive_id_set(reactive_map: &mut ReactivityMap) -> HashSet<Identifier
|
||||
fn apply_reactive_flags_to_inner_functions(
|
||||
func: &HirFunction,
|
||||
env: &mut Environment,
|
||||
reactive_ids: &HashSet<IdentifierId>,
|
||||
reactive_ids: &FxHashSet<IdentifierId>,
|
||||
) {
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
for instr_id in &block.instructions {
|
||||
@@ -733,7 +733,7 @@ fn apply_reactive_flags_to_inner_functions(
|
||||
fn apply_reactive_flags_to_inner_func(
|
||||
func_id: FunctionId,
|
||||
env: &mut Environment,
|
||||
reactive_ids: &HashSet<IdentifierId>,
|
||||
reactive_ids: &FxHashSet<IdentifierId>,
|
||||
) {
|
||||
// Collect nested function IDs first to avoid borrow issues
|
||||
let nested_func_ids: Vec<FunctionId> = {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
//! 3. MergeOverlappingReactiveScopes ensures scopes do not overlap.
|
||||
//! 4. BuildReactiveBlocks groups the statements for each scope.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use react_compiler_diagnostics::{CompilerDiagnostic, ErrorCategory};
|
||||
use react_compiler_hir::environment::Environment;
|
||||
@@ -45,7 +45,7 @@ pub fn infer_reactive_scope_variables(
|
||||
|
||||
// Phase 2: assign scopes
|
||||
// Maps each group root identifier to the ScopeId assigned to that group.
|
||||
let mut scopes: HashMap<IdentifierId, ScopeState> = HashMap::new();
|
||||
let mut scopes: FxHashMap<IdentifierId, ScopeState> = FxHashMap::default();
|
||||
|
||||
scope_identifiers.for_each(|identifier_id, group_id| {
|
||||
let ident_range = env.identifiers[identifier_id.0 as usize]
|
||||
@@ -267,7 +267,7 @@ pub(crate) fn find_disjoint_mutable_values(
|
||||
env: &Environment,
|
||||
) -> DisjointSet<IdentifierId> {
|
||||
let mut scope_identifiers = DisjointSet::<IdentifierId>::new();
|
||||
let mut declarations: HashMap<DeclarationId, IdentifierId> = HashMap::new();
|
||||
let mut declarations: FxHashMap<DeclarationId, IdentifierId> = FxHashMap::default();
|
||||
|
||||
let enable_forest = env.config.enable_forest;
|
||||
|
||||
@@ -284,8 +284,8 @@ pub(crate) fn find_disjoint_mutable_values(
|
||||
.map(|iid| func.instructions[iid.0 as usize].id)
|
||||
.unwrap_or(block.terminal.evaluation_order());
|
||||
|
||||
let is_phi_mutated_after_creation = phi_range.start.0 + 1 != phi_range.end.0
|
||||
&& phi_range.end > first_instr_id;
|
||||
let is_phi_mutated_after_creation =
|
||||
phi_range.start.0 + 1 != phi_range.end.0 && phi_range.end > first_instr_id;
|
||||
// A phi operand defined at or after the phi's block is a loop
|
||||
// back-edge: the variable is reassigned within the loop (eg a
|
||||
// counter `a++` or `a = a + 1`). The reassignment must count as
|
||||
|
||||
+18
-20
@@ -13,7 +13,7 @@
|
||||
//! 1. Forward data-flow: identify all macro tags (including property loads like `fbt.param`)
|
||||
//! 2. Reverse data-flow: merge arguments of macro invocations into the same scope
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_hir::environment::Environment;
|
||||
use react_compiler_hir::visitors;
|
||||
@@ -34,7 +34,7 @@ enum InlineLevel {
|
||||
struct MacroDefinition {
|
||||
level: InlineLevel,
|
||||
/// Maps property names to their own MacroDefinition. `"*"` is a wildcard.
|
||||
properties: Option<HashMap<String, MacroDefinition>>,
|
||||
properties: Option<FxHashMap<String, MacroDefinition>>,
|
||||
}
|
||||
|
||||
fn shallow_macro() -> MacroDefinition {
|
||||
@@ -52,7 +52,7 @@ fn transitive_macro() -> MacroDefinition {
|
||||
}
|
||||
|
||||
fn fbt_macro() -> MacroDefinition {
|
||||
let mut props = HashMap::new();
|
||||
let mut props = FxHashMap::default();
|
||||
props.insert("*".to_string(), shallow_macro());
|
||||
// fbt.enum gets FBT_MACRO (recursive/transitive)
|
||||
// We'll fill this in after construction since it's self-referential.
|
||||
@@ -66,7 +66,7 @@ fn fbt_macro() -> MacroDefinition {
|
||||
let enum_macro = MacroDefinition {
|
||||
level: InlineLevel::Transitive,
|
||||
properties: Some({
|
||||
let mut p = HashMap::new();
|
||||
let mut p = FxHashMap::default();
|
||||
p.insert("*".to_string(), shallow_macro());
|
||||
// enum's enum is also recursive, but in practice the depth is bounded
|
||||
p.insert("enum".to_string(), transitive_macro());
|
||||
@@ -81,8 +81,8 @@ fn fbt_macro() -> MacroDefinition {
|
||||
}
|
||||
|
||||
/// Built-in FBT tags and their macro definitions.
|
||||
fn fbt_tags() -> HashMap<String, MacroDefinition> {
|
||||
let mut tags = HashMap::new();
|
||||
fn fbt_tags() -> FxHashMap<String, MacroDefinition> {
|
||||
let mut tags = FxHashMap::default();
|
||||
tags.insert("fbt".to_string(), fbt_macro());
|
||||
tags.insert("fbt:param".to_string(), shallow_macro());
|
||||
tags.insert("fbt:enum".to_string(), fbt_macro());
|
||||
@@ -98,9 +98,9 @@ fn fbt_tags() -> HashMap<String, MacroDefinition> {
|
||||
pub fn memoize_fbt_and_macro_operands_in_same_scope(
|
||||
func: &HirFunction,
|
||||
env: &mut Environment,
|
||||
) -> HashSet<IdentifierId> {
|
||||
) -> FxHashSet<IdentifierId> {
|
||||
// Phase 1: Build macro kinds map from built-in FBT tags + custom macros
|
||||
let mut macro_kinds: HashMap<String, MacroDefinition> = fbt_tags();
|
||||
let mut macro_kinds: FxHashMap<String, MacroDefinition> = fbt_tags();
|
||||
if let Some(ref custom_macros) = env.config.custom_macros {
|
||||
for name in custom_macros {
|
||||
macro_kinds.insert(name.clone(), transitive_macro());
|
||||
@@ -120,9 +120,9 @@ pub fn memoize_fbt_and_macro_operands_in_same_scope(
|
||||
/// things like `fbt.foo.bar(...)`.
|
||||
fn populate_macro_tags(
|
||||
func: &HirFunction,
|
||||
macro_kinds: &HashMap<String, MacroDefinition>,
|
||||
) -> HashMap<IdentifierId, MacroDefinition> {
|
||||
let mut macro_tags: HashMap<IdentifierId, MacroDefinition> = HashMap::new();
|
||||
macro_kinds: &FxHashMap<String, MacroDefinition>,
|
||||
) -> FxHashMap<IdentifierId, MacroDefinition> {
|
||||
let mut macro_tags: FxHashMap<IdentifierId, MacroDefinition> = FxHashMap::default();
|
||||
|
||||
for block in func.body.blocks.values() {
|
||||
for &instr_id in &block.instructions {
|
||||
@@ -134,9 +134,7 @@ fn populate_macro_tags(
|
||||
value: PrimitiveValue::String(s),
|
||||
..
|
||||
} => {
|
||||
if let Some(macro_def) =
|
||||
s.as_str().and_then(|utf8| macro_kinds.get(utf8))
|
||||
{
|
||||
if let Some(macro_def) = s.as_str().and_then(|utf8| macro_kinds.get(utf8)) {
|
||||
// We don't distinguish between tag names and strings, so record
|
||||
// all `fbt` string literals in case they are used as a jsx tag.
|
||||
macro_tags.insert(lvalue_id, macro_def.clone());
|
||||
@@ -180,10 +178,10 @@ fn populate_macro_tags(
|
||||
fn merge_macro_arguments(
|
||||
func: &HirFunction,
|
||||
env: &mut Environment,
|
||||
macro_tags: &mut HashMap<IdentifierId, MacroDefinition>,
|
||||
macro_kinds: &HashMap<String, MacroDefinition>,
|
||||
) -> HashSet<IdentifierId> {
|
||||
let mut macro_values: HashSet<IdentifierId> = macro_tags.keys().copied().collect();
|
||||
macro_tags: &mut FxHashMap<IdentifierId, MacroDefinition>,
|
||||
macro_kinds: &FxHashMap<String, MacroDefinition>,
|
||||
) -> FxHashSet<IdentifierId> {
|
||||
let mut macro_values: FxHashSet<IdentifierId> = macro_tags.keys().copied().collect();
|
||||
|
||||
// Iterate blocks in reverse order
|
||||
let block_ids: Vec<_> = func.body.blocks.keys().copied().collect();
|
||||
@@ -356,8 +354,8 @@ fn visit_operands(
|
||||
lvalue_id: IdentifierId,
|
||||
value: &InstructionValue,
|
||||
env: &mut Environment,
|
||||
macro_values: &mut HashSet<IdentifierId>,
|
||||
macro_tags: &mut HashMap<IdentifierId, MacroDefinition>,
|
||||
macro_values: &mut FxHashSet<IdentifierId>,
|
||||
macro_tags: &mut FxHashMap<IdentifierId, MacroDefinition>,
|
||||
) {
|
||||
macro_values.insert(lvalue_id);
|
||||
|
||||
|
||||
+8
-8
@@ -15,8 +15,8 @@
|
||||
//!
|
||||
//! Ported from TypeScript `src/HIR/MergeOverlappingReactiveScopesHIR.ts`.
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use react_compiler_hir::environment::Environment;
|
||||
use react_compiler_hir::visitors;
|
||||
@@ -46,7 +46,7 @@ struct ScopeInfo {
|
||||
/// Sorted descending by id (so we can pop from the end for smallest)
|
||||
scope_ends: Vec<ScopeEndEntry>,
|
||||
/// Maps IdentifierId -> ScopeId for all places that have a scope
|
||||
place_scopes: HashMap<IdentifierId, ScopeId>,
|
||||
place_scopes: FxHashMap<IdentifierId, ScopeId>,
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -95,9 +95,9 @@ fn is_mutable(env: &Environment, id: EvaluationOrder, identifier_id: IdentifierI
|
||||
// =============================================================================
|
||||
|
||||
fn collect_scope_info(func: &HirFunction, env: &Environment) -> ScopeInfo {
|
||||
let mut scope_starts_map: HashMap<EvaluationOrder, Vec<ScopeId>> = HashMap::new();
|
||||
let mut scope_ends_map: HashMap<EvaluationOrder, Vec<ScopeId>> = HashMap::new();
|
||||
let mut place_scopes: HashMap<IdentifierId, ScopeId> = HashMap::new();
|
||||
let mut scope_starts_map: FxHashMap<EvaluationOrder, Vec<ScopeId>> = FxHashMap::default();
|
||||
let mut scope_ends_map: FxHashMap<EvaluationOrder, Vec<ScopeId>> = FxHashMap::default();
|
||||
let mut place_scopes: FxHashMap<IdentifierId, ScopeId> = FxHashMap::default();
|
||||
|
||||
let mut collect_place_scope = |identifier_id: IdentifierId, env: &Environment| {
|
||||
let scope_id = match env.identifiers[identifier_id.0 as usize].scope {
|
||||
@@ -144,7 +144,7 @@ fn collect_scope_info(func: &HirFunction, env: &Environment) -> ScopeInfo {
|
||||
// We must NOT sort by ScopeId here — the insertion order determines which scope
|
||||
// becomes the root in the disjoint set union.
|
||||
fn dedup_preserve_order(scopes: &mut Vec<ScopeId>) {
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
let mut seen = rustc_hash::FxHashSet::default();
|
||||
scopes.retain(|s| seen.insert(*s));
|
||||
}
|
||||
for scopes in scope_starts_map.values_mut() {
|
||||
@@ -348,8 +348,8 @@ pub fn merge_overlapping_reactive_scopes_hir(func: &mut HirFunction, env: &mut E
|
||||
// When scope.range is updated, ALL identifiers referencing that range object
|
||||
// automatically see the new values. We use MutableRangeId to identify which
|
||||
// identifiers share the same logical range as a root scope.
|
||||
let mut original_root_range_ids: HashMap<ScopeId, react_compiler_hir::MutableRangeId> =
|
||||
HashMap::new();
|
||||
let mut original_root_range_ids: FxHashMap<ScopeId, react_compiler_hir::MutableRangeId> =
|
||||
FxHashMap::default();
|
||||
for (_, root_id) in &scope_groups {
|
||||
if !original_root_range_ids.contains_key(root_id) {
|
||||
let range_id = env.scopes[root_id.0 as usize].range.id;
|
||||
|
||||
+105
-100
@@ -13,7 +13,8 @@
|
||||
//! - `src/HIR/DeriveMinimalDependenciesHIR.ts`
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use react_compiler_hir::environment::Environment;
|
||||
use react_compiler_hir::visitors::{ScopeBlockInfo, ScopeBlockTraversal};
|
||||
@@ -44,7 +45,7 @@ pub fn propagate_scope_dependencies_hir(func: &mut HirFunction, env: &mut Enviro
|
||||
let (working, registry) =
|
||||
collect_hoistable_and_propagate(func, env, &temporaries, &hoistable_objects);
|
||||
// Convert to scope-keyed map with full dependency paths
|
||||
let mut keyed: HashMap<ScopeId, Vec<ReactiveScopeDependency>> = HashMap::new();
|
||||
let mut keyed: FxHashMap<ScopeId, Vec<ReactiveScopeDependency>> = FxHashMap::default();
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
if let Terminal::Scope {
|
||||
scope,
|
||||
@@ -128,17 +129,17 @@ fn are_equal_paths(a: &[DependencyPathEntry], b: &[DependencyPathEntry]) -> bool
|
||||
fn find_temporaries_used_outside_declaring_scope(
|
||||
func: &HirFunction,
|
||||
env: &Environment,
|
||||
) -> HashSet<DeclarationId> {
|
||||
let mut declarations: HashMap<DeclarationId, ScopeId> = HashMap::new();
|
||||
let mut pruned_scopes: HashSet<ScopeId> = HashSet::new();
|
||||
) -> FxHashSet<DeclarationId> {
|
||||
let mut declarations: FxHashMap<DeclarationId, ScopeId> = FxHashMap::default();
|
||||
let mut pruned_scopes: FxHashSet<ScopeId> = FxHashSet::default();
|
||||
let mut traversal = ScopeBlockTraversal::new();
|
||||
let mut used_outside_declaring_scope: HashSet<DeclarationId> = HashSet::new();
|
||||
let mut used_outside_declaring_scope: FxHashSet<DeclarationId> = FxHashSet::default();
|
||||
|
||||
let handle_place = |place_id: IdentifierId,
|
||||
declarations: &HashMap<DeclarationId, ScopeId>,
|
||||
declarations: &FxHashMap<DeclarationId, ScopeId>,
|
||||
traversal: &ScopeBlockTraversal,
|
||||
pruned_scopes: &HashSet<ScopeId>,
|
||||
used_outside: &mut HashSet<DeclarationId>,
|
||||
pruned_scopes: &FxHashSet<ScopeId>,
|
||||
used_outside: &mut FxHashSet<DeclarationId>,
|
||||
env: &Environment| {
|
||||
let decl_id = env.identifiers[place_id.0 as usize].declaration_id;
|
||||
if let Some(&declaring_scope) = declarations.get(&decl_id) {
|
||||
@@ -227,9 +228,9 @@ fn find_temporaries_used_outside_declaring_scope(
|
||||
fn collect_temporaries_sidemap(
|
||||
func: &HirFunction,
|
||||
env: &Environment,
|
||||
used_outside_declaring_scope: &HashSet<DeclarationId>,
|
||||
) -> HashMap<IdentifierId, ReactiveScopeDependency> {
|
||||
let mut temporaries = HashMap::new();
|
||||
used_outside_declaring_scope: &FxHashSet<DeclarationId>,
|
||||
) -> FxHashMap<IdentifierId, ReactiveScopeDependency> {
|
||||
let mut temporaries = FxHashMap::default();
|
||||
collect_temporaries_sidemap_impl(
|
||||
func,
|
||||
env,
|
||||
@@ -269,8 +270,8 @@ fn convert_hoisted_lvalue_kind(kind: InstructionKind) -> Option<InstructionKind>
|
||||
fn collect_temporaries_sidemap_impl(
|
||||
func: &HirFunction,
|
||||
env: &Environment,
|
||||
used_outside_declaring_scope: &HashSet<DeclarationId>,
|
||||
temporaries: &mut HashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
used_outside_declaring_scope: &FxHashSet<DeclarationId>,
|
||||
temporaries: &mut FxHashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
inner_fn_context: Option<EvaluationOrder>,
|
||||
) {
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
@@ -369,7 +370,7 @@ fn get_property(
|
||||
property_name: &PropertyLiteral,
|
||||
optional: bool,
|
||||
loc: Option<react_compiler_hir::SourceLocation>,
|
||||
temporaries: &HashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
temporaries: &FxHashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
_env: &Environment,
|
||||
) -> ReactiveScopeDependency {
|
||||
let resolved = temporaries.get(&object.identifier);
|
||||
@@ -405,9 +406,9 @@ fn get_property(
|
||||
// =============================================================================
|
||||
|
||||
struct OptionalChainSidemap {
|
||||
temporaries_read_in_optional: HashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
processed_instrs_in_optional: HashSet<ProcessedInstr>,
|
||||
hoistable_objects: HashMap<BlockId, ReactiveScopeDependency>,
|
||||
temporaries_read_in_optional: FxHashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
processed_instrs_in_optional: FxHashSet<ProcessedInstr>,
|
||||
hoistable_objects: FxHashMap<BlockId, ReactiveScopeDependency>,
|
||||
}
|
||||
|
||||
/// We track processed instructions/terminals by their lvalue IdentifierId + block id.
|
||||
@@ -423,10 +424,10 @@ enum ProcessedInstr {
|
||||
|
||||
fn collect_optional_chain_sidemap(func: &HirFunction, env: &Environment) -> OptionalChainSidemap {
|
||||
let mut ctx = OptionalTraversalContext {
|
||||
seen_optionals: HashSet::new(),
|
||||
processed_instrs_in_optional: HashSet::new(),
|
||||
temporaries_read_in_optional: HashMap::new(),
|
||||
hoistable_objects: HashMap::new(),
|
||||
seen_optionals: FxHashSet::default(),
|
||||
processed_instrs_in_optional: FxHashSet::default(),
|
||||
temporaries_read_in_optional: FxHashMap::default(),
|
||||
hoistable_objects: FxHashMap::default(),
|
||||
};
|
||||
|
||||
traverse_function_optional(func, env, &mut ctx);
|
||||
@@ -439,10 +440,10 @@ fn collect_optional_chain_sidemap(func: &HirFunction, env: &Environment) -> Opti
|
||||
}
|
||||
|
||||
struct OptionalTraversalContext {
|
||||
seen_optionals: HashSet<BlockId>,
|
||||
processed_instrs_in_optional: HashSet<ProcessedInstr>,
|
||||
temporaries_read_in_optional: HashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
hoistable_objects: HashMap<BlockId, ReactiveScopeDependency>,
|
||||
seen_optionals: FxHashSet<BlockId>,
|
||||
processed_instrs_in_optional: FxHashSet<ProcessedInstr>,
|
||||
temporaries_read_in_optional: FxHashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
hoistable_objects: FxHashMap<BlockId, ReactiveScopeDependency>,
|
||||
}
|
||||
|
||||
fn traverse_function_optional(
|
||||
@@ -785,8 +786,8 @@ fn traverse_optional_block(
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct PropertyPathNode {
|
||||
properties: HashMap<PropertyLiteral, usize>, // index into registry
|
||||
optional_properties: HashMap<PropertyLiteral, usize>, // index into registry
|
||||
properties: FxHashMap<PropertyLiteral, usize>, // index into registry
|
||||
optional_properties: FxHashMap<PropertyLiteral, usize>, // index into registry
|
||||
#[allow(dead_code)]
|
||||
parent: Option<usize>,
|
||||
full_path: ReactiveScopeDependency,
|
||||
@@ -797,14 +798,14 @@ struct PropertyPathNode {
|
||||
|
||||
struct PropertyPathRegistry {
|
||||
nodes: Vec<PropertyPathNode>,
|
||||
roots: HashMap<IdentifierId, usize>,
|
||||
roots: FxHashMap<IdentifierId, usize>,
|
||||
}
|
||||
|
||||
impl PropertyPathRegistry {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
nodes: Vec::new(),
|
||||
roots: HashMap::new(),
|
||||
roots: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -819,8 +820,8 @@ impl PropertyPathRegistry {
|
||||
}
|
||||
let idx = self.nodes.len();
|
||||
self.nodes.push(PropertyPathNode {
|
||||
properties: HashMap::new(),
|
||||
optional_properties: HashMap::new(),
|
||||
properties: FxHashMap::default(),
|
||||
optional_properties: FxHashMap::default(),
|
||||
parent: None,
|
||||
full_path: ReactiveScopeDependency {
|
||||
identifier: identifier_id,
|
||||
@@ -858,8 +859,8 @@ impl PropertyPathRegistry {
|
||||
let mut new_path = parent_full_path.path.clone();
|
||||
new_path.push(entry.clone());
|
||||
self.nodes.push(PropertyPathNode {
|
||||
properties: HashMap::new(),
|
||||
optional_properties: HashMap::new(),
|
||||
properties: FxHashMap::default(),
|
||||
optional_properties: FxHashMap::default(),
|
||||
parent: Some(parent_idx),
|
||||
full_path: ReactiveScopeDependency {
|
||||
identifier: parent_full_path.identifier,
|
||||
@@ -962,11 +963,11 @@ struct BlockInfo {
|
||||
fn collect_hoistable_property_loads(
|
||||
func: &HirFunction,
|
||||
env: &Environment,
|
||||
temporaries: &HashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
hoistable_from_optionals: &HashMap<BlockId, ReactiveScopeDependency>,
|
||||
) -> HashMap<BlockId, BlockInfo> {
|
||||
temporaries: &FxHashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
hoistable_from_optionals: &FxHashMap<BlockId, ReactiveScopeDependency>,
|
||||
) -> FxHashMap<BlockId, BlockInfo> {
|
||||
let mut registry = PropertyPathRegistry::new();
|
||||
let known_immutable_identifiers: HashSet<IdentifierId> = if func.fn_type
|
||||
let known_immutable_identifiers: FxHashSet<IdentifierId> = if func.fn_type
|
||||
== ReactFunctionType::Component
|
||||
|| func.fn_type == ReactFunctionType::Hook
|
||||
{
|
||||
@@ -978,7 +979,7 @@ fn collect_hoistable_property_loads(
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
HashSet::new()
|
||||
FxHashSet::default()
|
||||
};
|
||||
|
||||
let assumed_invoked_fns = get_assumed_invoked_functions(func, env);
|
||||
@@ -994,11 +995,11 @@ fn collect_hoistable_property_loads(
|
||||
}
|
||||
|
||||
struct CollectHoistableContext<'a> {
|
||||
temporaries: &'a HashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
known_immutable_identifiers: &'a HashSet<IdentifierId>,
|
||||
hoistable_from_optionals: &'a HashMap<BlockId, ReactiveScopeDependency>,
|
||||
nested_fn_immutable_context: Option<&'a HashSet<IdentifierId>>,
|
||||
assumed_invoked_fns: &'a HashSet<FunctionId>,
|
||||
temporaries: &'a FxHashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
known_immutable_identifiers: &'a FxHashSet<IdentifierId>,
|
||||
hoistable_from_optionals: &'a FxHashMap<BlockId, ReactiveScopeDependency>,
|
||||
nested_fn_immutable_context: Option<&'a FxHashSet<IdentifierId>>,
|
||||
assumed_invoked_fns: &'a FxHashSet<FunctionId>,
|
||||
}
|
||||
|
||||
fn is_immutable_at_instr(
|
||||
@@ -1027,7 +1028,7 @@ fn in_range(id: EvaluationOrder, range: &MutableRange) -> bool {
|
||||
|
||||
fn get_maybe_non_null_in_instruction(
|
||||
value: &InstructionValue,
|
||||
temporaries: &HashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
temporaries: &FxHashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
) -> Option<ReactiveScopeDependency> {
|
||||
match value {
|
||||
InstructionValue::PropertyLoad { object, .. } => Some(
|
||||
@@ -1057,10 +1058,10 @@ fn collect_hoistable_property_loads_impl(
|
||||
env: &Environment,
|
||||
ctx: &CollectHoistableContext,
|
||||
registry: &mut PropertyPathRegistry,
|
||||
) -> HashMap<BlockId, BlockInfo> {
|
||||
) -> FxHashMap<BlockId, BlockInfo> {
|
||||
let nodes = collect_non_nulls_in_blocks(func, env, ctx, registry);
|
||||
let working = propagate_non_null(func, &nodes, registry);
|
||||
// Return the propagated results, converting HashSet<usize> back to BlockInfo
|
||||
// Return the propagated results, converting FxHashSet<usize> back to BlockInfo
|
||||
working
|
||||
.into_iter()
|
||||
.map(|(k, v)| {
|
||||
@@ -1078,17 +1079,18 @@ fn collect_hoistable_property_loads_impl(
|
||||
/// Returns the set of LoweredFunction FunctionIds that are assumed to be invoked.
|
||||
/// The `temporaries` map is shared across recursive calls (matching TS behavior where
|
||||
/// the same Map is passed to recursive invocations for inner functions).
|
||||
fn get_assumed_invoked_functions(func: &HirFunction, env: &Environment) -> HashSet<FunctionId> {
|
||||
let mut temporaries: HashMap<IdentifierId, (FunctionId, HashSet<FunctionId>)> = HashMap::new();
|
||||
fn get_assumed_invoked_functions(func: &HirFunction, env: &Environment) -> FxHashSet<FunctionId> {
|
||||
let mut temporaries: FxHashMap<IdentifierId, (FunctionId, FxHashSet<FunctionId>)> =
|
||||
FxHashMap::default();
|
||||
get_assumed_invoked_functions_impl(func, env, &mut temporaries)
|
||||
}
|
||||
|
||||
fn get_assumed_invoked_functions_impl(
|
||||
func: &HirFunction,
|
||||
env: &Environment,
|
||||
temporaries: &mut HashMap<IdentifierId, (FunctionId, HashSet<FunctionId>)>,
|
||||
) -> HashSet<FunctionId> {
|
||||
let mut hoistable: HashSet<FunctionId> = HashSet::new();
|
||||
temporaries: &mut FxHashMap<IdentifierId, (FunctionId, FxHashSet<FunctionId>)>,
|
||||
) -> FxHashSet<FunctionId> {
|
||||
let mut hoistable: FxHashSet<FunctionId> = FxHashSet::default();
|
||||
|
||||
// Step 1: Collect identifier to function expression mappings
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
@@ -1096,8 +1098,10 @@ fn get_assumed_invoked_functions_impl(
|
||||
let instr = &func.instructions[instr_id.0 as usize];
|
||||
match &instr.value {
|
||||
InstructionValue::FunctionExpression { lowered_func, .. } => {
|
||||
temporaries
|
||||
.insert(instr.lvalue.identifier, (lowered_func.func, HashSet::new()));
|
||||
temporaries.insert(
|
||||
instr.lvalue.identifier,
|
||||
(lowered_func.func, FxHashSet::default()),
|
||||
);
|
||||
}
|
||||
InstructionValue::StoreLocal {
|
||||
value: val, lvalue, ..
|
||||
@@ -1221,7 +1225,7 @@ fn collect_non_nulls_in_blocks(
|
||||
env: &Environment,
|
||||
ctx: &CollectHoistableContext,
|
||||
registry: &mut PropertyPathRegistry,
|
||||
) -> HashMap<BlockId, BlockInfo> {
|
||||
) -> FxHashMap<BlockId, BlockInfo> {
|
||||
// Known non-null identifiers (e.g. component props)
|
||||
let mut known_non_null: BTreeSet<usize> = BTreeSet::new();
|
||||
if func.fn_type == ReactFunctionType::Component && !func.params.is_empty() {
|
||||
@@ -1231,7 +1235,7 @@ fn collect_non_nulls_in_blocks(
|
||||
}
|
||||
}
|
||||
|
||||
let mut nodes: HashMap<BlockId, BlockInfo> = HashMap::new();
|
||||
let mut nodes: FxHashMap<BlockId, BlockInfo> = FxHashMap::default();
|
||||
|
||||
for (block_id, block) in &func.body.blocks {
|
||||
let mut assumed = known_non_null.clone();
|
||||
@@ -1290,7 +1294,7 @@ fn collect_non_nulls_in_blocks(
|
||||
if ctx.assumed_invoked_fns.contains(&lowered_func.func) {
|
||||
let inner_func = &env.functions[lowered_func.func.0 as usize];
|
||||
// Build nested fn immutable context
|
||||
let nested_fn_immutable_context: HashSet<IdentifierId> =
|
||||
let nested_fn_immutable_context: FxHashSet<IdentifierId> =
|
||||
if ctx.nested_fn_immutable_context.is_some() {
|
||||
// Already in a nested fn context, use existing
|
||||
ctx.nested_fn_immutable_context.unwrap().clone()
|
||||
@@ -1307,7 +1311,7 @@ fn collect_non_nulls_in_blocks(
|
||||
let inner_assumed = get_assumed_invoked_functions(inner_func, env);
|
||||
let inner_ctx = CollectHoistableContext {
|
||||
temporaries: ctx.temporaries,
|
||||
known_immutable_identifiers: &HashSet::new(),
|
||||
known_immutable_identifiers: &FxHashSet::default(),
|
||||
hoistable_from_optionals: ctx.hoistable_from_optionals,
|
||||
nested_fn_immutable_context: Some(&nested_fn_immutable_context),
|
||||
assumed_invoked_fns: &inner_assumed,
|
||||
@@ -1347,13 +1351,13 @@ fn collect_non_nulls_in_blocks(
|
||||
/// and should be filtered out, allowing non-null info to propagate through non-cyclic paths.
|
||||
fn propagate_non_null(
|
||||
func: &HirFunction,
|
||||
nodes: &HashMap<BlockId, BlockInfo>,
|
||||
nodes: &FxHashMap<BlockId, BlockInfo>,
|
||||
registry: &mut PropertyPathRegistry,
|
||||
) -> HashMap<BlockId, BTreeSet<usize>> {
|
||||
) -> FxHashMap<BlockId, BTreeSet<usize>> {
|
||||
// Build successor map. Use BTreeSet to iterate successors in sorted BlockId
|
||||
// order, matching the TS Set<BlockId> insertion order (blocks are created in
|
||||
// ascending BlockId order).
|
||||
let mut block_successors: HashMap<BlockId, BTreeSet<BlockId>> = HashMap::new();
|
||||
let mut block_successors: FxHashMap<BlockId, BTreeSet<BlockId>> = FxHashMap::default();
|
||||
for (block_id, block) in &func.body.blocks {
|
||||
for pred in &block.preds {
|
||||
block_successors.entry(*pred).or_default().insert(*block_id);
|
||||
@@ -1361,7 +1365,7 @@ fn propagate_non_null(
|
||||
}
|
||||
|
||||
// Clone nodes into mutable working set
|
||||
let mut working: HashMap<BlockId, BTreeSet<usize>> = nodes
|
||||
let mut working: FxHashMap<BlockId, BTreeSet<usize>> = nodes
|
||||
.iter()
|
||||
.map(|(k, v)| (*k, v.assumed_non_null_objects.clone()))
|
||||
.collect();
|
||||
@@ -1374,7 +1378,7 @@ fn propagate_non_null(
|
||||
let mut changed = false;
|
||||
|
||||
// Forward pass (using predecessors)
|
||||
let mut traversal_state: HashMap<BlockId, TraversalState> = HashMap::new();
|
||||
let mut traversal_state: FxHashMap<BlockId, TraversalState> = FxHashMap::default();
|
||||
for &block_id in &block_ids {
|
||||
let block_changed = recursively_propagate_non_null(
|
||||
block_id,
|
||||
@@ -1426,10 +1430,10 @@ enum PropagationDirection {
|
||||
fn recursively_propagate_non_null(
|
||||
node_id: BlockId,
|
||||
direction: PropagationDirection,
|
||||
traversal_state: &mut HashMap<BlockId, TraversalState>,
|
||||
working: &mut HashMap<BlockId, BTreeSet<usize>>,
|
||||
traversal_state: &mut FxHashMap<BlockId, TraversalState>,
|
||||
working: &mut FxHashMap<BlockId, BTreeSet<usize>>,
|
||||
func: &HirFunction,
|
||||
block_successors: &HashMap<BlockId, BTreeSet<BlockId>>,
|
||||
block_successors: &FxHashMap<BlockId, BTreeSet<BlockId>>,
|
||||
registry: &mut PropertyPathRegistry,
|
||||
) -> bool {
|
||||
// Avoid re-visiting computed or currently active nodes
|
||||
@@ -1500,12 +1504,12 @@ fn recursively_propagate_non_null(
|
||||
fn collect_hoistable_and_propagate(
|
||||
func: &HirFunction,
|
||||
env: &Environment,
|
||||
temporaries: &HashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
hoistable_from_optionals: &HashMap<BlockId, ReactiveScopeDependency>,
|
||||
) -> (HashMap<BlockId, BTreeSet<usize>>, PropertyPathRegistry) {
|
||||
temporaries: &FxHashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
hoistable_from_optionals: &FxHashMap<BlockId, ReactiveScopeDependency>,
|
||||
) -> (FxHashMap<BlockId, BTreeSet<usize>>, PropertyPathRegistry) {
|
||||
let mut registry = PropertyPathRegistry::new();
|
||||
let assumed_invoked_fns = get_assumed_invoked_functions(func, env);
|
||||
let known_immutable_identifiers: HashSet<IdentifierId> = if func.fn_type
|
||||
let known_immutable_identifiers: FxHashSet<IdentifierId> = if func.fn_type
|
||||
== ReactFunctionType::Component
|
||||
|| func.fn_type == ReactFunctionType::Hook
|
||||
{
|
||||
@@ -1517,7 +1521,7 @@ fn collect_hoistable_and_propagate(
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
HashSet::new()
|
||||
FxHashSet::default()
|
||||
};
|
||||
|
||||
let ctx = CollectHoistableContext {
|
||||
@@ -1538,9 +1542,9 @@ fn collect_hoistable_and_propagate(
|
||||
#[allow(dead_code)]
|
||||
fn key_by_scope_id(
|
||||
func: &HirFunction,
|
||||
block_keyed: &HashMap<BlockId, BlockInfo>,
|
||||
) -> HashMap<ScopeId, BlockInfo> {
|
||||
let mut keyed: HashMap<ScopeId, BlockInfo> = HashMap::new();
|
||||
block_keyed: &FxHashMap<BlockId, BlockInfo>,
|
||||
) -> FxHashMap<ScopeId, BlockInfo> {
|
||||
let mut keyed: FxHashMap<ScopeId, BlockInfo> = FxHashMap::default();
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
if let Terminal::Scope {
|
||||
scope,
|
||||
@@ -1600,7 +1604,7 @@ enum HoistableAccessType {
|
||||
}
|
||||
|
||||
struct HoistableNode {
|
||||
properties: HashMap<PropertyLiteral, Box<HoistableNodeEntry>>,
|
||||
properties: FxHashMap<PropertyLiteral, Box<HoistableNodeEntry>>,
|
||||
access_type: HoistableAccessType,
|
||||
}
|
||||
|
||||
@@ -1609,7 +1613,7 @@ struct HoistableNodeEntry {
|
||||
}
|
||||
|
||||
struct DependencyNode {
|
||||
properties: IndexMap<PropertyLiteral, Box<DependencyNodeEntry>>,
|
||||
properties: IndexMap<PropertyLiteral, Box<DependencyNodeEntry>, FxBuildHasher>,
|
||||
access_type: PropertyAccessType,
|
||||
loc: Option<react_compiler_hir::SourceLocation>,
|
||||
}
|
||||
@@ -1619,8 +1623,8 @@ struct DependencyNodeEntry {
|
||||
}
|
||||
|
||||
struct ReactiveScopeDependencyTreeHIR {
|
||||
hoistable_roots: HashMap<IdentifierId, (HoistableNode, bool)>, // node + reactive
|
||||
dep_roots: IndexMap<IdentifierId, (DependencyNode, bool)>, // node + reactive (preserves insertion order like JS Map)
|
||||
hoistable_roots: FxHashMap<IdentifierId, (HoistableNode, bool)>, // node + reactive
|
||||
dep_roots: IndexMap<IdentifierId, (DependencyNode, bool), FxBuildHasher>, // node + reactive (preserves insertion order like JS Map)
|
||||
}
|
||||
|
||||
impl ReactiveScopeDependencyTreeHIR {
|
||||
@@ -1628,7 +1632,8 @@ impl ReactiveScopeDependencyTreeHIR {
|
||||
hoistable_objects: impl Iterator<Item = &'a ReactiveScopeDependency>,
|
||||
_env: &Environment,
|
||||
) -> Self {
|
||||
let mut hoistable_roots: HashMap<IdentifierId, (HoistableNode, bool)> = HashMap::new();
|
||||
let mut hoistable_roots: FxHashMap<IdentifierId, (HoistableNode, bool)> =
|
||||
FxHashMap::default();
|
||||
|
||||
// Sort hoistable objects so that entries with optional first path come
|
||||
// before non-optional ones. This matches the TS behavior where
|
||||
@@ -1651,7 +1656,7 @@ impl ReactiveScopeDependencyTreeHIR {
|
||||
};
|
||||
(
|
||||
HoistableNode {
|
||||
properties: HashMap::new(),
|
||||
properties: FxHashMap::default(),
|
||||
access_type,
|
||||
},
|
||||
dep.reactive,
|
||||
@@ -1671,7 +1676,7 @@ impl ReactiveScopeDependencyTreeHIR {
|
||||
.or_insert_with(|| {
|
||||
Box::new(HoistableNodeEntry {
|
||||
node: HoistableNode {
|
||||
properties: HashMap::new(),
|
||||
properties: FxHashMap::default(),
|
||||
access_type,
|
||||
},
|
||||
})
|
||||
@@ -1682,7 +1687,7 @@ impl ReactiveScopeDependencyTreeHIR {
|
||||
|
||||
Self {
|
||||
hoistable_roots,
|
||||
dep_roots: IndexMap::new(),
|
||||
dep_roots: IndexMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1690,7 +1695,7 @@ impl ReactiveScopeDependencyTreeHIR {
|
||||
let root = self.dep_roots.entry(dep.identifier).or_insert_with(|| {
|
||||
(
|
||||
DependencyNode {
|
||||
properties: IndexMap::new(),
|
||||
properties: IndexMap::default(),
|
||||
access_type: PropertyAccessType::UnconditionalAccess,
|
||||
loc: dep.loc,
|
||||
},
|
||||
@@ -1735,7 +1740,7 @@ impl ReactiveScopeDependencyTreeHIR {
|
||||
.or_insert_with(|| {
|
||||
Box::new(DependencyNodeEntry {
|
||||
node: DependencyNode {
|
||||
properties: IndexMap::new(),
|
||||
properties: IndexMap::default(),
|
||||
access_type,
|
||||
loc: entry.loc,
|
||||
},
|
||||
@@ -1809,30 +1814,30 @@ struct Decl {
|
||||
|
||||
/// Context for dependency collection.
|
||||
struct DependencyCollectionContext<'a> {
|
||||
declarations: HashMap<DeclarationId, Decl>,
|
||||
reassignments: HashMap<IdentifierId, Decl>,
|
||||
declarations: FxHashMap<DeclarationId, Decl>,
|
||||
reassignments: FxHashMap<IdentifierId, Decl>,
|
||||
scope_stack: Vec<ScopeId>,
|
||||
dep_stack: Vec<Vec<ReactiveScopeDependency>>,
|
||||
deps: IndexMap<ScopeId, Vec<ReactiveScopeDependency>>,
|
||||
temporaries: &'a HashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
deps: IndexMap<ScopeId, Vec<ReactiveScopeDependency>, FxBuildHasher>,
|
||||
temporaries: &'a FxHashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
#[allow(dead_code)]
|
||||
temporaries_used_outside_scope: &'a HashSet<DeclarationId>,
|
||||
processed_instrs_in_optional: &'a HashSet<ProcessedInstr>,
|
||||
temporaries_used_outside_scope: &'a FxHashSet<DeclarationId>,
|
||||
processed_instrs_in_optional: &'a FxHashSet<ProcessedInstr>,
|
||||
inner_fn_context: Option<EvaluationOrder>,
|
||||
}
|
||||
|
||||
impl<'a> DependencyCollectionContext<'a> {
|
||||
fn new(
|
||||
temporaries_used_outside_scope: &'a HashSet<DeclarationId>,
|
||||
temporaries: &'a HashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
processed_instrs_in_optional: &'a HashSet<ProcessedInstr>,
|
||||
temporaries_used_outside_scope: &'a FxHashSet<DeclarationId>,
|
||||
temporaries: &'a FxHashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
processed_instrs_in_optional: &'a FxHashSet<ProcessedInstr>,
|
||||
) -> Self {
|
||||
Self {
|
||||
declarations: HashMap::new(),
|
||||
reassignments: HashMap::new(),
|
||||
declarations: FxHashMap::default(),
|
||||
reassignments: FxHashMap::default(),
|
||||
scope_stack: Vec::new(),
|
||||
dep_stack: Vec::new(),
|
||||
deps: IndexMap::new(),
|
||||
deps: IndexMap::default(),
|
||||
temporaries,
|
||||
temporaries_used_outside_scope,
|
||||
processed_instrs_in_optional,
|
||||
@@ -2222,10 +2227,10 @@ fn handle_instruction(
|
||||
fn collect_dependencies(
|
||||
func: &HirFunction,
|
||||
env: &mut Environment,
|
||||
used_outside_declaring_scope: &HashSet<DeclarationId>,
|
||||
temporaries: &HashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
processed_instrs_in_optional: &HashSet<ProcessedInstr>,
|
||||
) -> IndexMap<ScopeId, Vec<ReactiveScopeDependency>> {
|
||||
used_outside_declaring_scope: &FxHashSet<DeclarationId>,
|
||||
temporaries: &FxHashMap<IdentifierId, ReactiveScopeDependency>,
|
||||
processed_instrs_in_optional: &FxHashSet<ProcessedInstr>,
|
||||
) -> IndexMap<ScopeId, Vec<ReactiveScopeDependency>, FxBuildHasher> {
|
||||
let mut ctx = DependencyCollectionContext::new(
|
||||
used_outside_declaring_scope,
|
||||
temporaries,
|
||||
|
||||
@@ -8,4 +8,5 @@ react_compiler_ast = { path = "../react_compiler_ast" }
|
||||
react_compiler_hir = { path = "../react_compiler_hir" }
|
||||
react_compiler_diagnostics = { path = "../react_compiler_diagnostics" }
|
||||
indexmap = "2"
|
||||
rustc-hash = "2"
|
||||
serde_json = "1"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::{FxBuildHasher, FxHashSet};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use indexmap::IndexSet;
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use react_compiler_ast::scope::BindingId;
|
||||
use react_compiler_ast::scope::BindingKind as AstBindingKind;
|
||||
use react_compiler_ast::scope::ScopeId;
|
||||
@@ -2531,7 +2530,7 @@ fn collect_binding_names_from_pattern(
|
||||
pattern: &react_compiler_ast::patterns::PatternLike,
|
||||
scope_id: react_compiler_ast::scope::ScopeId,
|
||||
scope_info: &ScopeInfo,
|
||||
out: &mut HashSet<BindingId>,
|
||||
out: &mut FxHashSet<BindingId>,
|
||||
) {
|
||||
use react_compiler_ast::patterns::PatternLike;
|
||||
match pattern {
|
||||
@@ -2712,7 +2711,7 @@ fn lower_block_statement_inner(
|
||||
}
|
||||
|
||||
// Track which bindings have been "declared" (their declaration statement has been seen)
|
||||
let mut declared: HashSet<BindingId> = HashSet::new();
|
||||
let mut declared: FxHashSet<BindingId> = FxHashSet::default();
|
||||
|
||||
for body_stmt in &block.body {
|
||||
let stmt_start = statement_start(body_stmt).unwrap_or(0);
|
||||
@@ -4320,8 +4319,11 @@ pub fn lower(
|
||||
let context_identifiers = find_context_identifiers(func, scope_info, env, &identifier_locs)?;
|
||||
|
||||
// For top-level functions, context is empty (no captured refs)
|
||||
let context_map: IndexMap<react_compiler_ast::scope::BindingId, Option<SourceLocation>> =
|
||||
IndexMap::new();
|
||||
let context_map: IndexMap<
|
||||
react_compiler_ast::scope::BindingId,
|
||||
Option<SourceLocation>,
|
||||
FxBuildHasher,
|
||||
> = IndexMap::default();
|
||||
|
||||
let (hir_func, _used_names, _child_bindings) = lower_inner(
|
||||
params,
|
||||
@@ -5592,7 +5594,7 @@ fn lower_function(
|
||||
} else {
|
||||
let parent = builder.function_scope();
|
||||
let scope_info = builder.scope_info();
|
||||
let mapped: std::collections::HashSet<react_compiler_ast::scope::ScopeId> =
|
||||
let mapped: rustc_hash::FxHashSet<react_compiler_ast::scope::ScopeId> =
|
||||
scope_info.node_id_to_scope.values().copied().collect();
|
||||
let param_names: Vec<String> = params
|
||||
.iter()
|
||||
@@ -5604,7 +5606,7 @@ fn lower_function(
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let mut descendants = std::collections::HashSet::new();
|
||||
let mut descendants = rustc_hash::FxHashSet::default();
|
||||
descendants.insert(parent);
|
||||
let mut changed = true;
|
||||
while changed {
|
||||
@@ -5671,7 +5673,11 @@ fn lower_function(
|
||||
ident_locs,
|
||||
ref_override.as_ref(),
|
||||
);
|
||||
let merged_context: IndexMap<react_compiler_ast::scope::BindingId, Option<SourceLocation>> = {
|
||||
let merged_context: IndexMap<
|
||||
react_compiler_ast::scope::BindingId,
|
||||
Option<SourceLocation>,
|
||||
FxBuildHasher,
|
||||
> = {
|
||||
let parent_context = builder.context().clone();
|
||||
let mut merged = parent_context;
|
||||
for (k, v) in captured_context {
|
||||
@@ -5743,7 +5749,11 @@ fn lower_function_declaration(
|
||||
ident_locs,
|
||||
None,
|
||||
);
|
||||
let merged_context: IndexMap<react_compiler_ast::scope::BindingId, Option<SourceLocation>> = {
|
||||
let merged_context: IndexMap<
|
||||
react_compiler_ast::scope::BindingId,
|
||||
Option<SourceLocation>,
|
||||
FxBuildHasher,
|
||||
> = {
|
||||
let parent_context = builder.context().clone();
|
||||
let mut merged = parent_context;
|
||||
for (k, v) in captured_context {
|
||||
@@ -5944,7 +5954,11 @@ fn lower_function_for_object_method(
|
||||
ident_locs,
|
||||
None,
|
||||
);
|
||||
let merged_context: IndexMap<react_compiler_ast::scope::BindingId, Option<SourceLocation>> = {
|
||||
let merged_context: IndexMap<
|
||||
react_compiler_ast::scope::BindingId,
|
||||
Option<SourceLocation>,
|
||||
FxBuildHasher,
|
||||
> = {
|
||||
let parent_context = builder.context().clone();
|
||||
let mut merged = parent_context;
|
||||
for (k, v) in captured_context {
|
||||
@@ -5991,19 +6005,27 @@ fn lower_inner(
|
||||
loc: Option<SourceLocation>,
|
||||
scope_info: &ScopeInfo,
|
||||
env: &mut Environment,
|
||||
parent_bindings: Option<IndexMap<react_compiler_ast::scope::BindingId, IdentifierId>>,
|
||||
parent_used_names: Option<IndexMap<String, react_compiler_ast::scope::BindingId>>,
|
||||
context_map: IndexMap<react_compiler_ast::scope::BindingId, Option<SourceLocation>>,
|
||||
parent_bindings: Option<
|
||||
IndexMap<react_compiler_ast::scope::BindingId, IdentifierId, FxBuildHasher>,
|
||||
>,
|
||||
parent_used_names: Option<
|
||||
IndexMap<String, react_compiler_ast::scope::BindingId, FxBuildHasher>,
|
||||
>,
|
||||
context_map: IndexMap<
|
||||
react_compiler_ast::scope::BindingId,
|
||||
Option<SourceLocation>,
|
||||
FxBuildHasher,
|
||||
>,
|
||||
function_scope: react_compiler_ast::scope::ScopeId,
|
||||
component_scope: react_compiler_ast::scope::ScopeId,
|
||||
context_identifiers: &HashSet<react_compiler_ast::scope::BindingId>,
|
||||
context_identifiers: &FxHashSet<react_compiler_ast::scope::BindingId>,
|
||||
is_top_level: bool,
|
||||
identifier_locs: &IdentifierLocIndex,
|
||||
) -> Result<
|
||||
(
|
||||
HirFunction,
|
||||
IndexMap<String, react_compiler_ast::scope::BindingId>,
|
||||
IndexMap<react_compiler_ast::scope::BindingId, IdentifierId>,
|
||||
IndexMap<String, react_compiler_ast::scope::BindingId, FxBuildHasher>,
|
||||
IndexMap<react_compiler_ast::scope::BindingId, IdentifierId, FxBuildHasher>,
|
||||
),
|
||||
CompilerError,
|
||||
> {
|
||||
@@ -6776,22 +6798,22 @@ fn gather_captured_context(
|
||||
func_start: u32,
|
||||
func_end: u32,
|
||||
identifier_locs: &IdentifierLocIndex,
|
||||
ref_node_ids_override: Option<&IndexSet<u32>>,
|
||||
) -> IndexMap<react_compiler_ast::scope::BindingId, Option<SourceLocation>> {
|
||||
ref_node_ids_override: Option<&IndexSet<u32, FxBuildHasher>>,
|
||||
) -> IndexMap<react_compiler_ast::scope::BindingId, Option<SourceLocation>, FxBuildHasher> {
|
||||
let parent_scope = scope_info.scopes[function_scope.0 as usize].parent;
|
||||
let pure_scopes = match parent_scope {
|
||||
Some(parent) => capture_scopes(scope_info, parent, component_scope),
|
||||
None => IndexSet::new(),
|
||||
None => IndexSet::default(),
|
||||
};
|
||||
|
||||
// Collect the earliest (lowest source position) reference location for each
|
||||
// captured binding. Using the minimum position makes the result independent of
|
||||
// ref_node_id_to_binding iteration order, matching the behavior the TS compiler
|
||||
// gets from Babel's position-ordered traversal.
|
||||
let mut captured: std::collections::HashMap<
|
||||
let mut captured: rustc_hash::FxHashMap<
|
||||
react_compiler_ast::scope::BindingId,
|
||||
(u32, Option<SourceLocation>), // (min_position, loc)
|
||||
> = std::collections::HashMap::new();
|
||||
> = rustc_hash::FxHashMap::default();
|
||||
|
||||
for (&ref_nid, &binding_id) in &scope_info.ref_node_id_to_binding {
|
||||
if let Some(allowed) = ref_node_ids_override {
|
||||
@@ -6878,8 +6900,8 @@ fn capture_scopes(
|
||||
scope_info: &ScopeInfo,
|
||||
from: react_compiler_ast::scope::ScopeId,
|
||||
to: react_compiler_ast::scope::ScopeId,
|
||||
) -> IndexSet<react_compiler_ast::scope::ScopeId> {
|
||||
let mut result = IndexSet::new();
|
||||
) -> IndexSet<react_compiler_ast::scope::ScopeId, FxBuildHasher> {
|
||||
let mut result = IndexSet::default();
|
||||
let mut current = Some(from);
|
||||
while let Some(scope_id) = current {
|
||||
result.insert(scope_id);
|
||||
@@ -7118,8 +7140,8 @@ fn collect_fbt_sub_tags_from_stmts(
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_identifier_node_ids_from_body(body: &FunctionBody) -> IndexSet<u32> {
|
||||
let mut positions = IndexSet::new();
|
||||
fn collect_identifier_node_ids_from_body(body: &FunctionBody) -> IndexSet<u32, FxBuildHasher> {
|
||||
let mut positions = IndexSet::default();
|
||||
match body {
|
||||
FunctionBody::Block(block) => {
|
||||
for stmt in &block.body {
|
||||
@@ -7135,7 +7157,7 @@ fn collect_identifier_node_ids_from_body(body: &FunctionBody) -> IndexSet<u32> {
|
||||
|
||||
fn collect_identifier_node_ids_from_stmt(
|
||||
stmt: &react_compiler_ast::statements::Statement,
|
||||
positions: &mut IndexSet<u32>,
|
||||
positions: &mut IndexSet<u32, FxBuildHasher>,
|
||||
) {
|
||||
use react_compiler_ast::statements::Statement;
|
||||
match stmt {
|
||||
@@ -7175,7 +7197,7 @@ fn collect_identifier_node_ids_from_stmt(
|
||||
|
||||
fn collect_identifier_node_ids_from_expr(
|
||||
expr: &react_compiler_ast::expressions::Expression,
|
||||
positions: &mut IndexSet<u32>,
|
||||
positions: &mut IndexSet<u32, FxBuildHasher>,
|
||||
) {
|
||||
use react_compiler_ast::expressions::Expression;
|
||||
match expr {
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
//! walking the AST with scope tracking to find variables that cross
|
||||
//! function boundaries.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_ast::expressions::*;
|
||||
use react_compiler_ast::patterns::*;
|
||||
@@ -35,7 +34,7 @@ struct ContextIdentifierVisitor<'a> {
|
||||
/// Stack of inner function scopes encountered during traversal.
|
||||
/// Empty when at the top level of the function being compiled.
|
||||
function_stack: Vec<ScopeId>,
|
||||
binding_info: HashMap<BindingId, BindingInfo>,
|
||||
binding_info: FxHashMap<BindingId, BindingInfo>,
|
||||
error: Option<CompilerError>,
|
||||
}
|
||||
|
||||
@@ -313,8 +312,8 @@ fn is_captured_by_function(
|
||||
/// ref_node_id_to_binding. These are entries where the reference's node_id
|
||||
/// matches the binding's declaration_node_id — i.e., the "reference" is
|
||||
/// actually the declaration itself.
|
||||
fn build_declaration_node_ids(scope_info: &ScopeInfo) -> HashSet<(BindingId, u32)> {
|
||||
let mut result = HashSet::new();
|
||||
fn build_declaration_node_ids(scope_info: &ScopeInfo) -> FxHashSet<(BindingId, u32)> {
|
||||
let mut result = FxHashSet::default();
|
||||
for (&ref_nid, &binding_id) in &scope_info.ref_node_id_to_binding {
|
||||
let binding = &scope_info.bindings[binding_id.0 as usize];
|
||||
if binding.declaration_node_id == Some(ref_nid) {
|
||||
@@ -338,7 +337,7 @@ pub fn find_context_identifiers(
|
||||
scope_info: &ScopeInfo,
|
||||
env: &mut Environment,
|
||||
identifier_locs: &crate::identifier_loc_index::IdentifierLocIndex,
|
||||
) -> Result<HashSet<BindingId>, CompilerError> {
|
||||
) -> Result<FxHashSet<BindingId>, CompilerError> {
|
||||
let func_scope = scope_info
|
||||
.resolve_scope_for_node(func.node_id())
|
||||
.unwrap_or(scope_info.program_scope);
|
||||
@@ -347,7 +346,7 @@ pub fn find_context_identifiers(
|
||||
scope_info,
|
||||
env,
|
||||
function_stack: Vec::new(),
|
||||
binding_info: HashMap::new(),
|
||||
binding_info: FxHashMap::default(),
|
||||
error: None,
|
||||
};
|
||||
let mut walker = AstWalker::with_initial_scope(scope_info, func_scope);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use indexmap::IndexMap;
|
||||
use indexmap::IndexSet;
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use react_compiler_ast::scope::BindingId;
|
||||
use react_compiler_ast::scope::ImportBindingKind;
|
||||
use react_compiler_ast::scope::ScopeId;
|
||||
@@ -13,6 +12,7 @@ use react_compiler_hir::environment::Environment;
|
||||
use react_compiler_hir::visitors::each_terminal_successor;
|
||||
use react_compiler_hir::visitors::terminal_fallthrough;
|
||||
use react_compiler_hir::*;
|
||||
use rustc_hash::FxBuildHasher;
|
||||
|
||||
use crate::identifier_loc_index::IdentifierLocIndex;
|
||||
|
||||
@@ -139,18 +139,18 @@ fn new_block(id: BlockId, kind: BlockKind) -> WipBlock {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
pub struct HirBuilder<'a> {
|
||||
completed: IndexMap<BlockId, BasicBlock>,
|
||||
completed: IndexMap<BlockId, BasicBlock, FxBuildHasher>,
|
||||
current: WipBlock,
|
||||
entry: BlockId,
|
||||
scopes: Vec<Scope>,
|
||||
/// Context identifiers: variables captured from an outer scope.
|
||||
/// Maps the outer scope's BindingId to the source location where it was referenced.
|
||||
context: IndexMap<BindingId, Option<SourceLocation>>,
|
||||
context: IndexMap<BindingId, Option<SourceLocation>, FxBuildHasher>,
|
||||
/// Resolved bindings: maps a BindingId to the HIR IdentifierId created for it.
|
||||
bindings: IndexMap<BindingId, IdentifierId>,
|
||||
bindings: IndexMap<BindingId, IdentifierId, FxBuildHasher>,
|
||||
/// Names already used by bindings, for collision avoidance.
|
||||
/// Maps name string -> how many times it has been used (for appending _0, _1, ...).
|
||||
used_names: IndexMap<String, BindingId>,
|
||||
used_names: IndexMap<String, BindingId, FxBuildHasher>,
|
||||
env: &'a mut Environment,
|
||||
scope_info: &'a ScopeInfo,
|
||||
exception_handler_stack: Vec<BlockId>,
|
||||
@@ -166,10 +166,10 @@ pub struct HirBuilder<'a> {
|
||||
/// Set of BindingIds for variables declared in scopes between component_scope
|
||||
/// and any inner function scope, that are referenced from an inner function scope.
|
||||
/// These need StoreContext/LoadContext instead of StoreLocal/LoadLocal.
|
||||
context_identifiers: std::collections::HashSet<BindingId>,
|
||||
context_identifiers: rustc_hash::FxHashSet<BindingId>,
|
||||
/// Set of ScopeIds that have been matched to synthetic blocks/functions.
|
||||
/// Prevents the same scope from being reused for different synthetic nodes.
|
||||
claimed_synthetic_scopes: std::collections::HashSet<ScopeId>,
|
||||
claimed_synthetic_scopes: rustc_hash::FxHashSet<ScopeId>,
|
||||
/// Index mapping identifier byte offsets to source locations and JSX status.
|
||||
identifier_locs: &'a IdentifierLocIndex,
|
||||
}
|
||||
@@ -192,17 +192,17 @@ impl<'a> HirBuilder<'a> {
|
||||
scope_info: &'a ScopeInfo,
|
||||
function_scope: ScopeId,
|
||||
component_scope: ScopeId,
|
||||
context_identifiers: std::collections::HashSet<BindingId>,
|
||||
bindings: Option<IndexMap<BindingId, IdentifierId>>,
|
||||
context: Option<IndexMap<BindingId, Option<SourceLocation>>>,
|
||||
context_identifiers: rustc_hash::FxHashSet<BindingId>,
|
||||
bindings: Option<IndexMap<BindingId, IdentifierId, FxBuildHasher>>,
|
||||
context: Option<IndexMap<BindingId, Option<SourceLocation>, FxBuildHasher>>,
|
||||
entry_block_kind: Option<BlockKind>,
|
||||
used_names: Option<IndexMap<String, BindingId>>,
|
||||
used_names: Option<IndexMap<String, BindingId, FxBuildHasher>>,
|
||||
identifier_locs: &'a IdentifierLocIndex,
|
||||
) -> Self {
|
||||
let entry = env.next_block_id();
|
||||
let kind = entry_block_kind.unwrap_or(BlockKind::Block);
|
||||
HirBuilder {
|
||||
completed: IndexMap::new(),
|
||||
completed: IndexMap::default(),
|
||||
current: new_block(entry, kind),
|
||||
entry,
|
||||
scopes: Vec::new(),
|
||||
@@ -217,7 +217,7 @@ impl<'a> HirBuilder<'a> {
|
||||
function_scope,
|
||||
component_scope,
|
||||
context_identifiers,
|
||||
claimed_synthetic_scopes: std::collections::HashSet::new(),
|
||||
claimed_synthetic_scopes: rustc_hash::FxHashSet::default(),
|
||||
identifier_locs,
|
||||
}
|
||||
}
|
||||
@@ -290,12 +290,12 @@ impl<'a> HirBuilder<'a> {
|
||||
}
|
||||
|
||||
/// Access the context map.
|
||||
pub fn context(&self) -> &IndexMap<BindingId, Option<SourceLocation>> {
|
||||
pub fn context(&self) -> &IndexMap<BindingId, Option<SourceLocation>, FxBuildHasher> {
|
||||
&self.context
|
||||
}
|
||||
|
||||
/// Access the pre-computed context identifiers set.
|
||||
pub fn context_identifiers(&self) -> &std::collections::HashSet<BindingId> {
|
||||
pub fn context_identifiers(&self) -> &rustc_hash::FxHashSet<BindingId> {
|
||||
&self.context_identifiers
|
||||
}
|
||||
|
||||
@@ -326,18 +326,21 @@ impl<'a> HirBuilder<'a> {
|
||||
}
|
||||
|
||||
/// Access the bindings map.
|
||||
pub fn bindings(&self) -> &IndexMap<BindingId, IdentifierId> {
|
||||
pub fn bindings(&self) -> &IndexMap<BindingId, IdentifierId, FxBuildHasher> {
|
||||
&self.bindings
|
||||
}
|
||||
|
||||
/// Access the used names map.
|
||||
pub fn used_names(&self) -> &IndexMap<String, BindingId> {
|
||||
pub fn used_names(&self) -> &IndexMap<String, BindingId, FxBuildHasher> {
|
||||
&self.used_names
|
||||
}
|
||||
|
||||
/// Merge used names from a child builder back into this builder.
|
||||
/// This ensures name deduplication works across function scopes.
|
||||
pub fn merge_used_names(&mut self, child_used_names: IndexMap<String, BindingId>) {
|
||||
pub fn merge_used_names(
|
||||
&mut self,
|
||||
child_used_names: IndexMap<String, BindingId, FxBuildHasher>,
|
||||
) {
|
||||
for (name, binding_id) in child_used_names {
|
||||
self.used_names.entry(name).or_insert(binding_id);
|
||||
}
|
||||
@@ -346,7 +349,10 @@ impl<'a> HirBuilder<'a> {
|
||||
/// Merge bindings (binding_id -> IdentifierId) from a child builder back into this builder.
|
||||
/// This matches TS behavior where parent and child share the same #bindings map by reference,
|
||||
/// so bindings resolved by the child are automatically visible to the parent.
|
||||
pub fn merge_bindings(&mut self, child_bindings: IndexMap<BindingId, IdentifierId>) {
|
||||
pub fn merge_bindings(
|
||||
&mut self,
|
||||
child_bindings: IndexMap<BindingId, IdentifierId, FxBuildHasher>,
|
||||
) {
|
||||
for (binding_id, identifier_id) in child_bindings {
|
||||
self.bindings.entry(binding_id).or_insert(identifier_id);
|
||||
}
|
||||
@@ -403,7 +409,7 @@ impl<'a> HirBuilder<'a> {
|
||||
id: block_id,
|
||||
instructions: wip.instructions,
|
||||
terminal,
|
||||
preds: IndexSet::new(),
|
||||
preds: IndexSet::default(),
|
||||
phis: Vec::new(),
|
||||
},
|
||||
);
|
||||
@@ -427,7 +433,7 @@ impl<'a> HirBuilder<'a> {
|
||||
id: block_id,
|
||||
instructions: wip.instructions,
|
||||
terminal,
|
||||
preds: IndexSet::new(),
|
||||
preds: IndexSet::default(),
|
||||
phis: Vec::new(),
|
||||
},
|
||||
);
|
||||
@@ -451,7 +457,7 @@ impl<'a> HirBuilder<'a> {
|
||||
id: block_id,
|
||||
instructions: block.instructions,
|
||||
terminal,
|
||||
preds: IndexSet::new(),
|
||||
preds: IndexSet::default(),
|
||||
phis: Vec::new(),
|
||||
},
|
||||
);
|
||||
@@ -471,7 +477,7 @@ impl<'a> HirBuilder<'a> {
|
||||
id: completed_wip.id,
|
||||
instructions: completed_wip.instructions,
|
||||
terminal,
|
||||
preds: IndexSet::new(),
|
||||
preds: IndexSet::default(),
|
||||
phis: Vec::new(),
|
||||
},
|
||||
);
|
||||
@@ -493,7 +499,7 @@ impl<'a> HirBuilder<'a> {
|
||||
id: completed_wip.id,
|
||||
instructions: completed_wip.instructions,
|
||||
terminal,
|
||||
preds: IndexSet::new(),
|
||||
preds: IndexSet::default(),
|
||||
phis: Vec::new(),
|
||||
},
|
||||
);
|
||||
@@ -769,8 +775,8 @@ impl<'a> HirBuilder<'a> {
|
||||
(
|
||||
HIR,
|
||||
Vec<Instruction>,
|
||||
IndexMap<String, BindingId>,
|
||||
IndexMap<BindingId, IdentifierId>,
|
||||
IndexMap<String, BindingId, FxBuildHasher>,
|
||||
IndexMap<BindingId, IdentifierId, FxBuildHasher>,
|
||||
),
|
||||
CompilerError,
|
||||
> {
|
||||
@@ -1150,19 +1156,19 @@ impl<'a> HirBuilder<'a> {
|
||||
pub fn get_reverse_postordered_blocks(
|
||||
hir: &HIR,
|
||||
_instructions: &[Instruction],
|
||||
) -> IndexMap<BlockId, BasicBlock> {
|
||||
let mut visited: IndexSet<BlockId> = IndexSet::new();
|
||||
let mut used: IndexSet<BlockId> = IndexSet::new();
|
||||
let mut used_fallthroughs: IndexSet<BlockId> = IndexSet::new();
|
||||
) -> IndexMap<BlockId, BasicBlock, FxBuildHasher> {
|
||||
let mut visited: IndexSet<BlockId, FxBuildHasher> = IndexSet::default();
|
||||
let mut used: IndexSet<BlockId, FxBuildHasher> = IndexSet::default();
|
||||
let mut used_fallthroughs: IndexSet<BlockId, FxBuildHasher> = IndexSet::default();
|
||||
let mut postorder: Vec<BlockId> = Vec::new();
|
||||
|
||||
fn visit(
|
||||
hir: &HIR,
|
||||
block_id: BlockId,
|
||||
is_used: bool,
|
||||
visited: &mut IndexSet<BlockId>,
|
||||
used: &mut IndexSet<BlockId>,
|
||||
used_fallthroughs: &mut IndexSet<BlockId>,
|
||||
visited: &mut IndexSet<BlockId, FxBuildHasher>,
|
||||
used: &mut IndexSet<BlockId, FxBuildHasher>,
|
||||
used_fallthroughs: &mut IndexSet<BlockId, FxBuildHasher>,
|
||||
postorder: &mut Vec<BlockId>,
|
||||
) {
|
||||
let was_used = used.contains(&block_id);
|
||||
@@ -1222,7 +1228,7 @@ pub fn get_reverse_postordered_blocks(
|
||||
&mut postorder,
|
||||
);
|
||||
|
||||
let mut blocks = IndexMap::new();
|
||||
let mut blocks = IndexMap::default();
|
||||
for block_id in postorder.into_iter().rev() {
|
||||
let block = hir.blocks.get(&block_id).unwrap();
|
||||
if used.contains(&block_id) {
|
||||
@@ -1252,7 +1258,7 @@ pub fn get_reverse_postordered_blocks(
|
||||
/// For each block with a `For` terminal whose update block is not in the
|
||||
/// blocks map, set update to None.
|
||||
pub fn remove_unreachable_for_updates(hir: &mut HIR) {
|
||||
let block_ids: IndexSet<BlockId> = hir.blocks.keys().copied().collect();
|
||||
let block_ids: IndexSet<BlockId, FxBuildHasher> = hir.blocks.keys().copied().collect();
|
||||
for block in hir.blocks.values_mut() {
|
||||
if let Terminal::For { update, .. } = &mut block.terminal {
|
||||
if let Some(update_id) = *update {
|
||||
@@ -1267,7 +1273,7 @@ pub fn remove_unreachable_for_updates(hir: &mut HIR) {
|
||||
/// For each block with a `DoWhile` terminal whose test block is not in
|
||||
/// the blocks map, replace the terminal with a Goto to the loop block.
|
||||
pub fn remove_dead_do_while_statements(hir: &mut HIR) {
|
||||
let block_ids: IndexSet<BlockId> = hir.blocks.keys().copied().collect();
|
||||
let block_ids: IndexSet<BlockId, FxBuildHasher> = hir.blocks.keys().copied().collect();
|
||||
for block in hir.blocks.values_mut() {
|
||||
let should_replace = if let Terminal::DoWhile { test, .. } = &block.terminal {
|
||||
!block_ids.contains(test)
|
||||
@@ -1304,7 +1310,7 @@ pub fn remove_dead_do_while_statements(hir: &mut HIR) {
|
||||
/// Also cleans up the fallthrough block's predecessors if the handler
|
||||
/// was the only path to it.
|
||||
pub fn remove_unnecessary_try_catch(hir: &mut HIR) {
|
||||
let block_ids: IndexSet<BlockId> = hir.blocks.keys().copied().collect();
|
||||
let block_ids: IndexSet<BlockId, FxBuildHasher> = hir.blocks.keys().copied().collect();
|
||||
|
||||
// Collect the blocks that need replacement and their associated data
|
||||
let replacements: Vec<(BlockId, BlockId, BlockId, BlockId, Option<SourceLocation>)> = hir
|
||||
@@ -1376,13 +1382,13 @@ pub fn mark_predecessors(hir: &mut HIR) {
|
||||
block.preds.clear();
|
||||
}
|
||||
|
||||
let mut visited: IndexSet<BlockId> = IndexSet::new();
|
||||
let mut visited: IndexSet<BlockId, FxBuildHasher> = IndexSet::default();
|
||||
|
||||
fn visit(
|
||||
hir: &mut HIR,
|
||||
block_id: BlockId,
|
||||
prev_block_id: Option<BlockId>,
|
||||
visited: &mut IndexSet<BlockId>,
|
||||
visited: &mut IndexSet<BlockId, FxBuildHasher>,
|
||||
) {
|
||||
// Add predecessor
|
||||
if let Some(prev_id) = prev_block_id {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//! lookups; each entry also stores `start` (byte offset) for range-containment
|
||||
//! checks in `gather_captured_context`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use react_compiler_ast::expressions::*;
|
||||
use react_compiler_ast::jsx::JSXIdentifier;
|
||||
@@ -45,7 +45,7 @@ pub struct IdentifierLocEntry {
|
||||
|
||||
/// Index mapping node_id → IdentifierLocEntry for all Identifier
|
||||
/// and JSXIdentifier nodes in a function's AST.
|
||||
pub type IdentifierLocIndex = HashMap<u32, IdentifierLocEntry>;
|
||||
pub type IdentifierLocIndex = FxHashMap<u32, IdentifierLocEntry>;
|
||||
|
||||
struct IdentifierLocVisitor {
|
||||
index: IdentifierLocIndex,
|
||||
@@ -268,7 +268,7 @@ pub fn build_identifier_loc_index(
|
||||
.unwrap_or(scope_info.program_scope);
|
||||
|
||||
let mut visitor = IdentifierLocVisitor {
|
||||
index: HashMap::new(),
|
||||
index: FxHashMap::default(),
|
||||
current_opening_element_loc: None,
|
||||
};
|
||||
let mut walker = AstWalker::with_initial_scope(scope_info, func_scope);
|
||||
|
||||
@@ -9,3 +9,4 @@ react_compiler_hir = { path = "../react_compiler_hir" }
|
||||
react_compiler_lowering = { path = "../react_compiler_lowering" }
|
||||
react_compiler_ssa = { path = "../react_compiler_ssa" }
|
||||
indexmap = "2"
|
||||
rustc-hash = "2"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
//!
|
||||
//! Analogous to TS `Optimization/ConstantPropagation.ts`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use react_compiler_diagnostics::JsString;
|
||||
use react_compiler_hir::environment::Environment;
|
||||
@@ -68,16 +68,16 @@ impl Constant {
|
||||
}
|
||||
}
|
||||
|
||||
/// Map of known constant values. Uses HashMap (not IndexMap) since iteration
|
||||
/// Map of known constant values. Uses FxHashMap (not IndexMap) since iteration
|
||||
/// order does not affect correctness — this map is only used for lookups.
|
||||
type Constants = HashMap<IdentifierId, Constant>;
|
||||
type Constants = FxHashMap<IdentifierId, Constant>;
|
||||
|
||||
// =============================================================================
|
||||
// Public entry point
|
||||
// =============================================================================
|
||||
|
||||
pub fn constant_propagation(func: &mut HirFunction, env: &mut Environment) {
|
||||
let mut constants: Constants = HashMap::new();
|
||||
let mut constants: Constants = FxHashMap::default();
|
||||
constant_propagation_impl(func, env, &mut constants);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
//!
|
||||
//! Ported from TypeScript `src/Optimization/DeadCodeElimination.ts`.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use react_compiler_hir::environment::{Environment, OutputMode};
|
||||
use react_compiler_hir::object_shape::HookKind;
|
||||
@@ -69,16 +69,16 @@ pub fn dead_code_elimination(func: &mut HirFunction, env: &Environment) {
|
||||
/// State for tracking referenced identifiers during mark phase.
|
||||
struct State {
|
||||
/// SSA-specific usages (by IdentifierId)
|
||||
identifiers: HashSet<IdentifierId>,
|
||||
identifiers: FxHashSet<IdentifierId>,
|
||||
/// Named variable usages (any version)
|
||||
named: HashSet<String>,
|
||||
named: FxHashSet<String>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
fn new() -> Self {
|
||||
State {
|
||||
identifiers: HashSet::new(),
|
||||
named: HashSet::new(),
|
||||
identifiers: FxHashSet::default(),
|
||||
named: FxHashSet::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,7 +409,7 @@ fn pruneable_value(value: &InstructionValue, state: &State, env: &Environment) -
|
||||
|
||||
/// Check if the CFG has any back edges (indicating loops).
|
||||
fn has_back_edge(func: &HirFunction) -> bool {
|
||||
let mut visited: HashSet<BlockId> = HashSet::new();
|
||||
let mut visited: FxHashSet<BlockId> = FxHashSet::default();
|
||||
for (block_id, block) in &func.body.blocks {
|
||||
for pred_id in &block.preds {
|
||||
if !visited.contains(pred_id) {
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
//!
|
||||
//! Analogous to TS `Inference/DropManualMemoization.ts`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_diagnostics::CompilerDiagnostic;
|
||||
use react_compiler_diagnostics::CompilerDiagnosticDetail;
|
||||
@@ -58,17 +57,17 @@ struct ManualMemoCallee {
|
||||
|
||||
struct IdentifierSidemap {
|
||||
/// Maps identifier id -> InstructionId of FunctionExpression instructions
|
||||
functions: HashSet<IdentifierId>,
|
||||
functions: FxHashSet<IdentifierId>,
|
||||
/// Maps identifier id -> ManualMemoCallee for useMemo/useCallback callees
|
||||
manual_memos: HashMap<IdentifierId, ManualMemoCallee>,
|
||||
manual_memos: FxHashMap<IdentifierId, ManualMemoCallee>,
|
||||
/// Set of identifier ids that loaded 'React' global
|
||||
react: HashSet<IdentifierId>,
|
||||
react: FxHashSet<IdentifierId>,
|
||||
/// Maps identifier id -> deps list info for array expressions
|
||||
maybe_deps_lists: HashMap<IdentifierId, MaybeDepsListInfo>,
|
||||
maybe_deps_lists: FxHashMap<IdentifierId, MaybeDepsListInfo>,
|
||||
/// Maps identifier id -> ManualMemoDependency for dependency tracking
|
||||
maybe_deps: HashMap<IdentifierId, ManualMemoDependency>,
|
||||
maybe_deps: FxHashMap<IdentifierId, ManualMemoDependency>,
|
||||
/// Set of identifier ids that are results of optional chains
|
||||
optionals: HashSet<IdentifierId>,
|
||||
optionals: FxHashSet<IdentifierId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -99,11 +98,11 @@ pub fn drop_manual_memoization(
|
||||
|
||||
let optionals = find_optional_places(func)?;
|
||||
let mut sidemap = IdentifierSidemap {
|
||||
functions: HashSet::new(),
|
||||
manual_memos: HashMap::new(),
|
||||
react: HashSet::new(),
|
||||
maybe_deps: HashMap::new(),
|
||||
maybe_deps_lists: HashMap::new(),
|
||||
functions: FxHashSet::default(),
|
||||
manual_memos: FxHashMap::default(),
|
||||
react: FxHashSet::default(),
|
||||
maybe_deps: FxHashMap::default(),
|
||||
maybe_deps_lists: FxHashMap::default(),
|
||||
optionals,
|
||||
};
|
||||
let mut next_manual_memo_id: u32 = 0;
|
||||
@@ -113,7 +112,7 @@ pub fn drop_manual_memoization(
|
||||
// - (if validation is enabled) collect manual memoization markers
|
||||
//
|
||||
// queued_inserts maps InstructionId -> new Instruction to insert after that instruction
|
||||
let mut queued_inserts: HashMap<InstructionId, Instruction> = HashMap::new();
|
||||
let mut queued_inserts: FxHashMap<InstructionId, Instruction> = FxHashMap::default();
|
||||
|
||||
// Collect all block instruction lists up front to avoid borrowing func immutably
|
||||
// while needing to mutate it
|
||||
@@ -202,7 +201,7 @@ fn process_manual_memo_call(
|
||||
sidemap: &mut IdentifierSidemap,
|
||||
is_validation_enabled: bool,
|
||||
next_manual_memo_id: &mut u32,
|
||||
queued_inserts: &mut HashMap<InstructionId, Instruction>,
|
||||
queued_inserts: &mut FxHashMap<InstructionId, Instruction>,
|
||||
) {
|
||||
let instr = &func.instructions[instr_id.0 as usize];
|
||||
|
||||
@@ -386,7 +385,7 @@ fn collect_temporaries(
|
||||
/// Returns the variable + property reads represented by the instruction value.
|
||||
pub fn collect_maybe_memo_dependencies(
|
||||
value: &InstructionValue,
|
||||
maybe_deps: &HashMap<IdentifierId, ManualMemoDependency>,
|
||||
maybe_deps: &FxHashMap<IdentifierId, ManualMemoDependency>,
|
||||
optional: bool,
|
||||
env: &Environment,
|
||||
) -> Option<ManualMemoDependency> {
|
||||
@@ -649,10 +648,10 @@ fn extract_manual_memoization_args(
|
||||
// findOptionalPlaces
|
||||
// =============================================================================
|
||||
|
||||
fn find_optional_places(func: &HirFunction) -> Result<HashSet<IdentifierId>, CompilerDiagnostic> {
|
||||
fn find_optional_places(func: &HirFunction) -> Result<FxHashSet<IdentifierId>, CompilerDiagnostic> {
|
||||
use react_compiler_hir::Terminal;
|
||||
|
||||
let mut optionals = HashSet::new();
|
||||
let mut optionals = FxHashSet::default();
|
||||
for block in func.body.blocks.values() {
|
||||
if let Terminal::Optional {
|
||||
optional: true,
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
//!
|
||||
//! Analogous to TS `Inference/InlineImmediatelyInvokedFunctionExpressions.ts`.
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use indexmap::IndexSet;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_hir::environment::Environment;
|
||||
use react_compiler_hir::visitors;
|
||||
@@ -62,9 +63,9 @@ pub fn inline_immediately_invoked_function_expressions(
|
||||
env: &mut Environment,
|
||||
) {
|
||||
// Track all function expressions that are assigned to a temporary
|
||||
let mut functions: HashMap<IdentifierId, FunctionId> = HashMap::new();
|
||||
let mut functions: FxHashMap<IdentifierId, FunctionId> = FxHashMap::default();
|
||||
// Functions that are inlined (by identifier id of the callee)
|
||||
let mut inlined_functions: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut inlined_functions: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
|
||||
// Iterate the *existing* blocks from the outer component to find IIFEs
|
||||
// and inline them. During iteration we will modify `func` (by inlining the CFG
|
||||
@@ -140,7 +141,7 @@ pub fn inline_immediately_invoked_function_expressions(
|
||||
instructions: continuation_instructions,
|
||||
kind: block_kind,
|
||||
phis: Vec::new(),
|
||||
preds: indexmap::IndexSet::new(),
|
||||
preds: IndexSet::default(),
|
||||
terminal: continuation_terminal,
|
||||
};
|
||||
func.body
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
//!
|
||||
//! Analogous to TS `HIR/MergeConsecutiveBlocks.ts`.
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_hir::visitors;
|
||||
use react_compiler_hir::{
|
||||
@@ -53,7 +53,7 @@ pub fn merge_consecutive_blocks(func: &mut HirFunction, functions: &mut [HirFunc
|
||||
}
|
||||
|
||||
// Build fallthrough set
|
||||
let mut fallthrough_blocks: HashSet<BlockId> = HashSet::new();
|
||||
let mut fallthrough_blocks: FxHashSet<BlockId> = FxHashSet::default();
|
||||
for block in func.body.blocks.values() {
|
||||
if let Some(ft) = visitors::terminal_fallthrough(&block.terminal) {
|
||||
fallthrough_blocks.insert(ft);
|
||||
@@ -186,13 +186,13 @@ pub fn merge_consecutive_blocks(func: &mut HirFunction, functions: &mut [HirFunc
|
||||
|
||||
/// Tracks which blocks have been merged and into which target.
|
||||
struct MergedBlocks {
|
||||
map: HashMap<BlockId, BlockId>,
|
||||
map: FxHashMap<BlockId, BlockId>,
|
||||
}
|
||||
|
||||
impl MergedBlocks {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
map: HashMap::new(),
|
||||
map: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
//!
|
||||
//! Conditional on `env.config.enable_name_anonymous_functions`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use react_compiler_hir::environment::Environment;
|
||||
use react_compiler_hir::object_shape::HookKind;
|
||||
@@ -63,7 +63,7 @@ pub fn name_anonymous_functions(func: &mut HirFunction, env: &mut Environment) {
|
||||
if updates.is_empty() {
|
||||
return;
|
||||
}
|
||||
let update_map: HashMap<FunctionId, &String> =
|
||||
let update_map: FxHashMap<FunctionId, &String> =
|
||||
updates.iter().map(|(fid, name)| (*fid, name)).collect();
|
||||
|
||||
// Apply name updates to the inner HirFunction in the arena
|
||||
@@ -86,7 +86,7 @@ pub fn name_anonymous_functions(func: &mut HirFunction, env: &mut Environment) {
|
||||
/// Apply name hints to FunctionExpression instruction values.
|
||||
fn apply_name_hints_to_instructions(
|
||||
instructions: &mut [Instruction],
|
||||
update_map: &HashMap<FunctionId, &String>,
|
||||
update_map: &FxHashMap<FunctionId, &String>,
|
||||
) {
|
||||
for instr in instructions.iter_mut() {
|
||||
if let InstructionValue::FunctionExpression {
|
||||
@@ -117,9 +117,9 @@ struct Node {
|
||||
|
||||
fn name_anonymous_functions_impl(func: &HirFunction, env: &Environment) -> Vec<Node> {
|
||||
// Functions that we track to generate names for
|
||||
let mut functions: HashMap<IdentifierId, usize> = HashMap::new();
|
||||
let mut functions: FxHashMap<IdentifierId, usize> = FxHashMap::default();
|
||||
// Tracks temporaries that read from variables/globals/properties
|
||||
let mut names: HashMap<IdentifierId, String> = HashMap::new();
|
||||
let mut names: FxHashMap<IdentifierId, String> = FxHashMap::default();
|
||||
// Tracks all function nodes
|
||||
let mut nodes: Vec<Node> = Vec::new();
|
||||
|
||||
@@ -256,8 +256,8 @@ fn handle_call(
|
||||
_func: &HirFunction,
|
||||
callee_id: IdentifierId,
|
||||
args: &[PlaceOrSpread],
|
||||
functions: &mut HashMap<IdentifierId, usize>,
|
||||
names: &HashMap<IdentifierId, String>,
|
||||
functions: &mut FxHashMap<IdentifierId, usize>,
|
||||
names: &FxHashMap<IdentifierId, String>,
|
||||
nodes: &mut Vec<Node>,
|
||||
) {
|
||||
let callee_ident = &env.identifiers[callee_id.0 as usize];
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//!
|
||||
//! Ported from TypeScript `src/Optimization/OptimizeForSSR.ts`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use react_compiler_hir::environment::Environment;
|
||||
use react_compiler_hir::object_shape::HookKind;
|
||||
@@ -43,7 +43,7 @@ pub fn optimize_for_ssr(func: &mut HirFunction, env: &Environment) {
|
||||
// Any use of the hook return other than the expected destructuring pattern
|
||||
// prevents inlining (we delete from inlined_state if we see the identifier used
|
||||
// as an operand elsewhere).
|
||||
let mut inlined_state: HashMap<IdentifierId, InlinedStateReplacement> = HashMap::new();
|
||||
let mut inlined_state: FxHashMap<IdentifierId, InlinedStateReplacement> = FxHashMap::default();
|
||||
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
for &instr_id in &block.instructions {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
//!
|
||||
//! Conditional on `env.config.enable_function_outlining`.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use react_compiler_hir::environment::Environment;
|
||||
use react_compiler_hir::{
|
||||
@@ -25,7 +25,7 @@ use react_compiler_ssa::enter_ssa::placeholder_function;
|
||||
pub fn outline_functions(
|
||||
func: &mut HirFunction,
|
||||
env: &mut Environment,
|
||||
fbt_operands: &HashSet<IdentifierId>,
|
||||
fbt_operands: &FxHashSet<IdentifierId>,
|
||||
) {
|
||||
// Collect per-instruction actions to maintain depth-first name allocation order.
|
||||
// Each entry: (instr index, function_id to recurse into, should_outline)
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
//! Outlines JSX expressions in callbacks into separate component functions.
|
||||
//! This pass is conditional on `env.config.enable_jsx_outlining` (defaults to false).
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use react_compiler_hir::environment::Environment;
|
||||
use react_compiler_hir::{
|
||||
BasicBlock, BlockId, BlockKind, EvaluationOrder, FunctionId, HIR, HirFunction, IdentifierId,
|
||||
@@ -58,7 +58,7 @@ fn outline_jsx_impl(
|
||||
outlined_fns: &mut Vec<HirFunction>,
|
||||
) {
|
||||
// Collect LoadGlobal instructions (tag -> instr)
|
||||
let mut globals: HashMap<IdentifierId, usize> = HashMap::new(); // id -> instr_idx
|
||||
let mut globals: FxHashMap<IdentifierId, usize> = FxHashMap::default(); // id -> instr_idx
|
||||
|
||||
// Process each block
|
||||
let block_ids: Vec<BlockId> = func.body.blocks.keys().copied().collect();
|
||||
@@ -66,9 +66,9 @@ fn outline_jsx_impl(
|
||||
let block = &func.body.blocks[block_id];
|
||||
let instr_ids = block.instructions.clone();
|
||||
|
||||
let mut rewrite_instr: HashMap<EvaluationOrder, Vec<Instruction>> = HashMap::new();
|
||||
let mut rewrite_instr: FxHashMap<EvaluationOrder, Vec<Instruction>> = FxHashMap::default();
|
||||
let mut jsx_group: Vec<JsxInstrInfo> = Vec::new();
|
||||
let mut children_ids: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut children_ids: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
|
||||
// First pass: collect all instruction info without borrowing func mutably
|
||||
enum InstrAction {
|
||||
@@ -211,8 +211,8 @@ fn process_and_outline_jsx(
|
||||
func: &mut HirFunction,
|
||||
env: &mut Environment,
|
||||
jsx_group: &mut Vec<JsxInstrInfo>,
|
||||
globals: &HashMap<IdentifierId, usize>,
|
||||
rewrite_instr: &mut HashMap<EvaluationOrder, Vec<Instruction>>,
|
||||
globals: &FxHashMap<IdentifierId, usize>,
|
||||
rewrite_instr: &mut FxHashMap<EvaluationOrder, Vec<Instruction>>,
|
||||
outlined_fns: &mut Vec<HirFunction>,
|
||||
) {
|
||||
if jsx_group.len() <= 1 {
|
||||
@@ -237,7 +237,7 @@ fn process_jsx_group(
|
||||
func: &HirFunction,
|
||||
env: &mut Environment,
|
||||
jsx_group: &[JsxInstrInfo],
|
||||
globals: &HashMap<IdentifierId, usize>,
|
||||
globals: &FxHashMap<IdentifierId, usize>,
|
||||
) -> Option<OutlinedResult> {
|
||||
// Only outline in callbacks, not top-level components
|
||||
if func.fn_type == ReactFunctionType::Component {
|
||||
@@ -266,9 +266,9 @@ fn collect_props(
|
||||
jsx_group: &[JsxInstrInfo],
|
||||
) -> Option<Vec<OutlinedJsxAttribute>> {
|
||||
let mut id_counter = 1u32;
|
||||
let mut seen: HashSet<String> = HashSet::new();
|
||||
let mut seen: FxHashSet<String> = FxHashSet::default();
|
||||
let mut attributes = Vec::new();
|
||||
let jsx_ids: HashSet<IdentifierId> = jsx_group.iter().map(|j| j.lvalue_id).collect();
|
||||
let jsx_ids: FxHashSet<IdentifierId> = jsx_group.iter().map(|j| j.lvalue_id).collect();
|
||||
|
||||
let mut generate_name = |old_name: &str, _env: &mut Environment| -> String {
|
||||
let mut new_name = old_name.to_string();
|
||||
@@ -402,7 +402,7 @@ fn emit_outlined_fn(
|
||||
env: &mut Environment,
|
||||
jsx_group: &[JsxInstrInfo],
|
||||
old_props: &[OutlinedJsxAttribute],
|
||||
globals: &HashMap<IdentifierId, usize>,
|
||||
globals: &FxHashMap<IdentifierId, usize>,
|
||||
) -> Option<HirFunction> {
|
||||
let old_to_new_props = create_old_to_new_props_mapping(env, old_props);
|
||||
|
||||
@@ -458,7 +458,7 @@ fn emit_outlined_fn(
|
||||
kind: BlockKind::Block,
|
||||
id: BlockId(0),
|
||||
instructions: instr_ids,
|
||||
preds: indexmap::IndexSet::new(),
|
||||
preds: IndexSet::default(),
|
||||
terminal: Terminal::Return {
|
||||
value: last_lvalue,
|
||||
return_variant: ReturnVariant::Explicit,
|
||||
@@ -469,7 +469,7 @@ fn emit_outlined_fn(
|
||||
phis: Vec::new(),
|
||||
};
|
||||
|
||||
let mut blocks = IndexMap::new();
|
||||
let mut blocks = IndexMap::default();
|
||||
blocks.insert(BlockId(0), block);
|
||||
|
||||
let outlined_fn = HirFunction {
|
||||
@@ -498,7 +498,7 @@ fn emit_outlined_fn(
|
||||
fn emit_load_globals(
|
||||
func: &HirFunction,
|
||||
jsx_group: &[JsxInstrInfo],
|
||||
globals: &HashMap<IdentifierId, usize>,
|
||||
globals: &FxHashMap<IdentifierId, usize>,
|
||||
) -> Option<Vec<Instruction>> {
|
||||
let mut instructions = Vec::new();
|
||||
for info in jsx_group {
|
||||
@@ -516,9 +516,9 @@ fn emit_load_globals(
|
||||
fn emit_updated_jsx(
|
||||
func: &HirFunction,
|
||||
jsx_group: &[JsxInstrInfo],
|
||||
old_to_new_props: &IndexMap<IdentifierId, OutlinedJsxAttribute>,
|
||||
old_to_new_props: &IndexMap<IdentifierId, OutlinedJsxAttribute, FxBuildHasher>,
|
||||
) -> Vec<Instruction> {
|
||||
let jsx_ids: HashSet<IdentifierId> = jsx_group.iter().map(|j| j.lvalue_id).collect();
|
||||
let jsx_ids: FxHashSet<IdentifierId> = jsx_group.iter().map(|j| j.lvalue_id).collect();
|
||||
let mut new_instrs = Vec::new();
|
||||
|
||||
for info in jsx_group {
|
||||
@@ -594,8 +594,8 @@ fn emit_updated_jsx(
|
||||
fn create_old_to_new_props_mapping(
|
||||
env: &mut Environment,
|
||||
old_props: &[OutlinedJsxAttribute],
|
||||
) -> IndexMap<IdentifierId, OutlinedJsxAttribute> {
|
||||
let mut old_to_new = IndexMap::new();
|
||||
) -> IndexMap<IdentifierId, OutlinedJsxAttribute, FxBuildHasher> {
|
||||
let mut old_to_new = IndexMap::default();
|
||||
|
||||
for old_prop in old_props {
|
||||
if old_prop.original_name == "key" {
|
||||
@@ -629,7 +629,7 @@ fn create_old_to_new_props_mapping(
|
||||
fn emit_destructure_props(
|
||||
env: &mut Environment,
|
||||
props_obj: &Place,
|
||||
old_to_new_props: &IndexMap<IdentifierId, OutlinedJsxAttribute>,
|
||||
old_to_new_props: &IndexMap<IdentifierId, OutlinedJsxAttribute, FxBuildHasher>,
|
||||
) -> Instruction {
|
||||
let mut properties = Vec::new();
|
||||
for prop in old_to_new_props.values() {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
//!
|
||||
//! Analogous to TS `Optimization/PruneMaybeThrows.ts`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use react_compiler_diagnostics::{
|
||||
CompilerDiagnostic, CompilerDiagnosticDetail, ErrorCategory, GENERATED_SOURCE,
|
||||
@@ -86,8 +86,8 @@ pub fn prune_maybe_throws(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn prune_maybe_throws_impl(func: &mut HirFunction) -> Option<HashMap<BlockId, BlockId>> {
|
||||
let mut terminal_mapping: HashMap<BlockId, BlockId> = HashMap::new();
|
||||
fn prune_maybe_throws_impl(func: &mut HirFunction) -> Option<FxHashMap<BlockId, BlockId>> {
|
||||
let mut terminal_mapping: FxHashMap<BlockId, BlockId> = FxHashMap::default();
|
||||
let instructions = &func.instructions;
|
||||
|
||||
for block in func.body.blocks.values_mut() {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
//! Analogous to TS `PruneUnusedLabelsHIR.ts`.
|
||||
|
||||
use react_compiler_hir::{BlockId, BlockKind, GotoVariant, HirFunction, Terminal};
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
pub fn prune_unused_labels_hir(func: &mut HirFunction) {
|
||||
// Phase 1: Identify label terminals whose body block immediately breaks
|
||||
@@ -45,7 +45,7 @@ pub fn prune_unused_labels_hir(func: &mut HirFunction) {
|
||||
}
|
||||
|
||||
// Phase 2: Apply merges
|
||||
let mut rewrites: HashMap<BlockId, BlockId> = HashMap::new();
|
||||
let mut rewrites: FxHashMap<BlockId, BlockId> = FxHashMap::default();
|
||||
|
||||
for (original_label_id, next_id, fallthrough_id) in &merged {
|
||||
let label_id = rewrites
|
||||
|
||||
@@ -8,5 +8,6 @@ react_compiler_ast = { path = "../react_compiler_ast" }
|
||||
react_compiler_diagnostics = { path = "../react_compiler_diagnostics" }
|
||||
react_compiler_hir = { path = "../react_compiler_hir" }
|
||||
indexmap = "2"
|
||||
rustc-hash = "2"
|
||||
serde_json = "1"
|
||||
hmac-sha256 = "1"
|
||||
|
||||
+7
-7
@@ -8,7 +8,7 @@
|
||||
//!
|
||||
//! Corresponds to `src/ReactiveScopes/AssertScopeInstructionsWithinScope.ts`.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use react_compiler_diagnostics::{CompilerDiagnostic, ErrorCategory};
|
||||
use react_compiler_hir::environment::Environment;
|
||||
@@ -25,7 +25,7 @@ pub fn assert_scope_instructions_within_scopes(
|
||||
env: &Environment,
|
||||
) -> Result<(), CompilerDiagnostic> {
|
||||
// Pass 1: Collect all scope IDs
|
||||
let mut existing_scopes: HashSet<ScopeId> = HashSet::new();
|
||||
let mut existing_scopes: FxHashSet<ScopeId> = FxHashSet::default();
|
||||
let find_visitor = FindAllScopesVisitor { env };
|
||||
visit_reactive_function(func, &find_visitor, &mut existing_scopes);
|
||||
|
||||
@@ -33,7 +33,7 @@ pub fn assert_scope_instructions_within_scopes(
|
||||
let check_visitor = CheckInstructionsAgainstScopesVisitor { env };
|
||||
let mut check_state = CheckState {
|
||||
existing_scopes,
|
||||
active_scopes: HashSet::new(),
|
||||
active_scopes: FxHashSet::default(),
|
||||
error: None,
|
||||
};
|
||||
visit_reactive_function(func, &check_visitor, &mut check_state);
|
||||
@@ -52,13 +52,13 @@ struct FindAllScopesVisitor<'a> {
|
||||
}
|
||||
|
||||
impl<'a> ReactiveFunctionVisitor for FindAllScopesVisitor<'a> {
|
||||
type State = HashSet<ScopeId>;
|
||||
type State = FxHashSet<ScopeId>;
|
||||
|
||||
fn env(&self) -> &Environment {
|
||||
self.env
|
||||
}
|
||||
|
||||
fn visit_scope(&self, scope: &ReactiveScopeBlock, state: &mut HashSet<ScopeId>) {
|
||||
fn visit_scope(&self, scope: &ReactiveScopeBlock, state: &mut FxHashSet<ScopeId>) {
|
||||
self.traverse_scope(scope, state);
|
||||
state.insert(scope.scope);
|
||||
}
|
||||
@@ -69,8 +69,8 @@ impl<'a> ReactiveFunctionVisitor for FindAllScopesVisitor<'a> {
|
||||
// =============================================================================
|
||||
|
||||
struct CheckState {
|
||||
existing_scopes: HashSet<ScopeId>,
|
||||
active_scopes: HashSet<ScopeId>,
|
||||
existing_scopes: FxHashSet<ScopeId>,
|
||||
active_scopes: FxHashSet<ScopeId>,
|
||||
error: Option<CompilerDiagnostic>,
|
||||
}
|
||||
|
||||
|
||||
+8
-4
@@ -7,7 +7,7 @@
|
||||
//!
|
||||
//! Corresponds to `src/ReactiveScopes/AssertWellFormedBreakTargets.ts`.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use react_compiler_hir::{
|
||||
BlockId, ReactiveFunction, ReactiveTerminal, ReactiveTerminalStatement,
|
||||
@@ -19,7 +19,7 @@ use crate::visitors::{ReactiveFunctionVisitor, visit_reactive_function};
|
||||
/// Assert that all break/continue targets reference existent labels.
|
||||
pub fn assert_well_formed_break_targets(func: &ReactiveFunction, env: &Environment) {
|
||||
let visitor = Visitor { env };
|
||||
let mut state: HashSet<BlockId> = HashSet::new();
|
||||
let mut state: FxHashSet<BlockId> = FxHashSet::default();
|
||||
visit_reactive_function(func, &visitor, &mut state);
|
||||
}
|
||||
|
||||
@@ -28,13 +28,17 @@ struct Visitor<'a> {
|
||||
}
|
||||
|
||||
impl<'a> ReactiveFunctionVisitor for Visitor<'a> {
|
||||
type State = HashSet<BlockId>;
|
||||
type State = FxHashSet<BlockId>;
|
||||
|
||||
fn env(&self) -> &Environment {
|
||||
self.env
|
||||
}
|
||||
|
||||
fn visit_terminal(&self, stmt: &ReactiveTerminalStatement, seen_labels: &mut HashSet<BlockId>) {
|
||||
fn visit_terminal(
|
||||
&self,
|
||||
stmt: &ReactiveTerminalStatement,
|
||||
seen_labels: &mut FxHashSet<BlockId>,
|
||||
) {
|
||||
if let Some(label) = &stmt.label {
|
||||
seen_labels.insert(label.id);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//!
|
||||
//! Corresponds to `src/ReactiveScopes/BuildReactiveFunction.ts`.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use react_compiler_diagnostics::{
|
||||
CompilerDiagnostic, CompilerDiagnosticDetail, ErrorCategory, SourceLocation,
|
||||
@@ -108,10 +108,10 @@ impl ControlFlowTarget {
|
||||
struct Context<'a> {
|
||||
ir: &'a HirFunction,
|
||||
next_schedule_id: u32,
|
||||
emitted: HashSet<BlockId>,
|
||||
scope_fallthroughs: HashSet<BlockId>,
|
||||
scheduled: HashSet<BlockId>,
|
||||
catch_handlers: HashSet<BlockId>,
|
||||
emitted: FxHashSet<BlockId>,
|
||||
scope_fallthroughs: FxHashSet<BlockId>,
|
||||
scheduled: FxHashSet<BlockId>,
|
||||
catch_handlers: FxHashSet<BlockId>,
|
||||
control_flow_stack: Vec<ControlFlowTarget>,
|
||||
}
|
||||
|
||||
@@ -120,10 +120,10 @@ impl<'a> Context<'a> {
|
||||
Self {
|
||||
ir,
|
||||
next_schedule_id: 0,
|
||||
emitted: HashSet::new(),
|
||||
scope_fallthroughs: HashSet::new(),
|
||||
scheduled: HashSet::new(),
|
||||
catch_handlers: HashSet::new(),
|
||||
emitted: FxHashSet::default(),
|
||||
scope_fallthroughs: FxHashSet::default(),
|
||||
scheduled: FxHashSet::default(),
|
||||
catch_handlers: FxHashSet::default(),
|
||||
control_flow_stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
//!
|
||||
//! Corresponds to `src/ReactiveScopes/CodegenReactiveFunction.ts` in the TS compiler.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_ast::common::BaseNode;
|
||||
use react_compiler_ast::common::Position as AstPosition;
|
||||
@@ -195,8 +194,8 @@ fn source_file_hash(code: &str) -> String {
|
||||
pub fn codegen_function(
|
||||
func: &ReactiveFunction,
|
||||
env: &mut Environment,
|
||||
unique_identifiers: HashSet<String>,
|
||||
fbt_operands: HashSet<IdentifierId>,
|
||||
unique_identifiers: FxHashSet<String>,
|
||||
fbt_operands: FxHashSet<IdentifierId>,
|
||||
) -> Result<CodegenFunction, CompilerError> {
|
||||
let fn_name = func.id.as_deref().unwrap_or("[[ anonymous ]]");
|
||||
let mut cx = Context::new(env, fn_name.to_string(), unique_identifiers, fbt_operands);
|
||||
@@ -556,7 +555,7 @@ pub fn codegen_function(
|
||||
// Context
|
||||
// =============================================================================
|
||||
|
||||
type Temporaries = HashMap<DeclarationId, Option<ExpressionOrJsxText>>;
|
||||
type Temporaries = FxHashMap<DeclarationId, Option<ExpressionOrJsxText>>;
|
||||
|
||||
#[derive(Clone)]
|
||||
enum ExpressionOrJsxText {
|
||||
@@ -569,37 +568,37 @@ struct Context<'env> {
|
||||
#[allow(dead_code)]
|
||||
fn_name: String,
|
||||
next_cache_index: u32,
|
||||
declarations: HashSet<DeclarationId>,
|
||||
declarations: FxHashSet<DeclarationId>,
|
||||
temp: Temporaries,
|
||||
object_methods: HashMap<
|
||||
object_methods: FxHashMap<
|
||||
IdentifierId,
|
||||
(
|
||||
InstructionValue,
|
||||
Option<react_compiler_diagnostics::SourceLocation>,
|
||||
),
|
||||
>,
|
||||
unique_identifiers: HashSet<String>,
|
||||
fbt_operands: HashSet<IdentifierId>,
|
||||
synthesized_names: HashMap<String, String>,
|
||||
unique_identifiers: FxHashSet<String>,
|
||||
fbt_operands: FxHashSet<IdentifierId>,
|
||||
synthesized_names: FxHashMap<String, String>,
|
||||
}
|
||||
|
||||
impl<'env> Context<'env> {
|
||||
fn new(
|
||||
env: &'env mut Environment,
|
||||
fn_name: String,
|
||||
unique_identifiers: HashSet<String>,
|
||||
fbt_operands: HashSet<IdentifierId>,
|
||||
unique_identifiers: FxHashSet<String>,
|
||||
fbt_operands: FxHashSet<IdentifierId>,
|
||||
) -> Self {
|
||||
Context {
|
||||
env,
|
||||
fn_name,
|
||||
next_cache_index: 0,
|
||||
declarations: HashSet::new(),
|
||||
temp: HashMap::new(),
|
||||
object_methods: HashMap::new(),
|
||||
declarations: FxHashSet::default(),
|
||||
temp: FxHashMap::default(),
|
||||
object_methods: FxHashMap::default(),
|
||||
unique_identifiers,
|
||||
fbt_operands,
|
||||
synthesized_names: HashMap::new(),
|
||||
synthesized_names: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4163,7 +4162,7 @@ fn create_function_body_hook_guard(
|
||||
fn apply_renames_to_json(
|
||||
value: &mut serde_json::Value,
|
||||
renames: &[react_compiler_hir::environment::BindingRename],
|
||||
reference_node_ids: &std::collections::HashSet<u32>,
|
||||
reference_node_ids: &rustc_hash::FxHashSet<u32>,
|
||||
) {
|
||||
apply_renames_to_json_inner(value, renames, reference_node_ids, false);
|
||||
}
|
||||
@@ -4171,7 +4170,7 @@ fn apply_renames_to_json(
|
||||
fn apply_renames_to_json_inner(
|
||||
value: &mut serde_json::Value,
|
||||
renames: &[react_compiler_hir::environment::BindingRename],
|
||||
reference_node_ids: &std::collections::HashSet<u32>,
|
||||
reference_node_ids: &rustc_hash::FxHashSet<u32>,
|
||||
is_property_key: bool,
|
||||
) {
|
||||
if renames.is_empty() {
|
||||
|
||||
+4
-4
@@ -8,7 +8,7 @@
|
||||
//!
|
||||
//! Corresponds to `src/ReactiveScopes/ExtractScopeDeclarationsFromDestructuring.ts`.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use react_compiler_hir::{
|
||||
DeclarationId, IdentifierId, IdentifierName, InstructionKind, InstructionValue, LValue,
|
||||
@@ -29,7 +29,7 @@ pub fn extract_scope_declarations_from_destructuring(
|
||||
func: &mut ReactiveFunction,
|
||||
env: &mut Environment,
|
||||
) -> Result<(), react_compiler_diagnostics::CompilerError> {
|
||||
let mut declared: HashSet<DeclarationId> = HashSet::new();
|
||||
let mut declared: FxHashSet<DeclarationId> = FxHashSet::default();
|
||||
for param in &func.params {
|
||||
let place = match param {
|
||||
ParamPattern::Place(p) => p,
|
||||
@@ -44,7 +44,7 @@ pub fn extract_scope_declarations_from_destructuring(
|
||||
}
|
||||
|
||||
struct ExtractState {
|
||||
declared: HashSet<DeclarationId>,
|
||||
declared: FxHashSet<DeclarationId>,
|
||||
}
|
||||
|
||||
struct Transform<'a> {
|
||||
@@ -94,7 +94,7 @@ impl<'a> ReactiveFunctionTransform for Transform<'a> {
|
||||
}) = &mut instruction.value
|
||||
{
|
||||
// Check if this is a mixed destructuring (some declared, some not)
|
||||
let mut reassigned: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut reassigned: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
let mut has_declaration = false;
|
||||
|
||||
for place in visitors::each_pattern_operand(&lvalue.pattern) {
|
||||
|
||||
+13
-13
@@ -8,7 +8,7 @@
|
||||
//!
|
||||
//! Corresponds to `src/ReactiveScopes/MergeReactiveScopesThatInvalidateTogether.ts`.
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_diagnostics::CompilerError;
|
||||
use react_compiler_hir::{
|
||||
@@ -36,14 +36,14 @@ pub fn merge_reactive_scopes_that_invalidate_together(
|
||||
) -> Result<(), CompilerError> {
|
||||
// Pass 1: find last usage of each declaration
|
||||
let visitor = FindLastUsageVisitor { env: &*env };
|
||||
let mut last_usage: HashMap<DeclarationId, EvaluationOrder> = HashMap::new();
|
||||
let mut last_usage: FxHashMap<DeclarationId, EvaluationOrder> = FxHashMap::default();
|
||||
visit_reactive_function(func, &visitor, &mut last_usage);
|
||||
|
||||
// Pass 2+3: merge scopes
|
||||
let mut transform = MergeTransform {
|
||||
env,
|
||||
last_usage,
|
||||
temporaries: HashMap::new(),
|
||||
temporaries: FxHashMap::default(),
|
||||
};
|
||||
let mut state: Option<Vec<ReactiveScopeDependency>> = None;
|
||||
transform_reactive_function(func, &mut transform, &mut state)
|
||||
@@ -59,7 +59,7 @@ struct FindLastUsageVisitor<'a> {
|
||||
}
|
||||
|
||||
impl<'a> ReactiveFunctionVisitor for FindLastUsageVisitor<'a> {
|
||||
type State = HashMap<DeclarationId, EvaluationOrder>;
|
||||
type State = FxHashMap<DeclarationId, EvaluationOrder>;
|
||||
|
||||
fn env(&self) -> &Environment {
|
||||
self.env
|
||||
@@ -81,8 +81,8 @@ impl<'a> ReactiveFunctionVisitor for FindLastUsageVisitor<'a> {
|
||||
/// TS: `class Transform extends ReactiveFunctionTransform<ReactiveScopeDependencies | null>`
|
||||
struct MergeTransform<'a> {
|
||||
env: &'a mut Environment,
|
||||
last_usage: HashMap<DeclarationId, EvaluationOrder>,
|
||||
temporaries: HashMap<DeclarationId, DeclarationId>,
|
||||
last_usage: FxHashMap<DeclarationId, EvaluationOrder>,
|
||||
temporaries: FxHashMap<DeclarationId, DeclarationId>,
|
||||
}
|
||||
|
||||
impl<'a> ReactiveFunctionTransform for MergeTransform<'a> {
|
||||
@@ -138,7 +138,7 @@ impl<'a> MergeTransform<'a> {
|
||||
scope_id: ScopeId,
|
||||
from: usize,
|
||||
to: usize,
|
||||
lvalues: HashSet<DeclarationId>,
|
||||
lvalues: FxHashSet<DeclarationId>,
|
||||
}
|
||||
|
||||
let mut current: Option<MergedScope> = None;
|
||||
@@ -308,7 +308,7 @@ impl<'a> MergeTransform<'a> {
|
||||
scope_id: next_scope_id,
|
||||
from: i,
|
||||
to: i + 1,
|
||||
lvalues: HashSet::new(),
|
||||
lvalues: FxHashSet::default(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -319,7 +319,7 @@ impl<'a> MergeTransform<'a> {
|
||||
scope_id: next_scope_id,
|
||||
from: i,
|
||||
to: i + 1,
|
||||
lvalues: HashSet::new(),
|
||||
lvalues: FxHashSet::default(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -398,7 +398,7 @@ impl<'a> MergeTransform<'a> {
|
||||
/// Updates scope declarations to remove any that are not used after the scope.
|
||||
fn update_scope_declarations(
|
||||
scope_id: ScopeId,
|
||||
last_usage: &HashMap<DeclarationId, EvaluationOrder>,
|
||||
last_usage: &FxHashMap<DeclarationId, EvaluationOrder>,
|
||||
env: &mut Environment,
|
||||
) {
|
||||
let range_end = env.scopes[scope_id.0 as usize].range.end;
|
||||
@@ -417,8 +417,8 @@ fn update_scope_declarations(
|
||||
/// Returns whether all lvalues are last used at or before the given scope.
|
||||
fn are_lvalues_last_used_by_scope(
|
||||
scope_id: ScopeId,
|
||||
lvalues: &HashSet<DeclarationId>,
|
||||
last_usage: &HashMap<DeclarationId, EvaluationOrder>,
|
||||
lvalues: &FxHashSet<DeclarationId>,
|
||||
last_usage: &FxHashMap<DeclarationId, EvaluationOrder>,
|
||||
env: &Environment,
|
||||
) -> bool {
|
||||
let range_end = env.scopes[scope_id.0 as usize].range.end;
|
||||
@@ -437,7 +437,7 @@ fn can_merge_scopes(
|
||||
current_id: ScopeId,
|
||||
next_id: ScopeId,
|
||||
env: &Environment,
|
||||
temporaries: &HashMap<DeclarationId, DeclarationId>,
|
||||
temporaries: &FxHashMap<DeclarationId, DeclarationId>,
|
||||
) -> bool {
|
||||
let current = &env.scopes[current_id.0 as usize];
|
||||
let next = &env.scopes[next_id.0 as usize];
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
//!
|
||||
//! Corresponds to `src/ReactiveScopes/PromoteUsedTemporaries.ts`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_hir::DeclarationId;
|
||||
use react_compiler_hir::FunctionId;
|
||||
@@ -35,9 +34,9 @@ use react_compiler_hir::environment::Environment;
|
||||
// =============================================================================
|
||||
|
||||
struct State {
|
||||
tags: HashSet<DeclarationId>,
|
||||
promoted: HashSet<DeclarationId>,
|
||||
pruned: HashMap<DeclarationId, PrunedInfo>,
|
||||
tags: FxHashSet<DeclarationId>,
|
||||
promoted: FxHashSet<DeclarationId>,
|
||||
pruned: FxHashMap<DeclarationId, PrunedInfo>,
|
||||
}
|
||||
|
||||
struct PrunedInfo {
|
||||
@@ -53,9 +52,9 @@ struct PrunedInfo {
|
||||
/// TS: `promoteUsedTemporaries`
|
||||
pub fn promote_used_temporaries(func: &mut ReactiveFunction, env: &mut Environment) {
|
||||
let mut state = State {
|
||||
tags: HashSet::new(),
|
||||
promoted: HashSet::new(),
|
||||
pruned: HashMap::new(),
|
||||
tags: FxHashSet::default(),
|
||||
promoted: FxHashSet::default(),
|
||||
pruned: FxHashMap::default(),
|
||||
};
|
||||
|
||||
// Phase 1: collect promotable temporaries (jsx tags, pruned scope usage)
|
||||
@@ -78,8 +77,8 @@ pub fn promote_used_temporaries(func: &mut ReactiveFunction, env: &mut Environme
|
||||
promote_temporaries_block(&func.body, &mut state, env);
|
||||
|
||||
// Phase 3: promote interposed temporaries
|
||||
let mut consts: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut globals: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut consts: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
let mut globals: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
for param in &func.params {
|
||||
match param {
|
||||
ParamPattern::Place(p) => {
|
||||
@@ -90,7 +89,7 @@ pub fn promote_used_temporaries(func: &mut ReactiveFunction, env: &mut Environme
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut inter_state: HashMap<IdentifierId, (IdentifierId, bool)> = HashMap::new();
|
||||
let mut inter_state: FxHashMap<IdentifierId, (IdentifierId, bool)> = FxHashMap::default();
|
||||
promote_interposed_block(
|
||||
&func.body,
|
||||
&mut state,
|
||||
@@ -555,9 +554,9 @@ fn visit_hir_function_for_promotion(func_id: FunctionId, state: &mut State, env:
|
||||
fn promote_interposed_block(
|
||||
block: &ReactiveBlock,
|
||||
state: &mut State,
|
||||
inter_state: &mut HashMap<IdentifierId, (IdentifierId, bool)>,
|
||||
consts: &mut HashSet<IdentifierId>,
|
||||
globals: &mut HashSet<IdentifierId>,
|
||||
inter_state: &mut FxHashMap<IdentifierId, (IdentifierId, bool)>,
|
||||
consts: &mut FxHashSet<IdentifierId>,
|
||||
globals: &mut FxHashSet<IdentifierId>,
|
||||
env: &mut Environment,
|
||||
) {
|
||||
for stmt in block {
|
||||
@@ -595,8 +594,8 @@ fn promote_interposed_block(
|
||||
fn promote_interposed_place(
|
||||
place: &Place,
|
||||
state: &mut State,
|
||||
inter_state: &mut HashMap<IdentifierId, (IdentifierId, bool)>,
|
||||
consts: &HashSet<IdentifierId>,
|
||||
inter_state: &mut FxHashMap<IdentifierId, (IdentifierId, bool)>,
|
||||
consts: &FxHashSet<IdentifierId>,
|
||||
env: &mut Environment,
|
||||
) {
|
||||
if let Some(&(id, needs_promotion)) = inter_state.get(&place.identifier) {
|
||||
@@ -610,9 +609,9 @@ fn promote_interposed_place(
|
||||
fn promote_interposed_instruction(
|
||||
instr: &ReactiveInstruction,
|
||||
state: &mut State,
|
||||
inter_state: &mut HashMap<IdentifierId, (IdentifierId, bool)>,
|
||||
consts: &mut HashSet<IdentifierId>,
|
||||
globals: &mut HashSet<IdentifierId>,
|
||||
inter_state: &mut FxHashMap<IdentifierId, (IdentifierId, bool)>,
|
||||
consts: &mut FxHashSet<IdentifierId>,
|
||||
globals: &mut FxHashSet<IdentifierId>,
|
||||
env: &mut Environment,
|
||||
) {
|
||||
// Check instruction value lvalues (assignment targets)
|
||||
@@ -803,9 +802,9 @@ fn promote_interposed_instruction(
|
||||
fn promote_interposed_value(
|
||||
value: &ReactiveValue,
|
||||
state: &mut State,
|
||||
inter_state: &mut HashMap<IdentifierId, (IdentifierId, bool)>,
|
||||
consts: &mut HashSet<IdentifierId>,
|
||||
globals: &mut HashSet<IdentifierId>,
|
||||
inter_state: &mut FxHashMap<IdentifierId, (IdentifierId, bool)>,
|
||||
consts: &mut FxHashSet<IdentifierId>,
|
||||
globals: &mut FxHashSet<IdentifierId>,
|
||||
env: &mut Environment,
|
||||
) {
|
||||
match value {
|
||||
@@ -847,9 +846,9 @@ fn promote_interposed_value(
|
||||
fn promote_interposed_terminal(
|
||||
stmt: &ReactiveTerminalStatement,
|
||||
state: &mut State,
|
||||
inter_state: &mut HashMap<IdentifierId, (IdentifierId, bool)>,
|
||||
consts: &mut HashSet<IdentifierId>,
|
||||
globals: &mut HashSet<IdentifierId>,
|
||||
inter_state: &mut FxHashMap<IdentifierId, (IdentifierId, bool)>,
|
||||
consts: &mut FxHashSet<IdentifierId>,
|
||||
globals: &mut FxHashSet<IdentifierId>,
|
||||
env: &mut Environment,
|
||||
) {
|
||||
match &stmt.terminal {
|
||||
|
||||
+5
-5
@@ -11,7 +11,7 @@
|
||||
//!
|
||||
//! Corresponds to `src/ReactiveScopes/PruneAlwaysInvalidatingScopes.ts`.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use react_compiler_hir::{
|
||||
IdentifierId, InstructionValue, PrunedReactiveScopeBlock, ReactiveFunction,
|
||||
@@ -30,8 +30,8 @@ pub fn prune_always_invalidating_scopes(
|
||||
) -> Result<(), react_compiler_diagnostics::CompilerError> {
|
||||
let mut transform = Transform {
|
||||
env,
|
||||
always_invalidating_values: HashSet::new(),
|
||||
unmemoized_values: HashSet::new(),
|
||||
always_invalidating_values: FxHashSet::default(),
|
||||
unmemoized_values: FxHashSet::default(),
|
||||
};
|
||||
let mut state = false; // withinScope
|
||||
transform_reactive_function(func, &mut transform, &mut state)
|
||||
@@ -39,8 +39,8 @@ pub fn prune_always_invalidating_scopes(
|
||||
|
||||
struct Transform<'a> {
|
||||
env: &'a Environment,
|
||||
always_invalidating_values: HashSet<IdentifierId>,
|
||||
unmemoized_values: HashSet<IdentifierId>,
|
||||
always_invalidating_values: FxHashSet<IdentifierId>,
|
||||
unmemoized_values: FxHashSet<IdentifierId>,
|
||||
}
|
||||
|
||||
impl<'a> ReactiveFunctionTransform for Transform<'a> {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//!
|
||||
//! Corresponds to `src/ReactiveScopes/PruneHoistedContexts.ts`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use react_compiler_diagnostics::{CompilerError, CompilerErrorDetail, ErrorCategory};
|
||||
use react_compiler_hir::{
|
||||
@@ -33,7 +33,7 @@ pub fn prune_hoisted_contexts(
|
||||
let mut transform = Transform { env };
|
||||
let mut state = VisitorState {
|
||||
active_scopes: Vec::new(),
|
||||
uninitialized: HashMap::new(),
|
||||
uninitialized: FxHashMap::default(),
|
||||
};
|
||||
transform_reactive_function(func, &mut transform, &mut state)
|
||||
}
|
||||
@@ -49,8 +49,8 @@ enum UninitializedKind {
|
||||
}
|
||||
|
||||
struct VisitorState {
|
||||
active_scopes: Vec<std::collections::HashSet<IdentifierId>>,
|
||||
uninitialized: HashMap<IdentifierId, UninitializedKind>,
|
||||
active_scopes: Vec<rustc_hash::FxHashSet<IdentifierId>>,
|
||||
uninitialized: FxHashMap<IdentifierId, UninitializedKind>,
|
||||
}
|
||||
|
||||
impl VisitorState {
|
||||
@@ -81,7 +81,7 @@ impl<'a> ReactiveFunctionTransform for Transform<'a> {
|
||||
state: &mut VisitorState,
|
||||
) -> Result<(), CompilerError> {
|
||||
let scope_data = &self.env.scopes[scope.scope.0 as usize];
|
||||
let decl_ids: std::collections::HashSet<IdentifierId> =
|
||||
let decl_ids: rustc_hash::FxHashSet<IdentifierId> =
|
||||
scope_data.declarations.iter().map(|(id, _)| *id).collect();
|
||||
|
||||
// Add declared but not initialized variables
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
//!
|
||||
//! Corresponds to `src/ReactiveScopes/PruneNonEscapingScopes.ts`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
|
||||
|
||||
use indexmap::IndexSet;
|
||||
use react_compiler_hir::ArrayPatternElement;
|
||||
@@ -74,8 +73,8 @@ pub fn prune_non_escaping_scopes(
|
||||
// Prune scopes that do not declare/reassign any escaping values
|
||||
let mut transform = PruneScopesTransform {
|
||||
env,
|
||||
pruned_scopes: HashSet::new(),
|
||||
reassignments: HashMap::new(),
|
||||
pruned_scopes: FxHashSet::default(),
|
||||
reassignments: FxHashMap::default(),
|
||||
};
|
||||
let mut memoized_state = memoized;
|
||||
transform_reactive_function(func, &mut transform, &mut memoized_state)
|
||||
@@ -120,8 +119,8 @@ fn join_aliases(kind1: MemoizationLevel, kind2: MemoizationLevel) -> Memoization
|
||||
struct IdentifierNode {
|
||||
level: MemoizationLevel,
|
||||
memoized: bool,
|
||||
dependencies: IndexSet<DeclarationId>,
|
||||
scopes: IndexSet<ScopeId>,
|
||||
dependencies: IndexSet<DeclarationId, FxBuildHasher>,
|
||||
scopes: IndexSet<ScopeId, FxBuildHasher>,
|
||||
seen: bool,
|
||||
}
|
||||
|
||||
@@ -137,19 +136,19 @@ struct ScopeNode {
|
||||
|
||||
struct CollectState {
|
||||
/// Maps lvalues for LoadLocal to the identifier being loaded, to resolve indirections.
|
||||
definitions: HashMap<DeclarationId, DeclarationId>,
|
||||
identifiers: HashMap<DeclarationId, IdentifierNode>,
|
||||
scopes: HashMap<ScopeId, ScopeNode>,
|
||||
escaping_values: IndexSet<DeclarationId>,
|
||||
definitions: FxHashMap<DeclarationId, DeclarationId>,
|
||||
identifiers: FxHashMap<DeclarationId, IdentifierNode>,
|
||||
scopes: FxHashMap<ScopeId, ScopeNode>,
|
||||
escaping_values: IndexSet<DeclarationId, FxBuildHasher>,
|
||||
}
|
||||
|
||||
impl CollectState {
|
||||
fn new() -> Self {
|
||||
CollectState {
|
||||
definitions: HashMap::new(),
|
||||
identifiers: HashMap::new(),
|
||||
scopes: HashMap::new(),
|
||||
escaping_values: IndexSet::new(),
|
||||
definitions: FxHashMap::default(),
|
||||
identifiers: FxHashMap::default(),
|
||||
scopes: FxHashMap::default(),
|
||||
escaping_values: IndexSet::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,8 +159,8 @@ impl CollectState {
|
||||
IdentifierNode {
|
||||
level: MemoizationLevel::Never,
|
||||
memoized: false,
|
||||
dependencies: IndexSet::new(),
|
||||
scopes: IndexSet::new(),
|
||||
dependencies: IndexSet::default(),
|
||||
scopes: IndexSet::default(),
|
||||
seen: false,
|
||||
},
|
||||
);
|
||||
@@ -900,8 +899,8 @@ impl<'a> CollectDependenciesVisitor<'a> {
|
||||
.or_insert_with(|| IdentifierNode {
|
||||
level: MemoizationLevel::Never,
|
||||
memoized: false,
|
||||
dependencies: IndexSet::new(),
|
||||
scopes: IndexSet::new(),
|
||||
dependencies: IndexSet::default(),
|
||||
scopes: IndexSet::default(),
|
||||
seen: false,
|
||||
});
|
||||
node.level = join_aliases(node.level, lv.level);
|
||||
@@ -1049,17 +1048,17 @@ impl<'a> ReactiveFunctionVisitor for CollectDependenciesVisitor<'a> {
|
||||
// computeMemoizedIdentifiers
|
||||
// =============================================================================
|
||||
|
||||
fn compute_memoized_identifiers(state: &CollectState) -> HashSet<DeclarationId> {
|
||||
let mut memoized = HashSet::new();
|
||||
fn compute_memoized_identifiers(state: &CollectState) -> FxHashSet<DeclarationId> {
|
||||
let mut memoized = FxHashSet::default();
|
||||
|
||||
// We need mutable access to the nodes, so we clone the state into mutable structures
|
||||
let mut identifier_nodes: HashMap<
|
||||
let mut identifier_nodes: FxHashMap<
|
||||
DeclarationId,
|
||||
(
|
||||
MemoizationLevel,
|
||||
bool,
|
||||
IndexSet<DeclarationId>,
|
||||
IndexSet<ScopeId>,
|
||||
IndexSet<DeclarationId, FxBuildHasher>,
|
||||
IndexSet<ScopeId, FxBuildHasher>,
|
||||
bool,
|
||||
),
|
||||
> = state
|
||||
@@ -1079,7 +1078,7 @@ fn compute_memoized_identifiers(state: &CollectState) -> HashSet<DeclarationId>
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut scope_nodes: HashMap<ScopeId, (Vec<DeclarationId>, bool)> = state
|
||||
let mut scope_nodes: FxHashMap<ScopeId, (Vec<DeclarationId>, bool)> = state
|
||||
.scopes
|
||||
.iter()
|
||||
.map(|(id, node)| (*id, (node.dependencies.clone(), node.seen)))
|
||||
@@ -1088,18 +1087,18 @@ fn compute_memoized_identifiers(state: &CollectState) -> HashSet<DeclarationId>
|
||||
fn visit(
|
||||
id: DeclarationId,
|
||||
force_memoize: bool,
|
||||
identifier_nodes: &mut HashMap<
|
||||
identifier_nodes: &mut FxHashMap<
|
||||
DeclarationId,
|
||||
(
|
||||
MemoizationLevel,
|
||||
bool,
|
||||
IndexSet<DeclarationId>,
|
||||
IndexSet<ScopeId>,
|
||||
IndexSet<DeclarationId, FxBuildHasher>,
|
||||
IndexSet<ScopeId, FxBuildHasher>,
|
||||
bool,
|
||||
),
|
||||
>,
|
||||
scope_nodes: &mut HashMap<ScopeId, (Vec<DeclarationId>, bool)>,
|
||||
memoized: &mut HashSet<DeclarationId>,
|
||||
scope_nodes: &mut FxHashMap<ScopeId, (Vec<DeclarationId>, bool)>,
|
||||
memoized: &mut FxHashSet<DeclarationId>,
|
||||
) -> bool {
|
||||
let Some(&(level, _, _, _, seen)) = identifier_nodes.get(&id) else {
|
||||
return false;
|
||||
@@ -1149,18 +1148,18 @@ fn compute_memoized_identifiers(state: &CollectState) -> HashSet<DeclarationId>
|
||||
|
||||
fn force_memoize_scope_dependencies(
|
||||
id: ScopeId,
|
||||
identifier_nodes: &mut HashMap<
|
||||
identifier_nodes: &mut FxHashMap<
|
||||
DeclarationId,
|
||||
(
|
||||
MemoizationLevel,
|
||||
bool,
|
||||
IndexSet<DeclarationId>,
|
||||
IndexSet<ScopeId>,
|
||||
IndexSet<DeclarationId, FxBuildHasher>,
|
||||
IndexSet<ScopeId, FxBuildHasher>,
|
||||
bool,
|
||||
),
|
||||
>,
|
||||
scope_nodes: &mut HashMap<ScopeId, (Vec<DeclarationId>, bool)>,
|
||||
memoized: &mut HashSet<DeclarationId>,
|
||||
scope_nodes: &mut FxHashMap<ScopeId, (Vec<DeclarationId>, bool)>,
|
||||
memoized: &mut FxHashSet<DeclarationId>,
|
||||
) {
|
||||
let seen = scope_nodes
|
||||
.get(&id)
|
||||
@@ -1198,12 +1197,12 @@ fn compute_memoized_identifiers(state: &CollectState) -> HashSet<DeclarationId>
|
||||
|
||||
struct PruneScopesTransform<'a> {
|
||||
env: &'a Environment,
|
||||
pruned_scopes: HashSet<ScopeId>,
|
||||
reassignments: HashMap<DeclarationId, HashSet<IdentifierId>>,
|
||||
pruned_scopes: FxHashSet<ScopeId>,
|
||||
reassignments: FxHashMap<DeclarationId, FxHashSet<IdentifierId>>,
|
||||
}
|
||||
|
||||
impl<'a> ReactiveFunctionTransform for PruneScopesTransform<'a> {
|
||||
type State = HashSet<DeclarationId>;
|
||||
type State = FxHashSet<DeclarationId>;
|
||||
|
||||
fn env(&self) -> &Environment {
|
||||
self.env
|
||||
@@ -1212,7 +1211,7 @@ impl<'a> ReactiveFunctionTransform for PruneScopesTransform<'a> {
|
||||
fn transform_scope(
|
||||
&mut self,
|
||||
scope: &mut ReactiveScopeBlock,
|
||||
state: &mut HashSet<DeclarationId>,
|
||||
state: &mut FxHashSet<DeclarationId>,
|
||||
) -> Result<Transformed<ReactiveStatement>, react_compiler_diagnostics::CompilerError> {
|
||||
self.visit_scope(scope, state)?;
|
||||
|
||||
@@ -1248,7 +1247,7 @@ impl<'a> ReactiveFunctionTransform for PruneScopesTransform<'a> {
|
||||
fn transform_instruction(
|
||||
&mut self,
|
||||
instruction: &mut ReactiveInstruction,
|
||||
state: &mut HashSet<DeclarationId>,
|
||||
state: &mut FxHashSet<DeclarationId>,
|
||||
) -> Result<Transformed<ReactiveStatement>, react_compiler_diagnostics::CompilerError> {
|
||||
self.traverse_instruction(instruction, state)?;
|
||||
|
||||
@@ -1263,7 +1262,7 @@ impl<'a> ReactiveFunctionTransform for PruneScopesTransform<'a> {
|
||||
let ids = self
|
||||
.reassignments
|
||||
.entry(decl_id)
|
||||
.or_insert_with(HashSet::new);
|
||||
.or_insert_with(FxHashSet::default);
|
||||
ids.insert(store_value.identifier);
|
||||
}
|
||||
ReactiveValue::Instruction(InstructionValue::LoadLocal { place, .. }) => {
|
||||
@@ -1285,7 +1284,7 @@ impl<'a> ReactiveFunctionTransform for PruneScopesTransform<'a> {
|
||||
let ids = self
|
||||
.reassignments
|
||||
.entry(decl_id)
|
||||
.or_insert_with(HashSet::new);
|
||||
.or_insert_with(FxHashSet::default);
|
||||
ids.insert(place.identifier);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -8,7 +8,7 @@
|
||||
//! Corresponds to `src/ReactiveScopes/PruneNonReactiveDependencies.ts`
|
||||
//! and `src/ReactiveScopes/CollectReactiveIdentifiers.ts`.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use react_compiler_hir::{
|
||||
EvaluationOrder, IdentifierId, InstructionValue, Place, PrunedReactiveScopeBlock,
|
||||
@@ -28,9 +28,9 @@ use crate::visitors::{self, ReactiveFunctionTransform, ReactiveFunctionVisitor};
|
||||
pub fn collect_reactive_identifiers(
|
||||
func: &ReactiveFunction,
|
||||
env: &Environment,
|
||||
) -> HashSet<IdentifierId> {
|
||||
) -> FxHashSet<IdentifierId> {
|
||||
let visitor = CollectVisitor { env };
|
||||
let mut state = HashSet::new();
|
||||
let mut state = FxHashSet::default();
|
||||
crate::visitors::visit_reactive_function(func, &visitor, &mut state);
|
||||
state
|
||||
}
|
||||
@@ -40,7 +40,7 @@ struct CollectVisitor<'a> {
|
||||
}
|
||||
|
||||
impl<'a> ReactiveFunctionVisitor for CollectVisitor<'a> {
|
||||
type State = HashSet<IdentifierId>;
|
||||
type State = FxHashSet<IdentifierId>;
|
||||
|
||||
fn env(&self) -> &Environment {
|
||||
self.env
|
||||
@@ -74,7 +74,7 @@ impl<'a> ReactiveFunctionVisitor for CollectVisitor<'a> {
|
||||
/// TS: `isStableRefType`
|
||||
fn is_stable_ref_type(
|
||||
ty: &react_compiler_hir::Type,
|
||||
reactive_identifiers: &HashSet<IdentifierId>,
|
||||
reactive_identifiers: &FxHashSet<IdentifierId>,
|
||||
id: IdentifierId,
|
||||
) -> bool {
|
||||
is_use_ref_type(ty) && !reactive_identifiers.contains(&id)
|
||||
@@ -133,7 +133,7 @@ struct PruneVisitor<'a> {
|
||||
}
|
||||
|
||||
impl<'a> ReactiveFunctionTransform for PruneVisitor<'a> {
|
||||
type State = HashSet<IdentifierId>;
|
||||
type State = FxHashSet<IdentifierId>;
|
||||
|
||||
fn env(&self) -> &Environment {
|
||||
self.env
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//!
|
||||
//! Corresponds to `src/ReactiveScopes/PruneUnusedLabels.ts`.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use react_compiler_hir::{
|
||||
BlockId, ReactiveFunction, ReactiveStatement, ReactiveTerminal, ReactiveTerminalStatement,
|
||||
@@ -23,7 +23,7 @@ pub fn prune_unused_labels(
|
||||
env: &Environment,
|
||||
) -> Result<(), react_compiler_diagnostics::CompilerError> {
|
||||
let mut transform = Transform { env };
|
||||
let mut labels: HashSet<BlockId> = HashSet::new();
|
||||
let mut labels: FxHashSet<BlockId> = FxHashSet::default();
|
||||
transform_reactive_function(func, &mut transform, &mut labels)
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ struct Transform<'a> {
|
||||
}
|
||||
|
||||
impl<'a> ReactiveFunctionTransform for Transform<'a> {
|
||||
type State = HashSet<BlockId>;
|
||||
type State = FxHashSet<BlockId>;
|
||||
|
||||
fn env(&self) -> &Environment {
|
||||
self.env
|
||||
@@ -41,7 +41,7 @@ impl<'a> ReactiveFunctionTransform for Transform<'a> {
|
||||
fn transform_terminal(
|
||||
&mut self,
|
||||
stmt: &mut ReactiveTerminalStatement,
|
||||
state: &mut HashSet<BlockId>,
|
||||
state: &mut FxHashSet<BlockId>,
|
||||
) -> Result<Transformed<ReactiveStatement>, react_compiler_diagnostics::CompilerError> {
|
||||
// Traverse children first
|
||||
self.traverse_terminal(stmt, state)?;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
//!
|
||||
//! Corresponds to `src/ReactiveScopes/PruneTemporaryLValues.ts`.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use react_compiler_hir::{
|
||||
DeclarationId, EvaluationOrder, Place, ReactiveFunction, ReactiveInstruction,
|
||||
@@ -34,7 +34,7 @@ pub fn prune_unused_lvalues(func: &mut ReactiveFunction, env: &Environment) {
|
||||
// When we see an unnamed lvalue on an instruction, we add its DeclarationId.
|
||||
// When we see a place reference (operand), we remove its DeclarationId.
|
||||
let visitor = Visitor { env };
|
||||
let mut lvalues: HashSet<DeclarationId> = HashSet::new();
|
||||
let mut lvalues: FxHashSet<DeclarationId> = FxHashSet::default();
|
||||
visitors::visit_reactive_function(func, &visitor, &mut lvalues);
|
||||
|
||||
// Phase 2: Null out lvalues whose DeclarationId remains in the map.
|
||||
@@ -48,7 +48,7 @@ pub fn prune_unused_lvalues(func: &mut ReactiveFunction, env: &Environment) {
|
||||
/// TS: `type LValues = Map<DeclarationId, ReactiveInstruction>`
|
||||
/// In Rust, we only need the set of DeclarationIds (not the instruction refs)
|
||||
/// because we apply changes in a separate pass.
|
||||
type LValues = HashSet<DeclarationId>;
|
||||
type LValues = FxHashSet<DeclarationId>;
|
||||
|
||||
/// TS: `class Visitor extends ReactiveFunctionVisitor<LValues>`
|
||||
struct Visitor<'a> {
|
||||
@@ -87,7 +87,7 @@ impl ReactiveFunctionVisitor for Visitor<'_> {
|
||||
fn null_unused_lvalues(
|
||||
block: &mut Vec<ReactiveStatement>,
|
||||
env: &Environment,
|
||||
unused: &HashSet<DeclarationId>,
|
||||
unused: &FxHashSet<DeclarationId>,
|
||||
) {
|
||||
for stmt in block.iter_mut() {
|
||||
match stmt {
|
||||
@@ -110,7 +110,7 @@ fn null_unused_lvalues(
|
||||
fn null_unused_in_instruction(
|
||||
instr: &mut ReactiveInstruction,
|
||||
env: &Environment,
|
||||
unused: &HashSet<DeclarationId>,
|
||||
unused: &FxHashSet<DeclarationId>,
|
||||
) {
|
||||
if let Some(lv) = &instr.lvalue {
|
||||
let ident = &env.identifiers[lv.identifier.0 as usize];
|
||||
@@ -124,7 +124,7 @@ fn null_unused_in_instruction(
|
||||
fn null_unused_in_value(
|
||||
value: &mut ReactiveValue,
|
||||
env: &Environment,
|
||||
unused: &HashSet<DeclarationId>,
|
||||
unused: &FxHashSet<DeclarationId>,
|
||||
) {
|
||||
match value {
|
||||
ReactiveValue::SequenceExpression {
|
||||
@@ -161,7 +161,7 @@ fn null_unused_in_value(
|
||||
fn null_unused_in_terminal(
|
||||
terminal: &mut react_compiler_hir::ReactiveTerminal,
|
||||
env: &Environment,
|
||||
unused: &HashSet<DeclarationId>,
|
||||
unused: &FxHashSet<DeclarationId>,
|
||||
) {
|
||||
use react_compiler_hir::ReactiveTerminal;
|
||||
match terminal {
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
//!
|
||||
//! Corresponds to `src/ReactiveScopes/RenameVariables.ts`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_hir::DeclarationId;
|
||||
use react_compiler_hir::EvaluationOrder;
|
||||
@@ -33,19 +32,19 @@ use crate::visitors::{self};
|
||||
// =============================================================================
|
||||
|
||||
struct Scopes {
|
||||
seen: HashMap<DeclarationId, IdentifierName>,
|
||||
stack: Vec<HashMap<String, DeclarationId>>,
|
||||
globals: HashSet<String>,
|
||||
names: HashSet<String>,
|
||||
seen: FxHashMap<DeclarationId, IdentifierName>,
|
||||
stack: Vec<FxHashMap<String, DeclarationId>>,
|
||||
globals: FxHashSet<String>,
|
||||
names: FxHashSet<String>,
|
||||
}
|
||||
|
||||
impl Scopes {
|
||||
fn new(globals: HashSet<String>) -> Self {
|
||||
fn new(globals: FxHashSet<String>) -> Self {
|
||||
Self {
|
||||
seen: HashMap::new(),
|
||||
stack: vec![HashMap::new()],
|
||||
seen: FxHashMap::default(),
|
||||
stack: vec![FxHashMap::default()],
|
||||
globals,
|
||||
names: HashSet::new(),
|
||||
names: FxHashSet::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +113,7 @@ impl Scopes {
|
||||
}
|
||||
|
||||
fn enter(&mut self) {
|
||||
self.stack.push(HashMap::new());
|
||||
self.stack.push(FxHashMap::default());
|
||||
}
|
||||
|
||||
fn leave(&mut self) {
|
||||
@@ -202,15 +201,15 @@ impl ReactiveFunctionVisitor for Visitor<'_> {
|
||||
/// Renames variables for output — assigns unique names, handles SSA renames.
|
||||
/// Returns a Set of all unique variable names used.
|
||||
/// TS: `renameVariables`
|
||||
pub fn rename_variables(func: &mut ReactiveFunction, env: &mut Environment) -> HashSet<String> {
|
||||
pub fn rename_variables(func: &mut ReactiveFunction, env: &mut Environment) -> FxHashSet<String> {
|
||||
rename_variables_with_parent(func, env, None)
|
||||
}
|
||||
|
||||
fn rename_variables_with_parent(
|
||||
func: &mut ReactiveFunction,
|
||||
env: &mut Environment,
|
||||
parent_names: Option<&HashSet<String>>,
|
||||
) -> HashSet<String> {
|
||||
parent_names: Option<&FxHashSet<String>>,
|
||||
) -> FxHashSet<String> {
|
||||
let globals = collect_referenced_globals(&func.body, env);
|
||||
|
||||
// Phase 1: Use ReactiveFunctionVisitor to compute the rename mapping.
|
||||
@@ -242,7 +241,7 @@ fn rename_variables_with_parent(
|
||||
}
|
||||
}
|
||||
|
||||
let mut result: HashSet<String> = scopes.names;
|
||||
let mut result: FxHashSet<String> = scopes.names;
|
||||
result.extend(globals);
|
||||
result
|
||||
}
|
||||
@@ -267,13 +266,17 @@ fn rename_variables_impl(func: &ReactiveFunction, visitor: &Visitor, scopes: &mu
|
||||
|
||||
/// Collects all globally referenced names from the reactive function.
|
||||
/// TS: `collectReferencedGlobals`
|
||||
fn collect_referenced_globals(block: &ReactiveBlock, env: &Environment) -> HashSet<String> {
|
||||
let mut globals = HashSet::new();
|
||||
fn collect_referenced_globals(block: &ReactiveBlock, env: &Environment) -> FxHashSet<String> {
|
||||
let mut globals = FxHashSet::default();
|
||||
collect_globals_block(block, &mut globals, env);
|
||||
globals
|
||||
}
|
||||
|
||||
fn collect_globals_block(block: &ReactiveBlock, globals: &mut HashSet<String>, env: &Environment) {
|
||||
fn collect_globals_block(
|
||||
block: &ReactiveBlock,
|
||||
globals: &mut FxHashSet<String>,
|
||||
env: &Environment,
|
||||
) {
|
||||
for stmt in block {
|
||||
match stmt {
|
||||
react_compiler_hir::ReactiveStatement::Instruction(instr) => {
|
||||
@@ -292,7 +295,11 @@ fn collect_globals_block(block: &ReactiveBlock, globals: &mut HashSet<String>, e
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_globals_value(value: &ReactiveValue, globals: &mut HashSet<String>, env: &Environment) {
|
||||
fn collect_globals_value(
|
||||
value: &ReactiveValue,
|
||||
globals: &mut FxHashSet<String>,
|
||||
env: &Environment,
|
||||
) {
|
||||
match value {
|
||||
ReactiveValue::Instruction(iv) => {
|
||||
if let InstructionValue::LoadGlobal { binding, .. } = iv {
|
||||
@@ -340,7 +347,7 @@ fn collect_globals_value(value: &ReactiveValue, globals: &mut HashSet<String>, e
|
||||
/// Recursively collects LoadGlobal names from an inner HIR function.
|
||||
fn collect_globals_hir_function(
|
||||
func_id: FunctionId,
|
||||
globals: &mut HashSet<String>,
|
||||
globals: &mut FxHashSet<String>,
|
||||
env: &Environment,
|
||||
) {
|
||||
let inner_func = &env.functions[func_id.0 as usize];
|
||||
@@ -367,7 +374,7 @@ fn collect_globals_hir_function(
|
||||
|
||||
fn collect_globals_terminal(
|
||||
stmt: &react_compiler_hir::ReactiveTerminalStatement,
|
||||
globals: &mut HashSet<String>,
|
||||
globals: &mut FxHashSet<String>,
|
||||
env: &Environment,
|
||||
) {
|
||||
match &stmt.terminal {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
//!
|
||||
//! Corresponds to `src/ReactiveScopes/StabilizeBlockIds.ts`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap};
|
||||
|
||||
use indexmap::IndexSet;
|
||||
use react_compiler_hir::{
|
||||
@@ -27,12 +27,12 @@ use crate::visitors::{
|
||||
/// TS: `stabilizeBlockIds`
|
||||
pub fn stabilize_block_ids(func: &mut ReactiveFunction, env: &mut Environment) {
|
||||
// Pass 1: Collect referenced labels (preserving insertion order to match TS Set behavior)
|
||||
let mut referenced: IndexSet<BlockId> = IndexSet::new();
|
||||
let mut referenced: IndexSet<BlockId, FxBuildHasher> = IndexSet::default();
|
||||
let collector = CollectReferencedLabels { env: &*env };
|
||||
visit_reactive_function(func, &collector, &mut referenced);
|
||||
|
||||
// Build mappings: referenced block IDs -> sequential IDs (insertion-order deterministic)
|
||||
let mut mappings: HashMap<BlockId, BlockId> = HashMap::new();
|
||||
let mut mappings: FxHashMap<BlockId, BlockId> = FxHashMap::default();
|
||||
for block_id in &referenced {
|
||||
let len = mappings.len() as u32;
|
||||
mappings.entry(*block_id).or_insert(BlockId(len));
|
||||
@@ -52,7 +52,7 @@ struct CollectReferencedLabels<'a> {
|
||||
}
|
||||
|
||||
impl<'a> ReactiveFunctionVisitor for CollectReferencedLabels<'a> {
|
||||
type State = IndexSet<BlockId>;
|
||||
type State = IndexSet<BlockId, FxBuildHasher>;
|
||||
|
||||
fn env(&self) -> &Environment {
|
||||
self.env
|
||||
@@ -80,7 +80,7 @@ impl<'a> ReactiveFunctionVisitor for CollectReferencedLabels<'a> {
|
||||
// Pass 2: RewriteBlockIds
|
||||
// =============================================================================
|
||||
|
||||
fn get_or_insert_mapping(mappings: &mut HashMap<BlockId, BlockId>, id: BlockId) -> BlockId {
|
||||
fn get_or_insert_mapping(mappings: &mut FxHashMap<BlockId, BlockId>, id: BlockId) -> BlockId {
|
||||
let len = mappings.len() as u32;
|
||||
*mappings.entry(id).or_insert(BlockId(len))
|
||||
}
|
||||
@@ -91,7 +91,7 @@ struct RewriteBlockIds<'a> {
|
||||
}
|
||||
|
||||
impl<'a> ReactiveFunctionTransform for RewriteBlockIds<'a> {
|
||||
type State = HashMap<BlockId, BlockId>;
|
||||
type State = FxHashMap<BlockId, BlockId>;
|
||||
|
||||
fn env(&self) -> &Environment {
|
||||
self.env
|
||||
|
||||
@@ -7,3 +7,4 @@ edition = "2024"
|
||||
react_compiler_diagnostics = { path = "../react_compiler_diagnostics" }
|
||||
react_compiler_hir = { path = "../react_compiler_hir" }
|
||||
indexmap = "2"
|
||||
rustc-hash = "2"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_hir::environment::Environment;
|
||||
use react_compiler_hir::visitors;
|
||||
@@ -10,7 +10,7 @@ use crate::enter_ssa::placeholder_function;
|
||||
// Helper: rewrite_place
|
||||
// =============================================================================
|
||||
|
||||
fn rewrite_place(place: &mut Place, rewrites: &HashMap<IdentifierId, IdentifierId>) {
|
||||
fn rewrite_place(place: &mut Place, rewrites: &FxHashMap<IdentifierId, IdentifierId>) {
|
||||
if let Some(&rewrite) = rewrites.get(&place.identifier) {
|
||||
place.identifier = rewrite;
|
||||
}
|
||||
@@ -21,7 +21,7 @@ fn rewrite_place(place: &mut Place, rewrites: &HashMap<IdentifierId, IdentifierI
|
||||
// =============================================================================
|
||||
|
||||
pub fn eliminate_redundant_phi(func: &mut HirFunction, env: &mut Environment) {
|
||||
let mut rewrites: HashMap<IdentifierId, IdentifierId> = HashMap::new();
|
||||
let mut rewrites: FxHashMap<IdentifierId, IdentifierId> = FxHashMap::default();
|
||||
eliminate_redundant_phi_impl(func, env, &mut rewrites);
|
||||
}
|
||||
|
||||
@@ -32,12 +32,12 @@ pub fn eliminate_redundant_phi(func: &mut HirFunction, env: &mut Environment) {
|
||||
fn eliminate_redundant_phi_impl(
|
||||
func: &mut HirFunction,
|
||||
env: &mut Environment,
|
||||
rewrites: &mut HashMap<IdentifierId, IdentifierId>,
|
||||
rewrites: &mut FxHashMap<IdentifierId, IdentifierId>,
|
||||
) {
|
||||
let ir = &mut func.body;
|
||||
|
||||
let mut has_back_edge = false;
|
||||
let mut visited: HashSet<BlockId> = HashSet::new();
|
||||
let mut visited: FxHashSet<BlockId> = FxHashSet::default();
|
||||
|
||||
let mut size;
|
||||
loop {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use react_compiler_diagnostics::{CompilerDiagnostic, CompilerDiagnosticDetail, ErrorCategory};
|
||||
@@ -16,35 +16,35 @@ struct IncompletePhi {
|
||||
}
|
||||
|
||||
struct State {
|
||||
defs: HashMap<IdentifierId, IdentifierId>,
|
||||
defs: FxHashMap<IdentifierId, IdentifierId>,
|
||||
incomplete_phis: Vec<IncompletePhi>,
|
||||
}
|
||||
|
||||
struct SSABuilder {
|
||||
states: HashMap<BlockId, State>,
|
||||
states: FxHashMap<BlockId, State>,
|
||||
current: Option<BlockId>,
|
||||
unsealed_preds: HashMap<BlockId, u32>,
|
||||
block_preds: HashMap<BlockId, Vec<BlockId>>,
|
||||
unknown: HashSet<IdentifierId>,
|
||||
context: HashSet<IdentifierId>,
|
||||
pending_phis: HashMap<BlockId, Vec<Phi>>,
|
||||
unsealed_preds: FxHashMap<BlockId, u32>,
|
||||
block_preds: FxHashMap<BlockId, Vec<BlockId>>,
|
||||
unknown: FxHashSet<IdentifierId>,
|
||||
context: FxHashSet<IdentifierId>,
|
||||
pending_phis: FxHashMap<BlockId, Vec<Phi>>,
|
||||
processed_functions: Vec<FunctionId>,
|
||||
}
|
||||
|
||||
impl SSABuilder {
|
||||
fn new(blocks: &IndexMap<BlockId, BasicBlock>) -> Self {
|
||||
let mut block_preds = HashMap::new();
|
||||
fn new(blocks: &IndexMap<BlockId, BasicBlock, FxBuildHasher>) -> Self {
|
||||
let mut block_preds = FxHashMap::default();
|
||||
for (id, block) in blocks {
|
||||
block_preds.insert(*id, block.preds.iter().copied().collect());
|
||||
}
|
||||
SSABuilder {
|
||||
states: HashMap::new(),
|
||||
states: FxHashMap::default(),
|
||||
current: None,
|
||||
unsealed_preds: HashMap::new(),
|
||||
unsealed_preds: FxHashMap::default(),
|
||||
block_preds,
|
||||
unknown: HashSet::new(),
|
||||
context: HashSet::new(),
|
||||
pending_phis: HashMap::new(),
|
||||
unknown: FxHashSet::default(),
|
||||
context: FxHashSet::default(),
|
||||
pending_phis: FxHashMap::default(),
|
||||
processed_functions: Vec::new(),
|
||||
}
|
||||
}
|
||||
@@ -226,7 +226,7 @@ impl SSABuilder {
|
||||
) {
|
||||
let preds = self.block_preds.get(&block_id).cloned().unwrap_or_default();
|
||||
|
||||
let mut pred_defs: IndexMap<BlockId, Place> = IndexMap::new();
|
||||
let mut pred_defs: IndexMap<BlockId, Place, FxBuildHasher> = IndexMap::default();
|
||||
for pred_block_id in &preds {
|
||||
let pred_id = self.get_id_at(old_place, *pred_block_id, env);
|
||||
pred_defs.insert(
|
||||
@@ -266,7 +266,7 @@ impl SSABuilder {
|
||||
self.states.insert(
|
||||
block_id,
|
||||
State {
|
||||
defs: HashMap::new(),
|
||||
defs: FxHashMap::default(),
|
||||
incomplete_phis: Vec::new(),
|
||||
},
|
||||
);
|
||||
@@ -310,7 +310,7 @@ fn enter_ssa_impl(
|
||||
env: &mut Environment,
|
||||
root_entry: BlockId,
|
||||
) -> Result<(), CompilerDiagnostic> {
|
||||
let mut visited_blocks: HashSet<BlockId> = HashSet::new();
|
||||
let mut visited_blocks: FxHashSet<BlockId> = FxHashSet::default();
|
||||
let block_ids: Vec<BlockId> = func.body.blocks.keys().copied().collect();
|
||||
|
||||
for block_id in &block_ids {
|
||||
@@ -520,7 +520,7 @@ pub fn placeholder_function() -> HirFunction {
|
||||
context: Vec::new(),
|
||||
body: HIR {
|
||||
entry: BlockId(0),
|
||||
blocks: IndexMap::new(),
|
||||
blocks: IndexMap::default(),
|
||||
},
|
||||
instructions: Vec::new(),
|
||||
generator: false,
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@
|
||||
//! may be converted to a `const` if the reassignment is not used and was removed
|
||||
//! by dead code elimination.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use react_compiler_diagnostics::{
|
||||
CompilerDiagnostic, CompilerDiagnosticDetail, CompilerError, ErrorCategory, SourceLocation,
|
||||
@@ -115,7 +115,7 @@ pub fn rewrite_instruction_kinds_based_on_reassignment(
|
||||
//
|
||||
// Track: for each DeclarationId, the location of its first declaration,
|
||||
// and whether it needs to be changed to Let (because of reassignment).
|
||||
let mut declarations: HashMap<DeclarationId, DeclarationLoc> = HashMap::new();
|
||||
let mut declarations: FxHashMap<DeclarationId, DeclarationLoc> = FxHashMap::default();
|
||||
// Track which (block_index, instr_local_index) should have their lvalue.kind set to Reassign
|
||||
let mut reassign_locs: Vec<(usize, usize)> = Vec::new();
|
||||
// Track which declaration locations need to be set to Let
|
||||
|
||||
@@ -4,6 +4,7 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
rustc-hash = "2"
|
||||
react_compiler_diagnostics = { path = "../react_compiler_diagnostics" }
|
||||
react_compiler_hir = { path = "../react_compiler_hir" }
|
||||
react_compiler_ssa = { path = "../react_compiler_ssa" }
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//! Generates type equations from the HIR, unifies them, and applies the
|
||||
//! resolved types back to identifiers. Analogous to TS `InferTypes.ts`.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use react_compiler_diagnostics::{CompilerDiagnostic, ErrorCategory};
|
||||
use react_compiler_hir::environment::{Environment, is_hook_name};
|
||||
@@ -79,7 +79,7 @@ fn pre_resolve_globals(
|
||||
func: &HirFunction,
|
||||
function_key: u32,
|
||||
env: &mut Environment,
|
||||
global_types: &mut HashMap<(u32, InstructionId), Type>,
|
||||
global_types: &mut FxHashMap<(u32, InstructionId), Type>,
|
||||
) {
|
||||
for &instr_id in func.body.blocks.values().flat_map(|b| &b.instructions) {
|
||||
let instr = &func.instructions[instr_id.0 as usize];
|
||||
@@ -95,7 +95,7 @@ fn pre_resolve_globals(
|
||||
fn pre_resolve_globals_recursive(
|
||||
func_id: FunctionId,
|
||||
env: &mut Environment,
|
||||
global_types: &mut HashMap<(u32, InstructionId), Type>,
|
||||
global_types: &mut FxHashMap<(u32, InstructionId), Type>,
|
||||
) {
|
||||
// Collect LoadGlobal bindings and child function IDs in one pass to avoid
|
||||
// borrow conflicts (we need &env.functions to read, then &mut env for
|
||||
@@ -277,13 +277,13 @@ fn type_equals(a: &Type, b: &Type) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_name(names: &mut HashMap<IdentifierId, String>, id: IdentifierId, source: &Identifier) {
|
||||
fn set_name(names: &mut FxHashMap<IdentifierId, String>, id: IdentifierId, source: &Identifier) {
|
||||
if let Some(IdentifierName::Named(ref name)) = source.name {
|
||||
names.insert(id, name.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn get_name(names: &HashMap<IdentifierId, String>, id: IdentifierId) -> String {
|
||||
fn get_name(names: &FxHashMap<IdentifierId, String>, id: IdentifierId) -> String {
|
||||
names.get(&id).cloned().unwrap_or_default()
|
||||
}
|
||||
|
||||
@@ -335,7 +335,7 @@ fn generate(
|
||||
// &mut env, but generate_instruction_types takes split borrows on env fields.
|
||||
// The key is (function_key, InstructionId) where function_key is u32::MAX
|
||||
// for the outer function and FunctionId.0 for inner functions.
|
||||
let mut global_types: HashMap<(u32, InstructionId), Type> = HashMap::new();
|
||||
let mut global_types: FxHashMap<(u32, InstructionId), Type> = FxHashMap::default();
|
||||
pre_resolve_globals(func, u32::MAX, env, &mut global_types);
|
||||
// Also pre-resolve inner functions recursively
|
||||
for &instr_id in func.body.blocks.values().flat_map(|b| &b.instructions) {
|
||||
@@ -355,7 +355,7 @@ fn generate(
|
||||
}
|
||||
}
|
||||
|
||||
let mut names: HashMap<IdentifierId, String> = HashMap::new();
|
||||
let mut names: FxHashMap<IdentifierId, String> = FxHashMap::default();
|
||||
let mut return_types: Vec<Type> = Vec::new();
|
||||
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
@@ -420,7 +420,7 @@ fn generate_for_function_id(
|
||||
identifiers: &[Identifier],
|
||||
types: &mut Vec<Type>,
|
||||
functions: &mut Vec<HirFunction>,
|
||||
global_types: &HashMap<(u32, InstructionId), Type>,
|
||||
global_types: &FxHashMap<(u32, InstructionId), Type>,
|
||||
shapes: &ShapeRegistry,
|
||||
unifier: &mut Unifier,
|
||||
) -> Result<(), CompilerDiagnostic> {
|
||||
@@ -457,7 +457,7 @@ fn generate_for_function_id(
|
||||
|
||||
// TS creates a fresh `names` Map per recursive `generate` call, so inner
|
||||
// functions don't inherit or pollute the outer function's name mappings.
|
||||
let mut inner_names: HashMap<IdentifierId, String> = HashMap::new();
|
||||
let mut inner_names: FxHashMap<IdentifierId, String> = FxHashMap::default();
|
||||
let mut inner_return_types: Vec<Type> = Vec::new();
|
||||
|
||||
for (_block_id, block) in &inner.body.blocks {
|
||||
@@ -521,8 +521,8 @@ fn generate_instruction_types(
|
||||
identifiers: &[Identifier],
|
||||
types: &mut Vec<Type>,
|
||||
functions: &mut Vec<HirFunction>,
|
||||
names: &mut HashMap<IdentifierId, String>,
|
||||
global_types: &HashMap<(u32, InstructionId), Type>,
|
||||
names: &mut FxHashMap<IdentifierId, String>,
|
||||
global_types: &FxHashMap<(u32, InstructionId), Type>,
|
||||
shapes: &ShapeRegistry,
|
||||
unifier: &mut Unifier,
|
||||
) -> Result<(), CompilerDiagnostic> {
|
||||
@@ -1304,7 +1304,7 @@ fn apply_instruction_operands(
|
||||
// =============================================================================
|
||||
|
||||
struct Unifier {
|
||||
substitutions: HashMap<TypeId, Type>,
|
||||
substitutions: FxHashMap<TypeId, Type>,
|
||||
enable_treat_ref_like_identifiers_as_refs: bool,
|
||||
enable_treat_set_identifiers_as_state_setters: bool,
|
||||
custom_hook_type: Option<Type>,
|
||||
@@ -1317,7 +1317,7 @@ impl Unifier {
|
||||
enable_treat_set_identifiers_as_state_setters: bool,
|
||||
) -> Self {
|
||||
Unifier {
|
||||
substitutions: HashMap::new(),
|
||||
substitutions: FxHashMap::default(),
|
||||
enable_treat_ref_like_identifiers_as_refs,
|
||||
enable_treat_set_identifiers_as_state_setters,
|
||||
custom_hook_type,
|
||||
|
||||
@@ -5,3 +5,4 @@ edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
indexmap = "2"
|
||||
rustc-hash = "2"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//!
|
||||
//! Ported from TypeScript `src/Utils/DisjointSet.ts`.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::{FxBuildHasher, FxHashSet};
|
||||
use std::hash::Hash;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
@@ -17,13 +17,13 @@ use indexmap::IndexMap;
|
||||
/// Corresponds to TS `DisjointSet<T>` in `src/Utils/DisjointSet.ts`.
|
||||
/// Uses `IndexMap` to preserve insertion order (matching TS `Map` behavior).
|
||||
pub struct DisjointSet<K: Copy + Eq + Hash> {
|
||||
entries: IndexMap<K, K>,
|
||||
entries: IndexMap<K, K, FxBuildHasher>,
|
||||
}
|
||||
|
||||
impl<K: Copy + Eq + Hash> DisjointSet<K> {
|
||||
pub fn new() -> Self {
|
||||
DisjointSet {
|
||||
entries: IndexMap::new(),
|
||||
entries: IndexMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,8 +87,8 @@ impl<K: Copy + Eq + Hash> DisjointSet<K> {
|
||||
/// root) and returns a map of items to their roots.
|
||||
///
|
||||
/// Corresponds to TS `canonicalize(): Map<T, T>`.
|
||||
pub fn canonicalize(&mut self) -> IndexMap<K, K> {
|
||||
let mut result = IndexMap::new();
|
||||
pub fn canonicalize(&mut self) -> IndexMap<K, K, FxBuildHasher> {
|
||||
let mut result = IndexMap::default();
|
||||
let keys: Vec<K> = self.entries.keys().copied().collect();
|
||||
for item in keys {
|
||||
let root = self.find(item);
|
||||
@@ -115,9 +115,9 @@ impl<K: Copy + Eq + Hash> DisjointSet<K> {
|
||||
/// Groups all items by their root and returns the groups as a list of sets.
|
||||
///
|
||||
/// Corresponds to TS `buildSets(): Array<Set<T>>`.
|
||||
pub fn build_sets(&mut self) -> Vec<HashSet<K>> {
|
||||
let mut group_to_index: IndexMap<K, usize> = IndexMap::new();
|
||||
let mut sets: Vec<HashSet<K>> = Vec::new();
|
||||
pub fn build_sets(&mut self) -> Vec<FxHashSet<K>> {
|
||||
let mut group_to_index: IndexMap<K, usize, FxBuildHasher> = IndexMap::default();
|
||||
let mut sets: Vec<FxHashSet<K>> = Vec::new();
|
||||
let keys: Vec<K> = self.entries.keys().copied().collect();
|
||||
for item in keys {
|
||||
let group = self.find(item);
|
||||
@@ -126,7 +126,7 @@ impl<K: Copy + Eq + Hash> DisjointSet<K> {
|
||||
None => {
|
||||
let idx = sets.len();
|
||||
group_to_index.insert(group, idx);
|
||||
sets.push(HashSet::new());
|
||||
sets.push(FxHashSet::default());
|
||||
idx
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,5 +5,6 @@ edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
indexmap = "2"
|
||||
rustc-hash = "2"
|
||||
react_compiler_diagnostics = { path = "../react_compiler_diagnostics" }
|
||||
react_compiler_hir = { path = "../react_compiler_hir" }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use react_compiler_diagnostics::{
|
||||
CompilerDiagnostic, CompilerDiagnosticDetail, CompilerError, ErrorCategory,
|
||||
@@ -27,7 +27,7 @@ impl std::fmt::Display for VarRefKind {
|
||||
}
|
||||
}
|
||||
|
||||
type IdentifierKinds = HashMap<IdentifierId, (Place, VarRefKind)>;
|
||||
type IdentifierKinds = FxHashMap<IdentifierId, (Place, VarRefKind)>;
|
||||
|
||||
/// Validates that context variable lvalues are used consistently.
|
||||
///
|
||||
@@ -53,7 +53,7 @@ pub fn validate_context_variable_lvalues_with_errors(
|
||||
identifiers: &[Identifier],
|
||||
errors: &mut CompilerError,
|
||||
) -> Result<(), CompilerDiagnostic> {
|
||||
let mut identifier_kinds: IdentifierKinds = HashMap::new();
|
||||
let mut identifier_kinds: IdentifierKinds = FxHashMap::default();
|
||||
validate_context_variable_lvalues_impl(
|
||||
func,
|
||||
&mut identifier_kinds,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_diagnostics::{
|
||||
CompilerDiagnostic, CompilerDiagnosticDetail, CompilerSuggestion, CompilerSuggestionOperation,
|
||||
@@ -33,7 +33,7 @@ pub fn validate_exhaustive_dependencies(
|
||||
let validate_memo = env.config.validate_exhaustive_memoization_dependencies;
|
||||
let validate_effect = env.config.validate_exhaustive_effect_dependencies.clone();
|
||||
|
||||
let mut temporaries: HashMap<IdentifierId, Temporary> = HashMap::new();
|
||||
let mut temporaries: FxHashMap<IdentifierId, Temporary> = FxHashMap::default();
|
||||
for param in &func.params {
|
||||
let place = match param {
|
||||
ParamPattern::Place(p) => p,
|
||||
@@ -51,7 +51,7 @@ pub fn validate_exhaustive_dependencies(
|
||||
}
|
||||
|
||||
let mut start_memo: Option<StartMemoInfo> = None;
|
||||
let mut memo_locals: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut memo_locals: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
|
||||
// Callbacks struct holding the mutable state
|
||||
let mut callbacks = Callbacks {
|
||||
@@ -61,7 +61,7 @@ pub fn validate_exhaustive_dependencies(
|
||||
validate_effect: validate_effect.clone(),
|
||||
reactive: &reactive,
|
||||
diagnostics: Vec::new(),
|
||||
invalid_memo_ids: HashSet::new(),
|
||||
invalid_memo_ids: FxHashSet::default(),
|
||||
};
|
||||
|
||||
collect_dependencies(
|
||||
@@ -180,13 +180,13 @@ fn path_to_string(path: &[DependencyPathEntry]) -> String {
|
||||
struct Callbacks<'a> {
|
||||
start_memo: &'a mut Option<StartMemoInfo>,
|
||||
#[allow(dead_code)]
|
||||
memo_locals: &'a mut HashSet<IdentifierId>,
|
||||
memo_locals: &'a mut FxHashSet<IdentifierId>,
|
||||
validate_memo: bool,
|
||||
validate_effect: ExhaustiveEffectDepsMode,
|
||||
reactive: &'a HashSet<IdentifierId>,
|
||||
reactive: &'a FxHashSet<IdentifierId>,
|
||||
diagnostics: Vec<CompilerDiagnostic>,
|
||||
/// manual_memo_ids that had validation errors (to set has_invalid_deps)
|
||||
invalid_memo_ids: HashSet<u32>,
|
||||
invalid_memo_ids: FxHashSet<u32>,
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -283,8 +283,8 @@ fn is_sub_path_ignoring_optionals(
|
||||
fn collect_reactive_identifiers(
|
||||
func: &HirFunction,
|
||||
functions: &[HirFunction],
|
||||
) -> HashSet<IdentifierId> {
|
||||
let mut reactive = HashSet::new();
|
||||
) -> FxHashSet<IdentifierId> {
|
||||
let mut reactive = FxHashSet::default();
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
for &instr_id in &block.instructions {
|
||||
let instr = &func.instructions[instr_id.0 as usize];
|
||||
@@ -319,9 +319,9 @@ fn collect_reactive_identifiers(
|
||||
// findOptionalPlaces
|
||||
// =============================================================================
|
||||
|
||||
fn find_optional_places(func: &HirFunction) -> HashMap<IdentifierId, bool> {
|
||||
let mut optionals: HashMap<IdentifierId, bool> = HashMap::new();
|
||||
let mut visited: HashSet<BlockId> = HashSet::new();
|
||||
fn find_optional_places(func: &HirFunction) -> FxHashMap<IdentifierId, bool> {
|
||||
let mut optionals: FxHashMap<IdentifierId, bool> = FxHashMap::default();
|
||||
let mut visited: FxHashSet<BlockId> = FxHashSet::default();
|
||||
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
if visited.contains(&block.id) {
|
||||
@@ -418,8 +418,8 @@ fn find_optional_places(func: &HirFunction) -> HashMap<IdentifierId, bool> {
|
||||
fn add_dependency(
|
||||
dep: &Temporary,
|
||||
dependencies: &mut Vec<InferredDependency>,
|
||||
dep_keys: &mut HashSet<InferredDependencyKey>,
|
||||
locals: &HashSet<IdentifierId>,
|
||||
dep_keys: &mut FxHashSet<InferredDependencyKey>,
|
||||
locals: &FxHashSet<IdentifierId>,
|
||||
) {
|
||||
match dep {
|
||||
Temporary::Aggregate {
|
||||
@@ -464,8 +464,8 @@ fn add_dependency(
|
||||
fn add_dependency_inferred(
|
||||
dep: &InferredDependency,
|
||||
dependencies: &mut Vec<InferredDependency>,
|
||||
dep_keys: &mut HashSet<InferredDependencyKey>,
|
||||
locals: &HashSet<IdentifierId>,
|
||||
dep_keys: &mut FxHashSet<InferredDependencyKey>,
|
||||
locals: &FxHashSet<IdentifierId>,
|
||||
) {
|
||||
match dep {
|
||||
InferredDependency::Global { .. } => {
|
||||
@@ -487,10 +487,10 @@ fn add_dependency_inferred(
|
||||
|
||||
fn visit_candidate_dependency(
|
||||
place: &Place,
|
||||
temporaries: &HashMap<IdentifierId, Temporary>,
|
||||
temporaries: &FxHashMap<IdentifierId, Temporary>,
|
||||
dependencies: &mut Vec<InferredDependency>,
|
||||
dep_keys: &mut HashSet<InferredDependencyKey>,
|
||||
locals: &HashSet<IdentifierId>,
|
||||
dep_keys: &mut FxHashSet<InferredDependencyKey>,
|
||||
locals: &FxHashSet<IdentifierId>,
|
||||
) {
|
||||
if let Some(dep) = temporaries.get(&place.identifier) {
|
||||
add_dependency(dep, dependencies, dep_keys, locals);
|
||||
@@ -502,12 +502,12 @@ fn collect_dependencies(
|
||||
identifiers: &[Identifier],
|
||||
types: &[Type],
|
||||
functions: &[HirFunction],
|
||||
temporaries: &mut HashMap<IdentifierId, Temporary>,
|
||||
temporaries: &mut FxHashMap<IdentifierId, Temporary>,
|
||||
callbacks: &mut Option<&mut Callbacks<'_>>,
|
||||
is_function_expression: bool,
|
||||
) -> Result<Temporary, CompilerDiagnostic> {
|
||||
let optionals = find_optional_places(func);
|
||||
let mut locals: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut locals: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
|
||||
if is_function_expression {
|
||||
for param in &func.params {
|
||||
@@ -520,15 +520,15 @@ fn collect_dependencies(
|
||||
}
|
||||
|
||||
let mut dependencies: Vec<InferredDependency> = Vec::new();
|
||||
let mut dep_keys: HashSet<InferredDependencyKey> = HashSet::new();
|
||||
let mut dep_keys: FxHashSet<InferredDependencyKey> = FxHashSet::default();
|
||||
|
||||
// Saved state for when we're inside a memo block (StartMemoize..FinishMemoize).
|
||||
// In TS, `dependencies` and `locals` are shared by reference between the main
|
||||
// collection loop and the callbacks — StartMemoize clears them, FinishMemoize
|
||||
// reads and clears them. We simulate this by saving/restoring.
|
||||
let mut saved_dependencies: Option<Vec<InferredDependency>> = None;
|
||||
let mut saved_dep_keys: Option<HashSet<InferredDependencyKey>> = None;
|
||||
let mut saved_locals: Option<HashSet<IdentifierId>> = None;
|
||||
let mut saved_dep_keys: Option<FxHashSet<InferredDependencyKey>> = None;
|
||||
let mut saved_locals: Option<FxHashSet<IdentifierId>> = None;
|
||||
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
// Process phis
|
||||
@@ -906,8 +906,8 @@ fn collect_dependencies(
|
||||
}
|
||||
InstructionValue::ArrayExpression { elements, loc, .. } => {
|
||||
let mut array_deps: Vec<InferredDependency> = Vec::new();
|
||||
let mut array_keys: HashSet<InferredDependencyKey> = HashSet::new();
|
||||
let empty_locals = HashSet::new();
|
||||
let mut array_keys: FxHashSet<InferredDependencyKey> = FxHashSet::default();
|
||||
let empty_locals = FxHashSet::default();
|
||||
for elem in elements {
|
||||
let place = match elem {
|
||||
ArrayElement::Place(p) => Some(p),
|
||||
@@ -1224,7 +1224,7 @@ fn collect_dependencies(
|
||||
fn validate_dependencies(
|
||||
mut inferred: Vec<InferredDependency>,
|
||||
manual_dependencies: &[ManualMemoDependency],
|
||||
reactive: &HashSet<IdentifierId>,
|
||||
reactive: &FxHashSet<IdentifierId>,
|
||||
manual_memo_loc: Option<SourceLocation>,
|
||||
category: ErrorCategory,
|
||||
exhaustive_deps_report_mode: &str,
|
||||
@@ -1360,7 +1360,7 @@ fn validate_dependencies(
|
||||
}
|
||||
|
||||
// Validate manual deps
|
||||
let mut matched: HashSet<usize> = HashSet::new(); // indices into manual_dependencies
|
||||
let mut matched: FxHashSet<usize> = FxHashSet::default(); // indices into manual_dependencies
|
||||
let mut missing: Vec<&InferredDependency> = Vec::new();
|
||||
let mut extra: Vec<&ManualMemoDependency> = Vec::new();
|
||||
|
||||
@@ -1646,7 +1646,7 @@ fn print_manual_memo_dependency(dep: &ManualMemoDependency, identifiers: &[Ident
|
||||
|
||||
fn is_optional_dependency(
|
||||
identifier: IdentifierId,
|
||||
reactive: &HashSet<IdentifierId>,
|
||||
reactive: &FxHashSet<IdentifierId>,
|
||||
identifiers: &[Identifier],
|
||||
types: &[Type],
|
||||
) -> bool {
|
||||
@@ -1659,7 +1659,7 @@ fn is_optional_dependency(
|
||||
|
||||
fn is_optional_dependency_inferred(
|
||||
dep: &InferredDependency,
|
||||
reactive: &HashSet<IdentifierId>,
|
||||
reactive: &FxHashSet<IdentifierId>,
|
||||
identifiers: &[Identifier],
|
||||
types: &[Type],
|
||||
) -> bool {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
//! and not called dynamically. Also validates that hooks are not
|
||||
//! called inside function expressions.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use react_compiler_diagnostics::{
|
||||
@@ -51,7 +51,7 @@ fn join_kinds(a: Kind, b: Kind) -> Kind {
|
||||
|
||||
fn get_kind_for_place(
|
||||
place: &Place,
|
||||
value_kinds: &HashMap<IdentifierId, Kind>,
|
||||
value_kinds: &FxHashMap<IdentifierId, Kind>,
|
||||
identifiers: &[Identifier],
|
||||
) -> Kind {
|
||||
let known_kind = value_kinds.get(&place.identifier).copied();
|
||||
@@ -86,8 +86,8 @@ fn get_hook_kind_for_id<'a>(
|
||||
|
||||
fn visit_place(
|
||||
place: &Place,
|
||||
value_kinds: &HashMap<IdentifierId, Kind>,
|
||||
errors_by_loc: &mut IndexMap<SourceLocation, CompilerErrorDetail>,
|
||||
value_kinds: &FxHashMap<IdentifierId, Kind>,
|
||||
errors_by_loc: &mut IndexMap<SourceLocation, CompilerErrorDetail, FxBuildHasher>,
|
||||
env: &mut Environment,
|
||||
) -> Result<(), CompilerError> {
|
||||
let kind = value_kinds.get(&place.identifier).copied();
|
||||
@@ -99,8 +99,8 @@ fn visit_place(
|
||||
|
||||
fn record_conditional_hook_error(
|
||||
place: &Place,
|
||||
value_kinds: &mut HashMap<IdentifierId, Kind>,
|
||||
errors_by_loc: &mut IndexMap<SourceLocation, CompilerErrorDetail>,
|
||||
value_kinds: &mut FxHashMap<IdentifierId, Kind>,
|
||||
errors_by_loc: &mut IndexMap<SourceLocation, CompilerErrorDetail, FxBuildHasher>,
|
||||
env: &mut Environment,
|
||||
) -> Result<(), CompilerError> {
|
||||
value_kinds.insert(place.identifier, Kind::Error);
|
||||
@@ -133,7 +133,7 @@ fn record_conditional_hook_error(
|
||||
|
||||
fn record_invalid_hook_usage_error(
|
||||
place: &Place,
|
||||
errors_by_loc: &mut IndexMap<SourceLocation, CompilerErrorDetail>,
|
||||
errors_by_loc: &mut IndexMap<SourceLocation, CompilerErrorDetail, FxBuildHasher>,
|
||||
env: &mut Environment,
|
||||
) -> Result<(), CompilerError> {
|
||||
let reason = "Hooks may not be referenced as normal values, they must be called. See https://react.dev/reference/rules/react-calls-components-and-hooks#never-pass-around-hooks-as-regular-values".to_string();
|
||||
@@ -164,7 +164,7 @@ fn record_invalid_hook_usage_error(
|
||||
|
||||
fn record_dynamic_hook_usage_error(
|
||||
place: &Place,
|
||||
errors_by_loc: &mut IndexMap<SourceLocation, CompilerErrorDetail>,
|
||||
errors_by_loc: &mut IndexMap<SourceLocation, CompilerErrorDetail, FxBuildHasher>,
|
||||
env: &mut Environment,
|
||||
) -> Result<(), CompilerError> {
|
||||
let reason = "Hooks must be the same function on every render, but this value may change over time to a different function. See https://react.dev/reference/rules/react-calls-components-and-hooks#dont-dynamically-use-hooks".to_string();
|
||||
@@ -199,8 +199,9 @@ pub fn validate_hooks_usage(
|
||||
env: &mut Environment,
|
||||
) -> Result<(), react_compiler_diagnostics::CompilerDiagnostic> {
|
||||
let unconditional_blocks = compute_unconditional_blocks(func, env.next_block_id().0)?;
|
||||
let mut errors_by_loc: IndexMap<SourceLocation, CompilerErrorDetail> = IndexMap::new();
|
||||
let mut value_kinds: HashMap<IdentifierId, Kind> = HashMap::new();
|
||||
let mut errors_by_loc: IndexMap<SourceLocation, CompilerErrorDetail, FxBuildHasher> =
|
||||
IndexMap::default();
|
||||
let mut value_kinds: FxHashMap<IdentifierId, Kind> = FxHashMap::default();
|
||||
|
||||
// Process params
|
||||
for param in &func.params {
|
||||
@@ -512,8 +513,8 @@ fn hook_kind_display(kind: &HookKind) -> &'static str {
|
||||
/// Uses the canonical `each_instruction_value_operand` from visitors.
|
||||
fn visit_all_operands(
|
||||
value: &InstructionValue,
|
||||
value_kinds: &HashMap<IdentifierId, Kind>,
|
||||
errors_by_loc: &mut IndexMap<SourceLocation, CompilerErrorDetail>,
|
||||
value_kinds: &FxHashMap<IdentifierId, Kind>,
|
||||
errors_by_loc: &mut IndexMap<SourceLocation, CompilerErrorDetail, FxBuildHasher>,
|
||||
env: &mut Environment,
|
||||
) -> Result<(), CompilerError> {
|
||||
let operands = visitors::each_instruction_value_operand(value, &*env);
|
||||
|
||||
+4
-4
@@ -5,7 +5,7 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_diagnostics::{CompilerDiagnostic, CompilerDiagnosticDetail, ErrorCategory};
|
||||
use react_compiler_hir::environment::Environment;
|
||||
@@ -20,7 +20,7 @@ use react_compiler_hir::{
|
||||
/// This prevents a category of bugs in which a closure captures a
|
||||
/// binding from one render but does not update.
|
||||
pub fn validate_locals_not_reassigned_after_render(func: &HirFunction, env: &mut Environment) {
|
||||
let mut context_variables: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut context_variables: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
let mut diagnostics: Vec<CompilerDiagnostic> = Vec::new();
|
||||
|
||||
let reassignment = get_context_reassignment(
|
||||
@@ -85,13 +85,13 @@ fn get_context_reassignment(
|
||||
types: &[Type],
|
||||
functions: &[HirFunction],
|
||||
env: &Environment,
|
||||
context_variables: &mut HashSet<IdentifierId>,
|
||||
context_variables: &mut FxHashSet<IdentifierId>,
|
||||
is_function_expression: bool,
|
||||
is_async: bool,
|
||||
diagnostics: &mut Vec<CompilerDiagnostic>,
|
||||
) -> Option<Place> {
|
||||
// Maps identifiers to the place that they reassign
|
||||
let mut reassigning_functions: HashMap<IdentifierId, Place> = HashMap::new();
|
||||
let mut reassigning_functions: FxHashMap<IdentifierId, Place> = FxHashMap::default();
|
||||
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
for &instruction_id in &block.instructions {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_diagnostics::{CompilerError, CompilerErrorDetail, ErrorCategory};
|
||||
use react_compiler_hir::environment::Environment;
|
||||
@@ -12,15 +12,15 @@ pub fn validate_no_capitalized_calls(
|
||||
env: &mut Environment,
|
||||
) -> Result<(), CompilerError> {
|
||||
// Build the allow list from global registry keys + config entries
|
||||
let mut allow_list: HashSet<String> = env.globals().keys().cloned().collect();
|
||||
let mut allow_list: FxHashSet<String> = env.globals().keys().cloned().collect();
|
||||
if let Some(config_entries) = &env.config.validate_no_capitalized_calls {
|
||||
for entry in config_entries {
|
||||
allow_list.insert(entry.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let mut capital_load_globals: HashMap<IdentifierId, String> = HashMap::new();
|
||||
let mut capitalized_properties: HashMap<IdentifierId, String> = HashMap::new();
|
||||
let mut capital_load_globals: FxHashMap<IdentifierId, String> = FxHashMap::default();
|
||||
let mut capitalized_properties: FxHashMap<IdentifierId, String> = FxHashMap::default();
|
||||
|
||||
let reason = "Capitalized functions are reserved for components, which must be invoked with JSX. If this is a component, render it with JSX. Otherwise, ensure that it has no hook calls and rename it to begin with a lowercase letter. Alternatively, if you know for a fact that this function is not a component, you can allowlist it via the compiler config";
|
||||
|
||||
|
||||
+65
-60
@@ -10,7 +10,8 @@
|
||||
//!
|
||||
//! Port of ValidateNoDerivedComputationsInEffects_exp.ts.
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_diagnostics::{
|
||||
CompilerDiagnostic, CompilerDiagnosticDetail, CompilerError, CompilerErrorDetail, ErrorCategory,
|
||||
@@ -111,7 +112,7 @@ struct DerivationMetadata {
|
||||
type_of_value: TypeOfValue,
|
||||
place_identifier: IdentifierId,
|
||||
place_name: Option<IdentifierName>,
|
||||
source_ids: indexmap::IndexSet<IdentifierId>,
|
||||
source_ids: IndexSet<IdentifierId, FxBuildHasher>,
|
||||
is_state_source: bool,
|
||||
}
|
||||
|
||||
@@ -129,16 +130,16 @@ struct DepElement {
|
||||
|
||||
struct ValidationContext {
|
||||
/// Map from lvalue identifier to the FunctionId of function expressions
|
||||
functions: HashMap<IdentifierId, FunctionId>,
|
||||
functions: FxHashMap<IdentifierId, FunctionId>,
|
||||
/// Map from lvalue identifier to ArrayExpression elements (candidate deps)
|
||||
candidate_dependencies: HashMap<IdentifierId, Vec<DepElement>>,
|
||||
candidate_dependencies: FxHashMap<IdentifierId, Vec<DepElement>>,
|
||||
derivation_cache: DerivationCache,
|
||||
effects_cache: HashMap<IdentifierId, EffectMetadata>,
|
||||
set_state_loads: HashMap<IdentifierId, Option<IdentifierId>>,
|
||||
set_state_usages: HashMap<IdentifierId, HashSet<LocKey>>,
|
||||
effects_cache: FxHashMap<IdentifierId, EffectMetadata>,
|
||||
set_state_loads: FxHashMap<IdentifierId, Option<IdentifierId>>,
|
||||
set_state_usages: FxHashMap<IdentifierId, FxHashSet<LocKey>>,
|
||||
}
|
||||
|
||||
/// A hashable key for SourceLocation to use in HashSet
|
||||
/// A hashable key for SourceLocation to use in FxHashSet
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
struct LocKey {
|
||||
start_line: u32,
|
||||
@@ -169,21 +170,21 @@ impl LocKey {
|
||||
#[derive(Debug, Clone)]
|
||||
struct DerivationCache {
|
||||
has_changes: bool,
|
||||
cache: HashMap<IdentifierId, DerivationMetadata>,
|
||||
previous_cache: Option<HashMap<IdentifierId, DerivationMetadata>>,
|
||||
cache: FxHashMap<IdentifierId, DerivationMetadata>,
|
||||
previous_cache: Option<FxHashMap<IdentifierId, DerivationMetadata>>,
|
||||
}
|
||||
|
||||
impl DerivationCache {
|
||||
fn new() -> Self {
|
||||
DerivationCache {
|
||||
has_changes: false,
|
||||
cache: HashMap::new(),
|
||||
cache: FxHashMap::default(),
|
||||
previous_cache: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn take_snapshot(&mut self) {
|
||||
let mut prev = HashMap::new();
|
||||
let mut prev = FxHashMap::default();
|
||||
for (key, value) in &self.cache {
|
||||
prev.insert(
|
||||
*key,
|
||||
@@ -241,7 +242,7 @@ impl DerivationCache {
|
||||
&mut self,
|
||||
derived_id: IdentifierId,
|
||||
derived_name: Option<IdentifierName>,
|
||||
source_ids: indexmap::IndexSet<IdentifierId>,
|
||||
source_ids: IndexSet<IdentifierId, FxBuildHasher>,
|
||||
type_of_value: TypeOfValue,
|
||||
is_state_source: bool,
|
||||
) {
|
||||
@@ -302,8 +303,8 @@ fn join_value(lvalue_type: TypeOfValue, value_type: TypeOfValue) -> TypeOfValue
|
||||
|
||||
fn get_root_set_state(
|
||||
key: IdentifierId,
|
||||
loads: &HashMap<IdentifierId, Option<IdentifierId>>,
|
||||
visited: &mut HashSet<IdentifierId>,
|
||||
loads: &FxHashMap<IdentifierId, Option<IdentifierId>>,
|
||||
visited: &mut FxHashSet<IdentifierId>,
|
||||
) -> Option<IdentifierId> {
|
||||
if visited.contains(&key) {
|
||||
return None;
|
||||
@@ -320,8 +321,8 @@ fn get_root_set_state(
|
||||
fn maybe_record_set_state_for_instr(
|
||||
instr: &react_compiler_hir::Instruction,
|
||||
env: &Environment,
|
||||
set_state_loads: &mut HashMap<IdentifierId, Option<IdentifierId>>,
|
||||
set_state_usages: &mut HashMap<IdentifierId, HashSet<LocKey>>,
|
||||
set_state_loads: &mut FxHashMap<IdentifierId, Option<IdentifierId>>,
|
||||
set_state_usages: &mut FxHashMap<IdentifierId, FxHashSet<LocKey>>,
|
||||
) {
|
||||
let identifiers = &env.identifiers;
|
||||
let types = &env.types;
|
||||
@@ -349,10 +350,10 @@ fn maybe_record_set_state_for_instr(
|
||||
}
|
||||
}
|
||||
|
||||
let root = get_root_set_state(lvalue_id, set_state_loads, &mut HashSet::new());
|
||||
let root = get_root_set_state(lvalue_id, set_state_loads, &mut FxHashSet::default());
|
||||
if let Some(root_id) = root {
|
||||
set_state_usages.entry(root_id).or_insert_with(|| {
|
||||
let mut set = HashSet::new();
|
||||
let mut set = FxHashSet::default();
|
||||
set.insert(LocKey::from_loc(&instr.lvalue.loc));
|
||||
set
|
||||
});
|
||||
@@ -377,12 +378,12 @@ pub fn validate_no_derived_computations_in_effects_exp(
|
||||
let identifiers = &env.identifiers;
|
||||
|
||||
let mut context = ValidationContext {
|
||||
functions: HashMap::new(),
|
||||
candidate_dependencies: HashMap::new(),
|
||||
functions: FxHashMap::default(),
|
||||
candidate_dependencies: FxHashMap::default(),
|
||||
derivation_cache: DerivationCache::new(),
|
||||
effects_cache: HashMap::new(),
|
||||
set_state_loads: HashMap::new(),
|
||||
set_state_usages: HashMap::new(),
|
||||
effects_cache: FxHashMap::default(),
|
||||
set_state_loads: FxHashMap::default(),
|
||||
set_state_usages: FxHashMap::default(),
|
||||
};
|
||||
|
||||
// Initialize derivation cache based on function type
|
||||
@@ -395,7 +396,7 @@ pub fn validate_no_derived_computations_in_effects_exp(
|
||||
DerivationMetadata {
|
||||
place_identifier: place.identifier,
|
||||
place_name: name,
|
||||
source_ids: indexmap::IndexSet::new(),
|
||||
source_ids: IndexSet::default(),
|
||||
type_of_value: TypeOfValue::FromProps,
|
||||
is_state_source: true,
|
||||
},
|
||||
@@ -411,7 +412,7 @@ pub fn validate_no_derived_computations_in_effects_exp(
|
||||
DerivationMetadata {
|
||||
place_identifier: place.identifier,
|
||||
place_name: name,
|
||||
source_ids: indexmap::IndexSet::new(),
|
||||
source_ids: IndexSet::default(),
|
||||
type_of_value: TypeOfValue::FromProps,
|
||||
is_state_source: true,
|
||||
},
|
||||
@@ -477,7 +478,7 @@ fn record_phi_derivations(
|
||||
let identifiers = &env.identifiers;
|
||||
for phi in &block.phis {
|
||||
let mut type_of_value = TypeOfValue::Ignored;
|
||||
let mut source_ids: indexmap::IndexSet<IdentifierId> = indexmap::IndexSet::new();
|
||||
let mut source_ids: IndexSet<IdentifierId, FxBuildHasher> = IndexSet::default();
|
||||
|
||||
for (_block_id, operand) in &phi.operands {
|
||||
if let Some(operand_metadata) = context.derivation_cache.cache.get(&operand.identifier)
|
||||
@@ -522,7 +523,7 @@ fn record_instruction_derivations(
|
||||
|
||||
let mut type_of_value = TypeOfValue::Ignored;
|
||||
let is_source = false;
|
||||
let mut sources: indexmap::IndexSet<IdentifierId> = indexmap::IndexSet::new();
|
||||
let mut sources: IndexSet<IdentifierId, FxBuildHasher> = IndexSet::default();
|
||||
|
||||
match &instr.value {
|
||||
InstructionValue::FunctionExpression { lowered_func, .. } => {
|
||||
@@ -575,7 +576,7 @@ fn record_instruction_derivations(
|
||||
context.derivation_cache.add_derivation_entry(
|
||||
lvalue_id,
|
||||
name,
|
||||
indexmap::IndexSet::new(),
|
||||
IndexSet::default(),
|
||||
TypeOfValue::FromState,
|
||||
true,
|
||||
);
|
||||
@@ -614,7 +615,7 @@ fn record_instruction_derivations(
|
||||
context.derivation_cache.add_derivation_entry(
|
||||
lvalue_id,
|
||||
name,
|
||||
indexmap::IndexSet::new(),
|
||||
IndexSet::default(),
|
||||
TypeOfValue::FromState,
|
||||
true,
|
||||
);
|
||||
@@ -643,8 +644,11 @@ fn record_instruction_derivations(
|
||||
for (operand_id, operand_loc) in each_instruction_operand(instr, env) {
|
||||
// Track setState usages
|
||||
if context.set_state_loads.contains_key(&operand_id) {
|
||||
let root =
|
||||
get_root_set_state(operand_id, &context.set_state_loads, &mut HashSet::new());
|
||||
let root = get_root_set_state(
|
||||
operand_id,
|
||||
&context.set_state_loads,
|
||||
&mut FxHashSet::default(),
|
||||
);
|
||||
if let Some(root_id) = root {
|
||||
if let Some(usages) = context.set_state_usages.get_mut(&root_id) {
|
||||
usages.insert(LocKey::from_loc(&operand_loc));
|
||||
@@ -754,7 +758,7 @@ struct TreeNode {
|
||||
fn build_tree_node(
|
||||
source_id: IdentifierId,
|
||||
context: &ValidationContext,
|
||||
visited: &HashSet<String>,
|
||||
visited: &FxHashSet<String>,
|
||||
) -> Vec<TreeNode> {
|
||||
let source_metadata = match context.derivation_cache.cache.get(&source_id) {
|
||||
Some(m) => m,
|
||||
@@ -773,7 +777,7 @@ fn build_tree_node(
|
||||
}
|
||||
|
||||
let mut children: Vec<TreeNode> = Vec::new();
|
||||
let mut named_siblings: indexmap::IndexSet<String> = indexmap::IndexSet::new();
|
||||
let mut named_siblings: IndexSet<String, FxBuildHasher> = IndexSet::default();
|
||||
|
||||
for child_id in &source_metadata.source_ids {
|
||||
assert_ne!(
|
||||
@@ -813,8 +817,8 @@ fn render_tree(
|
||||
node: &TreeNode,
|
||||
indent: &str,
|
||||
is_last: bool,
|
||||
props_set: &mut indexmap::IndexSet<String>,
|
||||
state_set: &mut indexmap::IndexSet<String>,
|
||||
props_set: &mut IndexSet<String, FxBuildHasher>,
|
||||
state_set: &mut IndexSet<String, FxBuildHasher>,
|
||||
) -> String {
|
||||
let prefix = format!(
|
||||
"{}{}",
|
||||
@@ -865,10 +869,10 @@ fn render_tree(
|
||||
fn get_fn_local_deps(
|
||||
func_id: Option<FunctionId>,
|
||||
env: &Environment,
|
||||
) -> Option<HashSet<IdentifierId>> {
|
||||
) -> Option<FxHashSet<IdentifierId>> {
|
||||
let func_id = func_id?;
|
||||
let inner = &env.functions[func_id.0 as usize];
|
||||
let mut deps: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut deps: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
|
||||
for (_block_id, block) in &inner.body.blocks {
|
||||
for &instr_id in &block.instructions {
|
||||
@@ -894,34 +898,35 @@ fn validate_effect(
|
||||
let types = &env.types;
|
||||
let functions = &env.functions;
|
||||
let effect_function = &functions[effect_func_id.0 as usize];
|
||||
let mut seen_blocks: HashSet<BlockId> = HashSet::new();
|
||||
let mut seen_blocks: FxHashSet<BlockId> = FxHashSet::default();
|
||||
|
||||
struct DerivedSetStateCall {
|
||||
callee_loc: Option<SourceLocation>,
|
||||
callee_id: IdentifierId,
|
||||
callee_identifier_name: Option<String>,
|
||||
source_ids: indexmap::IndexSet<IdentifierId>,
|
||||
source_ids: IndexSet<IdentifierId, FxBuildHasher>,
|
||||
}
|
||||
|
||||
let mut effect_derived_set_state_calls: Vec<DerivedSetStateCall> = Vec::new();
|
||||
let mut effect_set_state_usages: HashMap<IdentifierId, HashSet<LocKey>> = HashMap::new();
|
||||
let mut effect_set_state_usages: FxHashMap<IdentifierId, FxHashSet<LocKey>> =
|
||||
FxHashMap::default();
|
||||
|
||||
// Consider setStates in the effect's dependency array as being part of effectSetStateUsages
|
||||
for dep in dependencies {
|
||||
let root = get_root_set_state(
|
||||
dep.identifier,
|
||||
&context.set_state_loads,
|
||||
&mut HashSet::new(),
|
||||
&mut FxHashSet::default(),
|
||||
);
|
||||
if let Some(root_id) = root {
|
||||
let mut set = HashSet::new();
|
||||
let mut set = FxHashSet::default();
|
||||
set.insert(LocKey::from_loc(&dep.loc));
|
||||
effect_set_state_usages.insert(root_id, set);
|
||||
}
|
||||
}
|
||||
|
||||
let mut cleanup_function_deps: Option<HashSet<IdentifierId>> = None;
|
||||
let mut globals: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut cleanup_function_deps: Option<FxHashSet<IdentifierId>> = None;
|
||||
let mut globals: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
|
||||
for (_block_id, block) in &effect_function.body.blocks {
|
||||
// Check for return -> cleanup function
|
||||
@@ -965,7 +970,7 @@ fn validate_effect(
|
||||
let root = get_root_set_state(
|
||||
operand_id,
|
||||
&context.set_state_loads,
|
||||
&mut HashSet::new(),
|
||||
&mut FxHashSet::default(),
|
||||
);
|
||||
if let Some(root_id) = root {
|
||||
if let Some(usages) = effect_set_state_usages.get_mut(&root_id) {
|
||||
@@ -1045,7 +1050,7 @@ fn validate_effect(
|
||||
let root_set_state_call = get_root_set_state(
|
||||
derived.callee_id,
|
||||
&context.set_state_loads,
|
||||
&mut HashSet::new(),
|
||||
&mut FxHashSet::default(),
|
||||
);
|
||||
if let Some(root_id) = root_set_state_call {
|
||||
let effect_usage_count = effect_set_state_usages
|
||||
@@ -1061,13 +1066,13 @@ fn validate_effect(
|
||||
&& context.set_state_usages.contains_key(&root_id)
|
||||
&& effect_usage_count == total_usage_count - 1
|
||||
{
|
||||
let mut props_set: indexmap::IndexSet<String> = indexmap::IndexSet::new();
|
||||
let mut state_set: indexmap::IndexSet<String> = indexmap::IndexSet::new();
|
||||
let mut props_set: IndexSet<String, FxBuildHasher> = IndexSet::default();
|
||||
let mut state_set: IndexSet<String, FxBuildHasher> = IndexSet::default();
|
||||
|
||||
let mut root_nodes_map: indexmap::IndexMap<String, TreeNode> =
|
||||
indexmap::IndexMap::new();
|
||||
let mut root_nodes_map: IndexMap<String, TreeNode, FxBuildHasher> =
|
||||
IndexMap::default();
|
||||
for id in &derived.source_ids {
|
||||
let nodes = build_tree_node(*id, context, &HashSet::new());
|
||||
let nodes = build_tree_node(*id, context, &FxHashSet::default());
|
||||
for node in nodes {
|
||||
if !root_nodes_map.contains_key(&node.name) {
|
||||
root_nodes_map.insert(node.name.clone(), node);
|
||||
@@ -1162,9 +1167,9 @@ pub fn validate_no_derived_computations_in_effects(
|
||||
let effects_to_validate: Vec<(FunctionId, Vec<IdentifierId>)> = {
|
||||
let ids = &env.identifiers;
|
||||
let tys = &env.types;
|
||||
let mut candidate_deps: HashMap<IdentifierId, Vec<IdentifierId>> = HashMap::new();
|
||||
let mut functions_map: HashMap<IdentifierId, FunctionId> = HashMap::new();
|
||||
let mut locals_map: HashMap<IdentifierId, IdentifierId> = HashMap::new();
|
||||
let mut candidate_deps: FxHashMap<IdentifierId, Vec<IdentifierId>> = FxHashMap::default();
|
||||
let mut functions_map: FxHashMap<IdentifierId, FunctionId> = FxHashMap::default();
|
||||
let mut locals_map: FxHashMap<IdentifierId, IdentifierId> = FxHashMap::default();
|
||||
let mut result = Vec::new();
|
||||
|
||||
for (_, block) in &func.body.blocks {
|
||||
@@ -1280,8 +1285,8 @@ fn validate_effect_non_exp(
|
||||
}
|
||||
}
|
||||
|
||||
let mut seen_blocks: HashSet<BlockId> = HashSet::new();
|
||||
let mut dep_values: HashMap<IdentifierId, Vec<IdentifierId>> = HashMap::new();
|
||||
let mut seen_blocks: FxHashSet<BlockId> = FxHashSet::default();
|
||||
let mut dep_values: FxHashMap<IdentifierId, Vec<IdentifierId>> = FxHashMap::default();
|
||||
for dep in effect_deps {
|
||||
dep_values.insert(*dep, vec![*dep]);
|
||||
}
|
||||
@@ -1296,7 +1301,7 @@ fn validate_effect_non_exp(
|
||||
}
|
||||
|
||||
for phi in &block.phis {
|
||||
let mut aggregate: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut aggregate: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
for operand in phi.operands.values() {
|
||||
if let Some(deps) = dep_values.get(&operand.identifier) {
|
||||
for d in deps {
|
||||
@@ -1326,7 +1331,7 @@ fn validate_effect_non_exp(
|
||||
| InstructionValue::TemplateLiteral { .. }
|
||||
| InstructionValue::CallExpression { .. }
|
||||
| InstructionValue::MethodCall { .. } => {
|
||||
let mut aggregate: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut aggregate: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
for operand in non_exp_value_operands(&instr.value) {
|
||||
if let Some(deps) = dep_values.get(&operand) {
|
||||
for d in deps {
|
||||
@@ -1343,7 +1348,7 @@ fn validate_effect_non_exp(
|
||||
if is_set_state_type(callee_ty) && args.len() == 1 {
|
||||
if let PlaceOrSpread::Place(arg) = &args[0] {
|
||||
if let Some(deps) = dep_values.get(&arg.identifier) {
|
||||
let dep_set: HashSet<_> = deps.iter().collect();
|
||||
let dep_set: FxHashSet<_> = deps.iter().collect();
|
||||
if dep_set.len() == effect_deps.len() {
|
||||
if let Some(loc) = callee.loc {
|
||||
set_state_locs.push(loc);
|
||||
|
||||
+4
-4
@@ -5,7 +5,7 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_diagnostics::{
|
||||
CompilerDiagnostic, CompilerDiagnosticDetail, ErrorCategory, SourceLocation,
|
||||
@@ -53,7 +53,7 @@ fn check_no_freezing_known_mutable_functions(
|
||||
env: &Environment,
|
||||
) -> Vec<CompilerDiagnostic> {
|
||||
// Maps an identifier to the mutation effect that makes it "known mutable"
|
||||
let mut context_mutation_effects: HashMap<IdentifierId, MutationInfo> = HashMap::new();
|
||||
let mut context_mutation_effects: FxHashMap<IdentifierId, MutationInfo> = FxHashMap::default();
|
||||
let mut diagnostics: Vec<CompilerDiagnostic> = Vec::new();
|
||||
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
@@ -83,7 +83,7 @@ fn check_no_freezing_known_mutable_functions(
|
||||
InstructionValue::FunctionExpression { lowered_func, .. } => {
|
||||
let inner_function = &functions[lowered_func.func.0 as usize];
|
||||
if let Some(ref aliasing_effects) = inner_function.aliasing_effects {
|
||||
let context_ids: HashSet<IdentifierId> = inner_function
|
||||
let context_ids: FxHashSet<IdentifierId> = inner_function
|
||||
.context
|
||||
.iter()
|
||||
.map(|place| place.identifier)
|
||||
@@ -170,7 +170,7 @@ fn check_no_freezing_known_mutable_functions(
|
||||
/// If an operand with Effect::Freeze is a known-mutable function, emit a diagnostic.
|
||||
fn check_operand_for_freeze_violation(
|
||||
operand: &Place,
|
||||
context_mutation_effects: &HashMap<IdentifierId, MutationInfo>,
|
||||
context_mutation_effects: &FxHashMap<IdentifierId, MutationInfo>,
|
||||
identifiers: &[Identifier],
|
||||
diagnostics: &mut Vec<CompilerDiagnostic>,
|
||||
) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_diagnostics::{
|
||||
CompilerDiagnostic, CompilerDiagnosticDetail, ErrorCategory, SourceLocation,
|
||||
@@ -270,16 +270,16 @@ fn join_ref_access_types_many(types: &[RefAccessType]) -> RefAccessType {
|
||||
|
||||
struct Env {
|
||||
changed: bool,
|
||||
data: HashMap<IdentifierId, RefAccessType>,
|
||||
temporaries: HashMap<IdentifierId, Place>,
|
||||
data: FxHashMap<IdentifierId, RefAccessType>,
|
||||
temporaries: FxHashMap<IdentifierId, Place>,
|
||||
}
|
||||
|
||||
impl Env {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
changed: false,
|
||||
data: HashMap::new(),
|
||||
temporaries: HashMap::new(),
|
||||
data: FxHashMap::default(),
|
||||
temporaries: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,7 +626,7 @@ fn validate_no_ref_access_in_render_impl(
|
||||
}
|
||||
|
||||
// Collect identifiers that are interpolated as JSX children
|
||||
let mut interpolated_as_jsx: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut interpolated_as_jsx: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
for (_, block) in &func.body.blocks {
|
||||
for &instr_id in &block.instructions {
|
||||
let instr = &func.instructions[instr_id.0 as usize];
|
||||
@@ -890,7 +890,8 @@ fn validate_no_ref_access_in_render_impl(
|
||||
* use the effects to determine what validation to apply.
|
||||
* Track visited id:kind pairs to avoid duplicate errors.
|
||||
*/
|
||||
let mut visited_effects: HashSet<String> = HashSet::new();
|
||||
let mut visited_effects: FxHashSet<String> =
|
||||
FxHashSet::default();
|
||||
for effect in effects {
|
||||
let (place, validation) = match effect {
|
||||
AliasingEffect::Freeze { value, .. } => {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
//!
|
||||
//! Port of ValidateNoSetStateInEffects.ts.
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_diagnostics::{
|
||||
CompilerDiagnostic, CompilerDiagnosticDetail, CompilerError, ErrorCategory,
|
||||
@@ -37,7 +37,7 @@ pub fn validate_no_set_state_in_effects(
|
||||
let enable_allow_set_state_from_refs = env.config.enable_allow_set_state_from_refs_in_effects;
|
||||
|
||||
// Map from IdentifierId to the Place where the setState originated
|
||||
let mut set_state_functions: HashMap<IdentifierId, SetStateInfo> = HashMap::new();
|
||||
let mut set_state_functions: FxHashMap<IdentifierId, SetStateInfo> = FxHashMap::default();
|
||||
let mut errors = CompilerError::new();
|
||||
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
@@ -246,7 +246,7 @@ fn push_error(errors: &mut CompilerError, info: &SetStateInfo, enable_verbose: b
|
||||
/// Recursively collect all Place identifiers from a destructure pattern.
|
||||
fn collect_destructure_places(
|
||||
pattern: &react_compiler_hir::Pattern,
|
||||
ref_derived_values: &mut HashSet<IdentifierId>,
|
||||
ref_derived_values: &mut FxHashSet<IdentifierId>,
|
||||
) {
|
||||
match pattern {
|
||||
react_compiler_hir::Pattern::Array(arr) => {
|
||||
@@ -279,7 +279,7 @@ fn collect_destructure_places(
|
||||
|
||||
fn is_derived_from_ref(
|
||||
id: IdentifierId,
|
||||
ref_derived_values: &HashSet<IdentifierId>,
|
||||
ref_derived_values: &FxHashSet<IdentifierId>,
|
||||
identifiers: &[Identifier],
|
||||
types: &[Type],
|
||||
) -> bool {
|
||||
@@ -306,12 +306,12 @@ fn collect_operands(value: &InstructionValue, functions: &[HirFunction]) -> Vec<
|
||||
fn create_ref_controlled_block_checker(
|
||||
func: &HirFunction,
|
||||
next_block_id_counter: u32,
|
||||
ref_derived_values: &HashSet<IdentifierId>,
|
||||
ref_derived_values: &FxHashSet<IdentifierId>,
|
||||
identifiers: &[Identifier],
|
||||
types: &[Type],
|
||||
) -> Result<HashMap<BlockId, bool>, CompilerDiagnostic> {
|
||||
) -> Result<FxHashMap<BlockId, bool>, CompilerDiagnostic> {
|
||||
let post_dominators = compute_post_dominator_tree(func, next_block_id_counter, false)?;
|
||||
let mut cache: HashMap<BlockId, bool> = HashMap::new();
|
||||
let mut cache: FxHashMap<BlockId, bool> = FxHashMap::default();
|
||||
|
||||
for (block_id, _block) in &func.body.blocks {
|
||||
let frontier = post_dominator_frontier(func, &post_dominators, *block_id);
|
||||
@@ -365,7 +365,7 @@ fn create_ref_controlled_block_checker(
|
||||
/// Tracks ref-derived values to allow setState when the value being set comes from a ref.
|
||||
fn get_set_state_call(
|
||||
func: &HirFunction,
|
||||
set_state_functions: &mut HashMap<IdentifierId, SetStateInfo>,
|
||||
set_state_functions: &mut FxHashMap<IdentifierId, SetStateInfo>,
|
||||
identifiers: &[Identifier],
|
||||
types: &[Type],
|
||||
functions: &[HirFunction],
|
||||
@@ -373,7 +373,7 @@ fn get_set_state_call(
|
||||
next_block_id_counter: u32,
|
||||
source_code: Option<&str>,
|
||||
) -> Result<Option<SetStateInfo>, CompilerDiagnostic> {
|
||||
let mut ref_derived_values: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut ref_derived_values: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
|
||||
// First pass: collect ref-derived values (needed before building control dominator checker)
|
||||
// We do a pre-pass to seed ref_derived_values so the control dominator checker has them.
|
||||
@@ -432,7 +432,7 @@ fn get_set_state_call(
|
||||
types,
|
||||
)?
|
||||
} else {
|
||||
HashMap::new()
|
||||
FxHashMap::default()
|
||||
};
|
||||
|
||||
let is_ref_controlled_block = |block_id: BlockId| -> bool {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//!
|
||||
//! Port of ValidateNoSetStateInRender.ts.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use react_compiler_diagnostics::{CompilerDiagnostic, CompilerDiagnosticDetail, ErrorCategory};
|
||||
use react_compiler_hir::dominator::compute_unconditional_blocks;
|
||||
@@ -18,7 +18,7 @@ pub fn validate_no_set_state_in_render(
|
||||
func: &HirFunction,
|
||||
env: &mut Environment,
|
||||
) -> Result<(), CompilerDiagnostic> {
|
||||
let mut unconditional_set_state_functions: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut unconditional_set_state_functions: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
let next_block_id = env.next_block_id().0;
|
||||
let diagnostics = validate_impl(
|
||||
func,
|
||||
@@ -52,9 +52,9 @@ fn validate_impl(
|
||||
functions: &[HirFunction],
|
||||
next_block_id_counter: u32,
|
||||
enable_use_keyed_state: bool,
|
||||
unconditional_set_state_functions: &mut HashSet<IdentifierId>,
|
||||
unconditional_set_state_functions: &mut FxHashSet<IdentifierId>,
|
||||
) -> Result<Vec<CompilerDiagnostic>, CompilerDiagnostic> {
|
||||
let unconditional_blocks: HashSet<BlockId> =
|
||||
let unconditional_blocks: FxHashSet<BlockId> =
|
||||
compute_unconditional_blocks(func, next_block_id_counter)?;
|
||||
let mut active_manual_memo_id: Option<u32> = None;
|
||||
let mut errors: Vec<CompilerDiagnostic> = Vec::new();
|
||||
|
||||
+14
-14
@@ -9,7 +9,7 @@
|
||||
//! accurately preserved, and that no originally memoized values became
|
||||
//! unmemoized in the output.
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_diagnostics::{
|
||||
CompilerDiagnostic, CompilerDiagnosticDetail, ErrorCategory, SourceLocation,
|
||||
@@ -25,11 +25,11 @@ use react_compiler_hir::{
|
||||
/// State tracked during manual memo validation within a StartMemoize..FinishMemoize range.
|
||||
struct ManualMemoBlockState {
|
||||
/// Reassigned temporaries (declaration_id -> set of identifier ids that were reassigned to it).
|
||||
reassignments: HashMap<DeclarationId, HashSet<IdentifierId>>,
|
||||
reassignments: FxHashMap<DeclarationId, FxHashSet<IdentifierId>>,
|
||||
/// Source location of the StartMemoize instruction.
|
||||
loc: Option<SourceLocation>,
|
||||
/// Declarations produced within this manual memo block.
|
||||
decls: HashSet<DeclarationId>,
|
||||
decls: FxHashSet<DeclarationId>,
|
||||
/// Normalized deps from source (useMemo/useCallback dep array).
|
||||
deps_from_source: Option<Vec<ManualMemoDependency>>,
|
||||
/// Manual memo id from StartMemoize.
|
||||
@@ -41,11 +41,11 @@ struct VisitorState<'a> {
|
||||
env: &'a mut Environment,
|
||||
manual_memo_state: Option<ManualMemoBlockState>,
|
||||
/// Completed (non-pruned) scope IDs.
|
||||
scopes: HashSet<ScopeId>,
|
||||
scopes: FxHashSet<ScopeId>,
|
||||
/// Completed pruned scope IDs.
|
||||
pruned_scopes: HashSet<ScopeId>,
|
||||
pruned_scopes: FxHashSet<ScopeId>,
|
||||
/// Map from identifier ID to its normalized manual memo dependency.
|
||||
temporaries: HashMap<IdentifierId, ManualMemoDependency>,
|
||||
temporaries: FxHashMap<IdentifierId, ManualMemoDependency>,
|
||||
}
|
||||
|
||||
/// Validate that manual memoization (useMemo/useCallback) is preserved.
|
||||
@@ -59,9 +59,9 @@ pub fn validate_preserved_manual_memoization(func: &ReactiveFunction, env: &mut
|
||||
let mut state = VisitorState {
|
||||
env,
|
||||
manual_memo_state: None,
|
||||
scopes: HashSet::new(),
|
||||
pruned_scopes: HashSet::new(),
|
||||
temporaries: HashMap::new(),
|
||||
scopes: FxHashSet::default(),
|
||||
pruned_scopes: FxHashSet::default(),
|
||||
temporaries: FxHashMap::default(),
|
||||
};
|
||||
visit_block(&func.body, &mut state);
|
||||
}
|
||||
@@ -203,10 +203,10 @@ fn visit_instruction(instr: &ReactiveInstruction, state: &mut VisitorState) {
|
||||
|
||||
state.manual_memo_state = Some(ManualMemoBlockState {
|
||||
loc: instr.loc,
|
||||
decls: HashSet::new(),
|
||||
decls: FxHashSet::default(),
|
||||
deps_from_source,
|
||||
manual_memo_id: *manual_memo_id,
|
||||
reassignments: HashMap::new(),
|
||||
reassignments: FxHashMap::default(),
|
||||
});
|
||||
|
||||
// Check that each dependency's scope has completed before the memo
|
||||
@@ -518,7 +518,7 @@ fn destructure_lvalue_places(pattern: &react_compiler_hir::Pattern) -> Vec<&Plac
|
||||
/// Check if an identifier is unmemoized (has a scope that hasn't completed).
|
||||
fn is_unmemoized(
|
||||
id: IdentifierId,
|
||||
completed_scopes: &HashSet<ScopeId>,
|
||||
completed_scopes: &FxHashSet<ScopeId>,
|
||||
identifiers: &[Identifier],
|
||||
) -> bool {
|
||||
let ident = &identifiers[id.0 as usize];
|
||||
@@ -675,8 +675,8 @@ fn get_compare_dependency_result_description(result: CompareDependencyResult) ->
|
||||
fn validate_inferred_dep(
|
||||
dep_id: IdentifierId,
|
||||
dep_path: &[DependencyPathEntry],
|
||||
temporaries: &HashMap<IdentifierId, ManualMemoDependency>,
|
||||
decls_within_memo_block: &HashSet<DeclarationId>,
|
||||
temporaries: &FxHashMap<IdentifierId, ManualMemoDependency>,
|
||||
decls_within_memo_block: &FxHashSet<DeclarationId>,
|
||||
valid_deps_in_memo_block: &[ManualMemoDependency],
|
||||
env: &mut Environment,
|
||||
memo_location: Option<SourceLocation>,
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
//!
|
||||
//! Port of ValidateStaticComponents.ts.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use react_compiler_diagnostics::{
|
||||
CompilerDiagnostic, CompilerDiagnosticDetail, CompilerError, ErrorCategory, SourceLocation,
|
||||
@@ -22,8 +22,8 @@ use react_compiler_hir::{HirFunction, IdentifierId, InstructionValue, JsxTag};
|
||||
/// Called via `env.logErrors()` pattern in Pipeline.ts.
|
||||
pub fn validate_static_components(func: &HirFunction) -> CompilerError {
|
||||
let mut error = CompilerError::new();
|
||||
let mut known_dynamic_components: HashMap<IdentifierId, Option<SourceLocation>> =
|
||||
HashMap::new();
|
||||
let mut known_dynamic_components: FxHashMap<IdentifierId, Option<SourceLocation>> =
|
||||
FxHashMap::default();
|
||||
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
// Process phis: propagate dynamic component knowledge through phi nodes
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use react_compiler_diagnostics::{
|
||||
CompilerDiagnostic, CompilerDiagnosticDetail, CompilerError, ErrorCategory, SourceLocation,
|
||||
@@ -38,11 +38,11 @@ fn validate_use_memo_impl(
|
||||
validate_no_void_use_memo: bool,
|
||||
) -> CompilerError {
|
||||
let mut void_memo_errors = CompilerError::new();
|
||||
let mut use_memos: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut react: HashSet<IdentifierId> = HashSet::new();
|
||||
let mut func_exprs: HashMap<IdentifierId, FuncExprInfo> = HashMap::new();
|
||||
let mut unused_use_memos: HashMap<IdentifierId, (SourceLocation, Option<String>)> =
|
||||
HashMap::new();
|
||||
let mut use_memos: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
let mut react: FxHashSet<IdentifierId> = FxHashSet::default();
|
||||
let mut func_exprs: FxHashMap<IdentifierId, FuncExprInfo> = FxHashMap::default();
|
||||
let mut unused_use_memos: FxHashMap<IdentifierId, (SourceLocation, Option<String>)> =
|
||||
FxHashMap::default();
|
||||
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
for &instr_id in &block.instructions {
|
||||
@@ -157,9 +157,9 @@ fn handle_possible_use_memo_call(
|
||||
functions: &[HirFunction],
|
||||
errors: &mut CompilerError,
|
||||
void_memo_errors: &mut CompilerError,
|
||||
use_memos: &HashSet<IdentifierId>,
|
||||
func_exprs: &HashMap<IdentifierId, FuncExprInfo>,
|
||||
unused_use_memos: &mut HashMap<IdentifierId, (SourceLocation, Option<String>)>,
|
||||
use_memos: &FxHashSet<IdentifierId>,
|
||||
func_exprs: &FxHashMap<IdentifierId, FuncExprInfo>,
|
||||
unused_use_memos: &mut FxHashMap<IdentifierId, (SourceLocation, Option<String>)>,
|
||||
callee: &Place,
|
||||
args: &[PlaceOrSpread],
|
||||
lvalue: &Place,
|
||||
@@ -254,7 +254,7 @@ fn handle_possible_use_memo_call(
|
||||
}
|
||||
|
||||
fn validate_no_context_variable_assignment(func: &HirFunction, errors: &mut CompilerError) {
|
||||
let context: HashSet<IdentifierId> =
|
||||
let context: FxHashSet<IdentifierId> =
|
||||
func.context.iter().map(|place| place.identifier).collect();
|
||||
|
||||
for (_block_id, block) in &func.body.blocks {
|
||||
|
||||
Reference in New Issue
Block a user