1pub mod default_module_type_provider;2pub mod dominator;3pub mod environment;4pub mod environment_config;5pub mod globals;6pub mod object_shape;7pub mod print;8pub mod reactive;9pub mod type_config;10pub mod visitors;1112use indexmap::{IndexMap, IndexSet};13pub use react_compiler_diagnostics::CompilerDiagnostic;14pub use react_compiler_diagnostics::ErrorCategory;15pub use react_compiler_diagnostics::GENERATED_SOURCE;16pub use react_compiler_diagnostics::Position;17pub use react_compiler_diagnostics::SourceLocation;18pub use reactive::*;19use rustc_hash::FxBuildHasher;2021// =============================================================================22// ID newtypes23// =============================================================================2425#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]26pub struct BlockId(pub u32);2728#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]29pub struct IdentifierId(pub u32);3031/// Index into the flat instruction table on HirFunction.32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]33pub struct InstructionId(pub u32);3435/// Evaluation order assigned to instructions and terminals during numbering.36/// This was previously called InstructionId in the TypeScript compiler.37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]38pub struct EvaluationOrder(pub u32);3940#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]41pub struct DeclarationId(pub u32);4243#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]44pub struct ScopeId(pub u32);4546#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]47pub struct TypeId(pub u32);4849#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]50pub struct FunctionId(pub u32);5152#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]53pub struct MutableRangeId(pub u32);5455// =============================================================================56// FloatValue wrapper57// =============================================================================5859/// Wrapper around f64 that stores raw bytes for deterministic equality and hashing.60/// This allows use in FxHashMap keys and ensures NaN == NaN (bitwise comparison).61#[derive(Debug, Clone, Copy)]62pub struct FloatValue(u64);6364impl FloatValue {65 pub fn new(value: f64) -> Self {66 FloatValue(value.to_bits())67 }6869 pub fn value(self) -> f64 {70 f64::from_bits(self.0)71 }72}7374impl From<f64> for FloatValue {75 fn from(value: f64) -> Self {76 FloatValue::new(value)77 }78}7980impl From<FloatValue> for f64 {81 fn from(value: FloatValue) -> Self {82 value.value()83 }84}8586impl PartialEq for FloatValue {87 fn eq(&self, other: &Self) -> bool {88 self.0 == other.089 }90}9192impl Eq for FloatValue {}9394impl std::hash::Hash for FloatValue {95 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {96 self.0.hash(state);97 }98}99100impl std::fmt::Display for FloatValue {101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {102 write!(f, "{}", format_js_number(self.value()))103 }104}105106/// Format an f64 the way JavaScript's `Number.prototype.toString()` does.107///108/// Key differences from Rust's default `Display`:109/// - Uses scientific notation for |x| >= 1e21 (e.g. `1e+21`, `2.18739127891275e+22`)110/// - Uses scientific notation for 0 < |x| < 1e-6 (e.g. `1e-7`, `1.5e-8`)111/// - Uses minimal significant digits that round-trip to the same f64112/// - Formats -0 as "0"113pub fn format_js_number(n: f64) -> String {114 if n.is_nan() {115 return "NaN".to_string();116 }117 if n.is_infinite() {118 return if n > 0.0 {119 "Infinity".to_string()120 } else {121 "-Infinity".to_string()122 };123 }124 if n == 0.0 {125 return "0".to_string();126 }127128 let abs = n.abs();129 let sign = if n < 0.0 { "-" } else { "" };130131 if abs >= 1e21 || (abs > 0.0 && abs < 1e-6) {132 // Use scientific notation matching JS format: coefficient + "e+" or "e-" + exponent133 // Rust's {:e} uses "e" (lowercase) like JS, but formats as e.g. "1.5e21" not "1.5e+21"134 let formatted = format!("{:e}", abs);135 // Split into coefficient and exponent parts136 let (coeff, exp_str) = formatted.split_once('e').unwrap();137 let exp: i32 = exp_str.parse().unwrap();138 // JS uses e+N for positive exponents, e-N for negative139 if exp >= 0 {140 format!("{}{}e+{}", sign, coeff, exp)141 } else {142 format!("{}{}e-{}", sign, coeff, exp.unsigned_abs())143 }144 } else if abs.fract() == 0.0 && abs < (i64::MAX as f64) {145 // Integer that fits in i64 — format without decimal point146 format!("{}{}", sign, abs as i64)147 } else {148 // Regular float: Rust's default Display gives us the right digits149 format!("{}", n)150 }151}152153// =============================================================================154// Core HIR types155// =============================================================================156157/// A function lowered to HIR form158#[derive(Debug, Clone)]159pub struct HirFunction {160 pub loc: Option<SourceLocation>,161 pub id: Option<String>,162 pub name_hint: Option<String>,163 pub fn_type: ReactFunctionType,164 pub params: Vec<ParamPattern>,165 pub return_type_annotation: Option<String>,166 pub returns: Place,167 pub context: Vec<Place>,168 pub body: HIR,169 pub instructions: Vec<Instruction>,170 pub generator: bool,171 pub is_async: bool,172 pub directives: Vec<String>,173 pub aliasing_effects: Option<Vec<AliasingEffect>>,174}175176#[derive(Debug, Clone, Copy, PartialEq, Eq)]177pub enum ReactFunctionType {178 Component,179 Hook,180 Other,181}182183#[derive(Debug, Clone)]184pub enum ParamPattern {185 Place(Place),186 Spread(SpreadPattern),187}188189/// The HIR control-flow graph190#[derive(Debug, Clone)]191pub struct HIR {192 pub entry: BlockId,193 pub blocks: IndexMap<BlockId, BasicBlock, FxBuildHasher>,194}195196/// Block kinds197#[derive(Debug, Clone, Copy, PartialEq, Eq)]198pub enum BlockKind {199 Block,200 Value,201 Loop,202 Sequence,203 Catch,204}205206impl std::fmt::Display for BlockKind {207 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {208 match self {209 BlockKind::Block => write!(f, "block"),210 BlockKind::Value => write!(f, "value"),211 BlockKind::Loop => write!(f, "loop"),212 BlockKind::Sequence => write!(f, "sequence"),213 BlockKind::Catch => write!(f, "catch"),214 }215 }216}217218/// A basic block in the CFG219#[derive(Debug, Clone)]220pub struct BasicBlock {221 pub kind: BlockKind,222 pub id: BlockId,223 pub instructions: Vec<InstructionId>,224 pub terminal: Terminal,225 pub preds: IndexSet<BlockId, FxBuildHasher>,226 pub phis: Vec<Phi>,227}228229/// Phi node for SSA230#[derive(Debug, Clone)]231pub struct Phi {232 pub place: Place,233 pub operands: IndexMap<BlockId, Place, FxBuildHasher>,234}235236// =============================================================================237// Terminal enum238// =============================================================================239240#[derive(Debug, Clone)]241pub enum Terminal {242 Unsupported {243 id: EvaluationOrder,244 loc: Option<SourceLocation>,245 },246 Unreachable {247 id: EvaluationOrder,248 loc: Option<SourceLocation>,249 },250 Throw {251 value: Place,252 id: EvaluationOrder,253 loc: Option<SourceLocation>,254 },255 Return {256 value: Place,257 return_variant: ReturnVariant,258 id: EvaluationOrder,259 loc: Option<SourceLocation>,260 effects: Option<Vec<AliasingEffect>>,261 },262 Goto {263 block: BlockId,264 variant: GotoVariant,265 id: EvaluationOrder,266 loc: Option<SourceLocation>,267 },268 If {269 test: Place,270 consequent: BlockId,271 alternate: BlockId,272 fallthrough: BlockId,273 id: EvaluationOrder,274 loc: Option<SourceLocation>,275 },276 Branch {277 test: Place,278 consequent: BlockId,279 alternate: BlockId,280 fallthrough: BlockId,281 id: EvaluationOrder,282 loc: Option<SourceLocation>,283 },284 Switch {285 test: Place,286 cases: Vec<Case>,287 fallthrough: BlockId,288 id: EvaluationOrder,289 loc: Option<SourceLocation>,290 },291 DoWhile {292 loop_block: BlockId,293 test: BlockId,294 fallthrough: BlockId,295 id: EvaluationOrder,296 loc: Option<SourceLocation>,297 },298 While {299 test: BlockId,300 loop_block: BlockId,301 fallthrough: BlockId,302 id: EvaluationOrder,303 loc: Option<SourceLocation>,304 },305 For {306 init: BlockId,307 test: BlockId,308 update: Option<BlockId>,309 loop_block: BlockId,310 fallthrough: BlockId,311 id: EvaluationOrder,312 loc: Option<SourceLocation>,313 },314 ForOf {315 init: BlockId,316 test: BlockId,317 loop_block: BlockId,318 fallthrough: BlockId,319 id: EvaluationOrder,320 loc: Option<SourceLocation>,321 },322 ForIn {323 init: BlockId,324 loop_block: BlockId,325 fallthrough: BlockId,326 id: EvaluationOrder,327 loc: Option<SourceLocation>,328 },329 Logical {330 operator: LogicalOperator,331 test: BlockId,332 fallthrough: BlockId,333 id: EvaluationOrder,334 loc: Option<SourceLocation>,335 },336 Ternary {337 test: BlockId,338 fallthrough: BlockId,339 id: EvaluationOrder,340 loc: Option<SourceLocation>,341 },342 Optional {343 optional: bool,344 test: BlockId,345 fallthrough: BlockId,346 id: EvaluationOrder,347 loc: Option<SourceLocation>,348 },349 Label {350 block: BlockId,351 fallthrough: BlockId,352 id: EvaluationOrder,353 loc: Option<SourceLocation>,354 },355 Sequence {356 block: BlockId,357 fallthrough: BlockId,358 id: EvaluationOrder,359 loc: Option<SourceLocation>,360 },361 MaybeThrow {362 continuation: BlockId,363 handler: Option<BlockId>,364 id: EvaluationOrder,365 loc: Option<SourceLocation>,366 effects: Option<Vec<AliasingEffect>>,367 },368 Try {369 block: BlockId,370 handler_binding: Option<Place>,371 handler: BlockId,372 fallthrough: BlockId,373 id: EvaluationOrder,374 loc: Option<SourceLocation>,375 },376 Scope {377 fallthrough: BlockId,378 block: BlockId,379 scope: ScopeId,380 id: EvaluationOrder,381 loc: Option<SourceLocation>,382 },383 PrunedScope {384 fallthrough: BlockId,385 block: BlockId,386 scope: ScopeId,387 id: EvaluationOrder,388 loc: Option<SourceLocation>,389 },390}391392impl Terminal {393 /// Get the evaluation order of this terminal394 pub fn evaluation_order(&self) -> EvaluationOrder {395 match self {396 Terminal::Unsupported { id, .. }397 | Terminal::Unreachable { id, .. }398 | Terminal::Throw { id, .. }399 | Terminal::Return { id, .. }400 | Terminal::Goto { id, .. }401 | Terminal::If { id, .. }402 | Terminal::Branch { id, .. }403 | Terminal::Switch { id, .. }404 | Terminal::DoWhile { id, .. }405 | Terminal::While { id, .. }406 | Terminal::For { id, .. }407 | Terminal::ForOf { id, .. }408 | Terminal::ForIn { id, .. }409 | Terminal::Logical { id, .. }410 | Terminal::Ternary { id, .. }411 | Terminal::Optional { id, .. }412 | Terminal::Label { id, .. }413 | Terminal::Sequence { id, .. }414 | Terminal::MaybeThrow { id, .. }415 | Terminal::Try { id, .. }416 | Terminal::Scope { id, .. }417 | Terminal::PrunedScope { id, .. } => *id,418 }419 }420421 /// Get the source location of this terminal422 pub fn loc(&self) -> Option<&SourceLocation> {423 match self {424 Terminal::Unsupported { loc, .. }425 | Terminal::Unreachable { loc, .. }426 | Terminal::Throw { loc, .. }427 | Terminal::Return { loc, .. }428 | Terminal::Goto { loc, .. }429 | Terminal::If { loc, .. }430 | Terminal::Branch { loc, .. }431 | Terminal::Switch { loc, .. }432 | Terminal::DoWhile { loc, .. }433 | Terminal::While { loc, .. }434 | Terminal::For { loc, .. }435 | Terminal::ForOf { loc, .. }436 | Terminal::ForIn { loc, .. }437 | Terminal::Logical { loc, .. }438 | Terminal::Ternary { loc, .. }439 | Terminal::Optional { loc, .. }440 | Terminal::Label { loc, .. }441 | Terminal::Sequence { loc, .. }442 | Terminal::MaybeThrow { loc, .. }443 | Terminal::Try { loc, .. }444 | Terminal::Scope { loc, .. }445 | Terminal::PrunedScope { loc, .. } => loc.as_ref(),446 }447 }448449 /// Set the evaluation order of this terminal450 pub fn set_evaluation_order(&mut self, new_id: EvaluationOrder) {451 match self {452 Terminal::Unsupported { id, .. }453 | Terminal::Unreachable { id, .. }454 | Terminal::Throw { id, .. }455 | Terminal::Return { id, .. }456 | Terminal::Goto { id, .. }457 | Terminal::If { id, .. }458 | Terminal::Branch { id, .. }459 | Terminal::Switch { id, .. }460 | Terminal::DoWhile { id, .. }461 | Terminal::While { id, .. }462 | Terminal::For { id, .. }463 | Terminal::ForOf { id, .. }464 | Terminal::ForIn { id, .. }465 | Terminal::Logical { id, .. }466 | Terminal::Ternary { id, .. }467 | Terminal::Optional { id, .. }468 | Terminal::Label { id, .. }469 | Terminal::Sequence { id, .. }470 | Terminal::MaybeThrow { id, .. }471 | Terminal::Try { id, .. }472 | Terminal::Scope { id, .. }473 | Terminal::PrunedScope { id, .. } => *id = new_id,474 }475 }476}477478#[derive(Debug, Clone, Copy, PartialEq, Eq)]479pub enum ReturnVariant {480 Void,481 Implicit,482 Explicit,483}484485#[derive(Debug, Clone, Copy, PartialEq, Eq)]486pub enum GotoVariant {487 Break,488 Continue,489 Try,490}491492#[derive(Debug, Clone)]493pub struct Case {494 pub test: Option<Place>,495 pub block: BlockId,496}497498#[derive(Debug, Clone, Copy, PartialEq, Eq)]499pub enum LogicalOperator {500 And,501 Or,502 NullishCoalescing,503}504505impl std::fmt::Display for LogicalOperator {506 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {507 match self {508 LogicalOperator::And => write!(f, "&&"),509 LogicalOperator::Or => write!(f, "||"),510 LogicalOperator::NullishCoalescing => write!(f, "??"),511 }512 }513}514515// =============================================================================516// Instruction types517// =============================================================================518519#[derive(Debug, Clone)]520pub struct Instruction {521 pub id: EvaluationOrder,522 pub lvalue: Place,523 pub value: InstructionValue,524 pub loc: Option<SourceLocation>,525 pub effects: Option<Vec<AliasingEffect>>,526}527528#[derive(Debug, Clone, Copy, PartialEq, Eq)]529pub enum InstructionKind {530 Const,531 Let,532 Reassign,533 Catch,534 HoistedConst,535 HoistedLet,536 HoistedFunction,537 Function,538}539540#[derive(Debug, Clone)]541pub struct LValue {542 pub place: Place,543 pub kind: InstructionKind,544}545546#[derive(Debug, Clone)]547pub struct LValuePattern {548 pub pattern: Pattern,549 pub kind: InstructionKind,550}551552#[derive(Debug, Clone)]553pub enum Pattern {554 Array(ArrayPattern),555 Object(ObjectPattern),556}557558// =============================================================================559// InstructionValue enum560// =============================================================================561562#[derive(Debug, Clone)]563pub enum InstructionValue {564 LoadLocal {565 place: Place,566 loc: Option<SourceLocation>,567 },568 LoadContext {569 place: Place,570 loc: Option<SourceLocation>,571 },572 DeclareLocal {573 lvalue: LValue,574 type_annotation: Option<String>,575 loc: Option<SourceLocation>,576 },577 DeclareContext {578 lvalue: LValue,579 loc: Option<SourceLocation>,580 },581 StoreLocal {582 lvalue: LValue,583 value: Place,584 type_annotation: Option<String>,585 loc: Option<SourceLocation>,586 },587 StoreContext {588 lvalue: LValue,589 value: Place,590 loc: Option<SourceLocation>,591 },592 Destructure {593 lvalue: LValuePattern,594 value: Place,595 loc: Option<SourceLocation>,596 },597 Primitive {598 value: PrimitiveValue,599 loc: Option<SourceLocation>,600 },601 JSXText {602 value: String,603 loc: Option<SourceLocation>,604 },605 BinaryExpression {606 operator: BinaryOperator,607 left: Place,608 right: Place,609 loc: Option<SourceLocation>,610 },611 NewExpression {612 callee: Place,613 args: Vec<PlaceOrSpread>,614 loc: Option<SourceLocation>,615 },616 CallExpression {617 callee: Place,618 args: Vec<PlaceOrSpread>,619 loc: Option<SourceLocation>,620 },621 MethodCall {622 receiver: Place,623 property: Place,624 args: Vec<PlaceOrSpread>,625 loc: Option<SourceLocation>,626 },627 UnaryExpression {628 operator: UnaryOperator,629 value: Place,630 loc: Option<SourceLocation>,631 },632 TypeCastExpression {633 value: Place,634 type_: Type,635 type_annotation_name: Option<String>,636 type_annotation_kind: Option<String>,637 /// The original AST type annotation node, preserved for codegen.638 /// For Flow: the inner type from TypeAnnotation.typeAnnotation639 /// For TS: the TSType node from TSAsExpression/TSSatisfiesExpression640 type_annotation: Option<Box<serde_json::Value>>,641 loc: Option<SourceLocation>,642 },643 JsxExpression {644 tag: JsxTag,645 props: Vec<JsxAttribute>,646 children: Option<Vec<Place>>,647 loc: Option<SourceLocation>,648 opening_loc: Option<SourceLocation>,649 closing_loc: Option<SourceLocation>,650 },651 ObjectExpression {652 properties: Vec<ObjectPropertyOrSpread>,653 loc: Option<SourceLocation>,654 },655 ObjectMethod {656 loc: Option<SourceLocation>,657 lowered_func: LoweredFunction,658 },659 ArrayExpression {660 elements: Vec<ArrayElement>,661 loc: Option<SourceLocation>,662 },663 JsxFragment {664 children: Vec<Place>,665 loc: Option<SourceLocation>,666 },667 RegExpLiteral {668 pattern: String,669 flags: String,670 loc: Option<SourceLocation>,671 },672 MetaProperty {673 meta: String,674 property: String,675 loc: Option<SourceLocation>,676 },677 PropertyStore {678 object: Place,679 property: PropertyLiteral,680 value: Place,681 loc: Option<SourceLocation>,682 },683 PropertyLoad {684 object: Place,685 property: PropertyLiteral,686 loc: Option<SourceLocation>,687 },688 PropertyDelete {689 object: Place,690 property: PropertyLiteral,691 loc: Option<SourceLocation>,692 },693 ComputedStore {694 object: Place,695 property: Place,696 value: Place,697 loc: Option<SourceLocation>,698 },699 ComputedLoad {700 object: Place,701 property: Place,702 loc: Option<SourceLocation>,703 },704 ComputedDelete {705 object: Place,706 property: Place,707 loc: Option<SourceLocation>,708 },709 LoadGlobal {710 binding: NonLocalBinding,711 loc: Option<SourceLocation>,712 },713 StoreGlobal {714 name: String,715 value: Place,716 loc: Option<SourceLocation>,717 },718 FunctionExpression {719 name: Option<String>,720 name_hint: Option<String>,721 lowered_func: LoweredFunction,722 expr_type: FunctionExpressionType,723 loc: Option<SourceLocation>,724 },725 TaggedTemplateExpression {726 tag: Place,727 value: TemplateQuasi,728 loc: Option<SourceLocation>,729 },730 TemplateLiteral {731 subexprs: Vec<Place>,732 quasis: Vec<TemplateQuasi>,733 loc: Option<SourceLocation>,734 },735 Await {736 value: Place,737 loc: Option<SourceLocation>,738 },739 GetIterator {740 collection: Place,741 loc: Option<SourceLocation>,742 },743 IteratorNext {744 iterator: Place,745 collection: Place,746 loc: Option<SourceLocation>,747 },748 NextPropertyOf {749 value: Place,750 loc: Option<SourceLocation>,751 },752 PrefixUpdate {753 lvalue: Place,754 operation: UpdateOperator,755 value: Place,756 loc: Option<SourceLocation>,757 },758 PostfixUpdate {759 lvalue: Place,760 operation: UpdateOperator,761 value: Place,762 loc: Option<SourceLocation>,763 },764 Debugger {765 loc: Option<SourceLocation>,766 },767 StartMemoize {768 manual_memo_id: u32,769 deps: Option<Vec<ManualMemoDependency>>,770 deps_loc: Option<Option<SourceLocation>>,771 has_invalid_deps: bool,772 loc: Option<SourceLocation>,773 },774 FinishMemoize {775 manual_memo_id: u32,776 decl: Place,777 pruned: bool,778 loc: Option<SourceLocation>,779 },780 UnsupportedNode {781 node_type: Option<String>,782 /// The original AST node serialized as JSON, so codegen can emit it verbatim.783 original_node: Option<serde_json::Value>,784 loc: Option<SourceLocation>,785 },786}787788impl InstructionValue {789 pub fn loc(&self) -> Option<&SourceLocation> {790 match self {791 InstructionValue::LoadLocal { loc, .. }792 | InstructionValue::LoadContext { loc, .. }793 | InstructionValue::DeclareLocal { loc, .. }794 | InstructionValue::DeclareContext { loc, .. }795 | InstructionValue::StoreLocal { loc, .. }796 | InstructionValue::StoreContext { loc, .. }797 | InstructionValue::Destructure { loc, .. }798 | InstructionValue::Primitive { loc, .. }799 | InstructionValue::JSXText { loc, .. }800 | InstructionValue::BinaryExpression { loc, .. }801 | InstructionValue::NewExpression { loc, .. }802 | InstructionValue::CallExpression { loc, .. }803 | InstructionValue::MethodCall { loc, .. }804 | InstructionValue::UnaryExpression { loc, .. }805 | InstructionValue::TypeCastExpression { loc, .. }806 | InstructionValue::JsxExpression { loc, .. }807 | InstructionValue::ObjectExpression { loc, .. }808 | InstructionValue::ObjectMethod { loc, .. }809 | InstructionValue::ArrayExpression { loc, .. }810 | InstructionValue::JsxFragment { loc, .. }811 | InstructionValue::RegExpLiteral { loc, .. }812 | InstructionValue::MetaProperty { loc, .. }813 | InstructionValue::PropertyStore { loc, .. }814 | InstructionValue::PropertyLoad { loc, .. }815 | InstructionValue::PropertyDelete { loc, .. }816 | InstructionValue::ComputedStore { loc, .. }817 | InstructionValue::ComputedLoad { loc, .. }818 | InstructionValue::ComputedDelete { loc, .. }819 | InstructionValue::LoadGlobal { loc, .. }820 | InstructionValue::StoreGlobal { loc, .. }821 | InstructionValue::FunctionExpression { loc, .. }822 | InstructionValue::TaggedTemplateExpression { loc, .. }823 | InstructionValue::TemplateLiteral { loc, .. }824 | InstructionValue::Await { loc, .. }825 | InstructionValue::GetIterator { loc, .. }826 | InstructionValue::IteratorNext { loc, .. }827 | InstructionValue::NextPropertyOf { loc, .. }828 | InstructionValue::PrefixUpdate { loc, .. }829 | InstructionValue::PostfixUpdate { loc, .. }830 | InstructionValue::Debugger { loc, .. }831 | InstructionValue::StartMemoize { loc, .. }832 | InstructionValue::FinishMemoize { loc, .. }833 | InstructionValue::UnsupportedNode { loc, .. } => loc.as_ref(),834 }835 }836}837838// =============================================================================839// Supporting types840// =============================================================================841842#[derive(Debug, Clone, PartialEq, Eq, Hash)]843pub enum PrimitiveValue {844 Null,845 Undefined,846 Boolean(bool),847 Number(FloatValue),848 String(react_compiler_diagnostics::JsString),849}850851#[derive(Debug, Clone, Copy, PartialEq, Eq)]852pub enum BinaryOperator {853 Equal,854 NotEqual,855 StrictEqual,856 StrictNotEqual,857 LessThan,858 LessEqual,859 GreaterThan,860 GreaterEqual,861 ShiftLeft,862 ShiftRight,863 UnsignedShiftRight,864 Add,865 Subtract,866 Multiply,867 Divide,868 Modulo,869 Exponent,870 BitwiseOr,871 BitwiseXor,872 BitwiseAnd,873 In,874 InstanceOf,875}876877impl std::fmt::Display for BinaryOperator {878 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {879 match self {880 BinaryOperator::Equal => write!(f, "=="),881 BinaryOperator::NotEqual => write!(f, "!="),882 BinaryOperator::StrictEqual => write!(f, "==="),883 BinaryOperator::StrictNotEqual => write!(f, "!=="),884 BinaryOperator::LessThan => write!(f, "<"),885 BinaryOperator::LessEqual => write!(f, "<="),886 BinaryOperator::GreaterThan => write!(f, ">"),887 BinaryOperator::GreaterEqual => write!(f, ">="),888 BinaryOperator::ShiftLeft => write!(f, "<<"),889 BinaryOperator::ShiftRight => write!(f, ">>"),890 BinaryOperator::UnsignedShiftRight => write!(f, ">>>"),891 BinaryOperator::Add => write!(f, "+"),892 BinaryOperator::Subtract => write!(f, "-"),893 BinaryOperator::Multiply => write!(f, "*"),894 BinaryOperator::Divide => write!(f, "/"),895 BinaryOperator::Modulo => write!(f, "%"),896 BinaryOperator::Exponent => write!(f, "**"),897 BinaryOperator::BitwiseOr => write!(f, "|"),898 BinaryOperator::BitwiseXor => write!(f, "^"),899 BinaryOperator::BitwiseAnd => write!(f, "&"),900 BinaryOperator::In => write!(f, "in"),901 BinaryOperator::InstanceOf => write!(f, "instanceof"),902 }903 }904}905906#[derive(Debug, Clone, Copy, PartialEq, Eq)]907pub enum UnaryOperator {908 Minus,909 Plus,910 Not,911 BitwiseNot,912 TypeOf,913 Void,914}915916impl std::fmt::Display for UnaryOperator {917 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {918 match self {919 UnaryOperator::Minus => write!(f, "-"),920 UnaryOperator::Plus => write!(f, "+"),921 UnaryOperator::Not => write!(f, "!"),922 UnaryOperator::BitwiseNot => write!(f, "~"),923 UnaryOperator::TypeOf => write!(f, "typeof"),924 UnaryOperator::Void => write!(f, "void"),925 }926 }927}928929#[derive(Debug, Clone, Copy, PartialEq, Eq)]930pub enum UpdateOperator {931 Increment,932 Decrement,933}934935impl std::fmt::Display for UpdateOperator {936 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {937 match self {938 UpdateOperator::Increment => write!(f, "++"),939 UpdateOperator::Decrement => write!(f, "--"),940 }941 }942}943944#[derive(Debug, Clone, Copy, PartialEq, Eq)]945pub enum FunctionExpressionType {946 ArrowFunctionExpression,947 FunctionExpression,948 FunctionDeclaration,949}950951#[derive(Debug, Clone)]952pub struct TemplateQuasi {953 pub raw: String,954 pub cooked: Option<String>,955}956957#[derive(Debug, Clone)]958pub struct ManualMemoDependency {959 pub root: ManualMemoDependencyRoot,960 pub path: Vec<DependencyPathEntry>,961 pub loc: Option<SourceLocation>,962}963964#[derive(Debug, Clone)]965pub enum ManualMemoDependencyRoot {966 NamedLocal { value: Place, constant: bool },967 Global { identifier_name: String },968}969970#[derive(Debug, Clone, PartialEq, Eq)]971pub struct DependencyPathEntry {972 pub property: PropertyLiteral,973 pub optional: bool,974 pub loc: Option<SourceLocation>,975}976977// =============================================================================978// Place, Identifier, and related types979// =============================================================================980981#[derive(Debug, Clone)]982pub struct Place {983 pub identifier: IdentifierId,984 pub effect: Effect,985 pub reactive: bool,986 pub loc: Option<SourceLocation>,987}988989#[derive(Debug, Clone)]990pub struct Identifier {991 pub id: IdentifierId,992 pub declaration_id: DeclarationId,993 pub name: Option<IdentifierName>,994 pub mutable_range: MutableRange,995 pub scope: Option<ScopeId>,996 pub type_: TypeId,997 pub loc: Option<SourceLocation>,998}9991000#[derive(Debug, Clone)]1001pub struct MutableRange {1002 /// Unique identity for this logical range. Cloning preserves the ID1003 /// (same logical range); use `Environment::new_mutable_range()` to create1004 /// a range with a fresh ID.1005 pub id: MutableRangeId,1006 pub start: EvaluationOrder,1007 pub end: EvaluationOrder,1008}10091010impl MutableRange {1011 /// Returns true if the given evaluation order falls within this mutable range.1012 /// Corresponds to TS `inRange({id}, range)` / `isMutable(instr, place)`.1013 pub fn contains(&self, eval_order: EvaluationOrder) -> bool {1014 eval_order >= self.start && eval_order < self.end1015 }10161017 /// Returns true if this range has the same identity as `other`.1018 /// In the TS compiler, this corresponds to checking whether two mutableRange1019 /// references point to the same JS object (=== identity).1020 pub fn same_range(&self, other: &MutableRange) -> bool {1021 self.id == other.id1022 }1023}10241025#[derive(Debug, Clone)]1026pub enum IdentifierName {1027 Named(String),1028 Promoted(String),1029}10301031impl IdentifierName {1032 pub fn value(&self) -> &str {1033 match self {1034 IdentifierName::Named(v) | IdentifierName::Promoted(v) => v,1035 }1036 }1037}10381039#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]1040pub enum Effect {1041 #[serde(rename = "<unknown>")]1042 Unknown,1043 #[serde(rename = "freeze")]1044 Freeze,1045 #[serde(rename = "read")]1046 Read,1047 #[serde(rename = "capture")]1048 Capture,1049 #[serde(rename = "mutate-iterator?")]1050 ConditionallyMutateIterator,1051 #[serde(rename = "mutate?")]1052 ConditionallyMutate,1053 #[serde(rename = "mutate")]1054 Mutate,1055 #[serde(rename = "store")]1056 Store,1057}10581059impl Effect {1060 /// Returns true if this effect represents a mutable operation.1061 /// Mutable effects are: Capture, Store, ConditionallyMutate,1062 /// ConditionallyMutateIterator, and Mutate.1063 pub fn is_mutable(&self) -> bool {1064 matches!(1065 self,1066 Effect::Capture1067 | Effect::Store1068 | Effect::ConditionallyMutate1069 | Effect::ConditionallyMutateIterator1070 | Effect::Mutate1071 )1072 }1073}10741075impl std::fmt::Display for Effect {1076 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {1077 match self {1078 Effect::Unknown => write!(f, "<unknown>"),1079 Effect::Freeze => write!(f, "freeze"),1080 Effect::Read => write!(f, "read"),1081 Effect::Capture => write!(f, "capture"),1082 Effect::ConditionallyMutateIterator => write!(f, "mutate-iterator?"),1083 Effect::ConditionallyMutate => write!(f, "mutate?"),1084 Effect::Mutate => write!(f, "mutate"),1085 Effect::Store => write!(f, "store"),1086 }1087 }1088}10891090#[derive(Debug, Clone)]1091pub struct SpreadPattern {1092 pub place: Place,1093}10941095#[derive(Debug, Clone, Copy, PartialEq, Eq)]1096pub enum Hole {1097 Hole,1098}10991100#[derive(Debug, Clone)]1101pub struct ArrayPattern {1102 pub items: Vec<ArrayPatternElement>,1103 pub loc: Option<SourceLocation>,1104}11051106#[derive(Debug, Clone)]1107pub enum ArrayPatternElement {1108 Place(Place),1109 Spread(SpreadPattern),1110 Hole,1111}11121113#[derive(Debug, Clone)]1114pub struct ObjectPattern {1115 pub properties: Vec<ObjectPropertyOrSpread>,1116 pub loc: Option<SourceLocation>,1117}11181119#[derive(Debug, Clone)]1120pub enum ObjectPropertyOrSpread {1121 Property(ObjectProperty),1122 Spread(SpreadPattern),1123}11241125#[derive(Debug, Clone)]1126pub struct ObjectProperty {1127 pub key: ObjectPropertyKey,1128 pub property_type: ObjectPropertyType,1129 pub place: Place,1130}11311132#[derive(Debug, Clone)]1133pub enum ObjectPropertyKey {1134 String { name: String },1135 Identifier { name: String },1136 Computed { name: Place },1137 Number { name: FloatValue },1138}11391140#[derive(Debug, Clone, Copy, PartialEq, Eq)]1141pub enum ObjectPropertyType {1142 Property,1143 Method,1144}11451146impl std::fmt::Display for ObjectPropertyType {1147 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {1148 match self {1149 ObjectPropertyType::Property => write!(f, "property"),1150 ObjectPropertyType::Method => write!(f, "method"),1151 }1152 }1153}11541155#[derive(Debug, Clone, PartialEq, Eq, Hash)]1156pub enum PropertyLiteral {1157 String(String),1158 Number(FloatValue),1159}11601161impl std::fmt::Display for PropertyLiteral {1162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {1163 match self {1164 PropertyLiteral::String(s) => write!(f, "{}", s),1165 PropertyLiteral::Number(n) => write!(f, "{}", n),1166 }1167 }1168}11691170#[derive(Debug, Clone)]1171pub enum PlaceOrSpread {1172 Place(Place),1173 Spread(SpreadPattern),1174}11751176#[derive(Debug, Clone)]1177pub enum ArrayElement {1178 Place(Place),1179 Spread(SpreadPattern),1180 Hole,1181}11821183#[derive(Debug, Clone)]1184pub struct LoweredFunction {1185 pub func: FunctionId,1186}11871188#[derive(Debug, Clone)]1189pub struct BuiltinTag {1190 pub name: String,1191 pub loc: Option<SourceLocation>,1192}11931194#[derive(Debug, Clone)]1195pub enum JsxTag {1196 Place(Place),1197 Builtin(BuiltinTag),1198}11991200#[derive(Debug, Clone)]1201pub enum JsxAttribute {1202 SpreadAttribute { argument: Place },1203 Attribute { name: String, place: Place },1204}12051206// =============================================================================1207// Variable Binding types1208// =============================================================================12091210#[derive(Debug, Clone, Copy, PartialEq, Eq)]1211pub enum BindingKind {1212 Var,1213 Let,1214 Const,1215 Param,1216 Module,1217 Hoisted,1218 Local,1219 Unknown,1220}12211222#[derive(Debug, Clone)]1223pub enum VariableBinding {1224 Identifier {1225 identifier: IdentifierId,1226 binding_kind: BindingKind,1227 },1228 Global {1229 name: String,1230 },1231 ImportDefault {1232 name: String,1233 module: String,1234 },1235 ImportSpecifier {1236 name: String,1237 module: String,1238 imported: String,1239 },1240 ImportNamespace {1241 name: String,1242 module: String,1243 },1244 ModuleLocal {1245 name: String,1246 },1247}12481249#[derive(Debug, Clone)]1250pub enum NonLocalBinding {1251 ImportDefault {1252 name: String,1253 module: String,1254 },1255 ImportSpecifier {1256 name: String,1257 module: String,1258 imported: String,1259 },1260 ImportNamespace {1261 name: String,1262 module: String,1263 },1264 ModuleLocal {1265 name: String,1266 },1267 Global {1268 name: String,1269 },1270}12711272impl NonLocalBinding {1273 /// Returns the `name` field common to all variants.1274 pub fn name(&self) -> &str {1275 match self {1276 NonLocalBinding::ImportDefault { name, .. }1277 | NonLocalBinding::ImportSpecifier { name, .. }1278 | NonLocalBinding::ImportNamespace { name, .. }1279 | NonLocalBinding::ModuleLocal { name, .. }1280 | NonLocalBinding::Global { name, .. } => name,1281 }1282 }1283}12841285// =============================================================================1286// Type system (from Types.ts)1287// =============================================================================12881289#[derive(Debug, Clone)]1290pub enum Type {1291 Primitive,1292 Function {1293 shape_id: Option<String>,1294 return_type: Box<Type>,1295 is_constructor: bool,1296 },1297 Object {1298 shape_id: Option<String>,1299 },1300 TypeVar {1301 id: TypeId,1302 },1303 Poly,1304 Phi {1305 operands: Vec<Type>,1306 },1307 Property {1308 object_type: Box<Type>,1309 object_name: String,1310 property_name: PropertyNameKind,1311 },1312 ObjectMethod,1313}13141315#[derive(Debug, Clone)]1316pub enum PropertyNameKind {1317 Literal { value: PropertyLiteral },1318 Computed { value: Box<Type> },1319}13201321// =============================================================================1322// ReactiveScope1323// =============================================================================13241325#[derive(Debug, Clone)]1326pub struct ReactiveScope {1327 pub id: ScopeId,1328 pub range: MutableRange,13291330 /// The inputs to this reactive scope (populated by later passes)1331 pub dependencies: Vec<ReactiveScopeDependency>,13321333 /// The set of values produced by this scope (populated by later passes)1334 pub declarations: Vec<(IdentifierId, ReactiveScopeDeclaration)>,13351336 /// Identifiers which are reassigned by this scope (populated by later passes)1337 pub reassignments: Vec<IdentifierId>,13381339 /// If the scope contains an early return, this stores info about it (populated by later passes)1340 pub early_return_value: Option<ReactiveScopeEarlyReturn>,13411342 /// Scopes that were merged into this one (populated by later passes)1343 pub merged: Vec<ScopeId>,13441345 /// Source location spanning the scope1346 pub loc: Option<SourceLocation>,1347}13481349/// A dependency of a reactive scope.1350#[derive(Debug, Clone)]1351pub struct ReactiveScopeDependency {1352 pub identifier: IdentifierId,1353 pub reactive: bool,1354 pub path: Vec<DependencyPathEntry>,1355 pub loc: Option<SourceLocation>,1356}13571358/// A declaration produced by a reactive scope.1359#[derive(Debug, Clone)]1360pub struct ReactiveScopeDeclaration {1361 pub identifier: IdentifierId,1362 pub scope: ScopeId,1363}13641365/// Early return value info for a reactive scope.1366#[derive(Debug, Clone)]1367pub struct ReactiveScopeEarlyReturn {1368 pub value: IdentifierId,1369 pub loc: Option<SourceLocation>,1370 pub label: BlockId,1371}13721373// =============================================================================1374// Aliasing effects (runtime types, from AliasingEffects.ts)1375// =============================================================================13761377use crate::object_shape::FunctionSignature;1378use crate::type_config::ValueKind;1379use crate::type_config::ValueReason;13801381/// Reason for a mutation, used for generating hints (e.g. rename to "Ref").1382#[derive(Debug, Clone, PartialEq, Eq)]1383pub enum MutationReason {1384 AssignCurrentProperty,1385}13861387/// Describes the aliasing/mutation/data-flow effects of an instruction or terminal.1388/// Ported from TS `AliasingEffect` in `AliasingEffects.ts`.1389#[derive(Debug, Clone)]1390pub enum AliasingEffect {1391 /// Marks the given value and its direct aliases as frozen.1392 Freeze { value: Place, reason: ValueReason },1393 /// Mutate the value and any direct aliases.1394 Mutate {1395 value: Place,1396 reason: Option<MutationReason>,1397 },1398 /// Mutate the value conditionally (only if mutable).1399 MutateConditionally { value: Place },1400 /// Mutate the value and transitive captures.1401 MutateTransitive { value: Place },1402 /// Mutate the value and transitive captures conditionally.1403 MutateTransitiveConditionally { value: Place },1404 /// Information flow from `from` to `into` (non-aliasing capture).1405 Capture { from: Place, into: Place },1406 /// Direct aliasing: mutation of `into` implies mutation of `from`.1407 Alias { from: Place, into: Place },1408 /// Potential aliasing relationship.1409 MaybeAlias { from: Place, into: Place },1410 /// Direct assignment: `into = from`.1411 Assign { from: Place, into: Place },1412 /// Creates a value of the given kind at the given place.1413 Create {1414 into: Place,1415 value: ValueKind,1416 reason: ValueReason,1417 },1418 /// Creates a new value with the same kind as the source.1419 CreateFrom { from: Place, into: Place },1420 /// Immutable data flow (escape analysis only, no mutable range influence).1421 ImmutableCapture { from: Place, into: Place },1422 /// Function call application.1423 Apply {1424 receiver: Place,1425 function: Place,1426 mutates_function: bool,1427 args: Vec<PlaceOrSpreadOrHole>,1428 into: Place,1429 signature: Option<FunctionSignature>,1430 loc: Option<SourceLocation>,1431 },1432 /// Function expression creation with captures.1433 CreateFunction {1434 captures: Vec<Place>,1435 function_id: FunctionId,1436 into: Place,1437 },1438 /// Mutation of a value known to be frozen (error).1439 MutateFrozen {1440 place: Place,1441 error: CompilerDiagnostic,1442 },1443 /// Mutation of a global value (error).1444 MutateGlobal {1445 place: Place,1446 error: CompilerDiagnostic,1447 },1448 /// Side-effect not safe during render.1449 Impure {1450 place: Place,1451 error: CompilerDiagnostic,1452 },1453 /// Value is accessed during render.1454 Render { place: Place },1455}14561457/// Combined Place/Spread/Hole for Apply args.1458#[derive(Debug, Clone)]1459pub enum PlaceOrSpreadOrHole {1460 Place(Place),1461 Spread(SpreadPattern),1462 Hole,1463}14641465/// Aliasing signature for function calls.1466/// Ported from TS `AliasingSignature` in `AliasingEffects.ts`.1467#[derive(Debug, Clone)]1468pub struct AliasingSignature {1469 pub receiver: IdentifierId,1470 pub params: Vec<IdentifierId>,1471 pub rest: Option<IdentifierId>,1472 pub returns: IdentifierId,1473 pub effects: Vec<AliasingEffect>,1474 pub temporaries: Vec<Place>,1475}14761477// =============================================================================1478// Type helper functions (ported from HIR.ts)1479// =============================================================================14801481use crate::object_shape::BUILT_IN_ARRAY_ID;1482use crate::object_shape::BUILT_IN_JSX_ID;1483use crate::object_shape::BUILT_IN_MAP_ID;1484use crate::object_shape::BUILT_IN_PROPS_ID;1485use crate::object_shape::BUILT_IN_REF_VALUE_ID;1486use crate::object_shape::BUILT_IN_SET_ID;1487use crate::object_shape::BUILT_IN_USE_OPERATOR_ID;1488use crate::object_shape::BUILT_IN_USE_REF_ID;14891490/// Returns true if the type (looked up via identifier) is primitive.1491pub fn is_primitive_type(ty: &Type) -> bool {1492 matches!(ty, Type::Primitive)1493}14941495/// Returns true if the type is the props object.1496pub fn is_props_type(ty: &Type) -> bool {1497 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_PROPS_ID)1498}14991500/// Returns true if the type is an array.1501pub fn is_array_type(ty: &Type) -> bool {1502 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_ARRAY_ID)1503}15041505/// Returns true if the type is a Set.1506pub fn is_set_type(ty: &Type) -> bool {1507 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_SET_ID)1508}15091510/// Returns true if the type is a Map.1511pub fn is_map_type(ty: &Type) -> bool {1512 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_MAP_ID)1513}15141515/// Returns true if the type is JSX.1516pub fn is_jsx_type(ty: &Type) -> bool {1517 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_JSX_ID)1518}15191520/// Returns true if the identifier type is a ref value.1521pub fn is_ref_value_type(ty: &Type) -> bool {1522 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_REF_VALUE_ID)1523}15241525/// Returns true if the identifier type is useRef.1526pub fn is_use_ref_type(ty: &Type) -> bool {1527 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_USE_REF_ID)1528}15291530/// Returns true if the type is a ref or ref value.1531pub fn is_ref_or_ref_value(ty: &Type) -> bool {1532 is_use_ref_type(ty) || is_ref_value_type(ty)1533}15341535/// Returns true if the type is a useState result (BuiltInUseState).1536pub fn is_use_state_type(ty: &Type) -> bool {1537 matches!(ty, Type::Object { shape_id: Some(id) } if id == object_shape::BUILT_IN_USE_STATE_ID)1538}15391540/// Returns true if the type is a setState function (BuiltInSetState).1541pub fn is_set_state_type(ty: &Type) -> bool {1542 matches!(ty, Type::Function { shape_id: Some(id), .. } if id == object_shape::BUILT_IN_SET_STATE_ID)1543}15441545/// Returns true if the type is a useEffect hook.1546pub fn is_use_effect_hook_type(ty: &Type) -> bool {1547 matches!(ty, Type::Function { shape_id: Some(id), .. } if id == object_shape::BUILT_IN_USE_EFFECT_HOOK_ID)1548}15491550/// Returns true if the type is a useLayoutEffect hook.1551pub fn is_use_layout_effect_hook_type(ty: &Type) -> bool {1552 matches!(ty, Type::Function { shape_id: Some(id), .. } if id == object_shape::BUILT_IN_USE_LAYOUT_EFFECT_HOOK_ID)1553}15541555/// Returns true if the type is a useInsertionEffect hook.1556pub fn is_use_insertion_effect_hook_type(ty: &Type) -> bool {1557 matches!(ty, Type::Function { shape_id: Some(id), .. } if id == object_shape::BUILT_IN_USE_INSERTION_EFFECT_HOOK_ID)1558}15591560/// Returns true if the type is a useEffectEvent function.1561pub fn is_use_effect_event_type(ty: &Type) -> bool {1562 matches!(ty, Type::Function { shape_id: Some(id), .. } if id == object_shape::BUILT_IN_USE_EFFECT_EVENT_ID)1563}15641565/// Returns true if the type is a ref or ref-like mutable type (e.g. Reanimated shared values).1566pub fn is_ref_or_ref_like_mutable_type(ty: &Type) -> bool {1567 matches!(ty, Type::Object { shape_id: Some(id) }1568 if id == object_shape::BUILT_IN_USE_REF_ID || id == object_shape::REANIMATED_SHARED_VALUE_ID)1569}15701571/// Returns true if the type is the `use()` operator (React.use).1572pub fn is_use_operator_type(ty: &Type) -> bool {1573 matches!(1574 ty,1575 Type::Function { shape_id: Some(id), .. }1576 if id == BUILT_IN_USE_OPERATOR_ID1577 )1578}15791580/// Returns true if the type is a plain object (BuiltInObject).1581pub fn is_plain_object_type(ty: &Type) -> bool {1582 matches!(ty, Type::Object { shape_id: Some(id) } if id == object_shape::BUILT_IN_OBJECT_ID)1583}15841585/// Returns true if the type is a startTransition function (BuiltInStartTransition).1586pub fn is_start_transition_type(ty: &Type) -> bool {1587 matches!(ty, Type::Function { shape_id: Some(id), .. } if id == object_shape::BUILT_IN_START_TRANSITION_ID)1588}15891590#[cfg(test)]1591mod tests {1592 use super::*;15931594 #[test]1595 fn test_format_js_number() {1596 // Scientific notation for large numbers (>= 1e21)1597 assert_eq!(format_js_number(1e21), "1e+21");1598 assert_eq!(format_js_number(1.5e21), "1.5e+21");1599 assert_eq!(1600 format_js_number(2.18739127891275e22),1601 "2.18739127891275e+22"1602 );1603 assert_eq!(format_js_number(1e100), "1e+100");1604 assert_eq!(format_js_number(-1e21), "-1e+21");1605 assert_eq!(format_js_number(-1e100), "-1e+100");16061607 // Scientific notation for small numbers (< 1e-6)1608 assert_eq!(format_js_number(1e-7), "1e-7");1609 assert_eq!(format_js_number(5e-7), "5e-7");1610 assert_eq!(format_js_number(1.5e-8), "1.5e-8");1611 assert_eq!(format_js_number(-1.5e-8), "-1.5e-8");16121613 // Non-scientific large numbers (< 1e21)1614 assert_eq!(format_js_number(1e20), "100000000000000000000");1615 assert_eq!(format_js_number(1e-6), "0.000001");16161617 // Integers1618 assert_eq!(format_js_number(0.0), "0");1619 assert_eq!(format_js_number(-0.0), "0");1620 assert_eq!(format_js_number(1.0), "1");1621 assert_eq!(format_js_number(100.0), "100");16221623 // Regular floats1624 assert_eq!(format_js_number(1.5), "1.5");1625 assert_eq!(format_js_number(0.5), "0.5");1626 assert_eq!(format_js_number(0.1), "0.1");16271628 // Special values1629 assert_eq!(format_js_number(f64::NAN), "NaN");1630 assert_eq!(format_js_number(f64::INFINITY), "Infinity");1631 assert_eq!(format_js_number(f64::NEG_INFINITY), "-Infinity");1632 }1633}