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;
11
12use react_compiler_utils::FxIndexMap;
13use react_compiler_utils::FxIndexSet;
14pub use react_compiler_diagnostics::CompilerDiagnostic;
15pub use react_compiler_diagnostics::ErrorCategory;
16pub use react_compiler_diagnostics::GENERATED_SOURCE;
17pub use react_compiler_diagnostics::Position;
18pub use react_compiler_diagnostics::SourceLocation;
19pub use reactive::*;
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
26pub struct BlockId(pub u32);
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
29pub struct IdentifierId(pub u32);
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
33pub struct InstructionId(pub u32);
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
38pub struct EvaluationOrder(pub u32);
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
41pub struct DeclarationId(pub u32);
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
44pub struct ScopeId(pub u32);
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
47pub struct TypeId(pub u32);
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
50pub struct FunctionId(pub u32);
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
53pub struct MutableRangeId(pub u32);
54
55#[derive(Debug, Clone, Copy)]
62pub struct FloatValue(u64);
63
64impl FloatValue {
65 pub fn new(value: f64) -> Self {
66 FloatValue(value.to_bits())
67 }
68
69 pub fn value(self) -> f64 {
70 f64::from_bits(self.0)
71 }
72}
73
74impl From<f64> for FloatValue {
75 fn from(value: f64) -> Self {
76 FloatValue::new(value)
77 }
78}
79
80impl From<FloatValue> for f64 {
81 fn from(value: FloatValue) -> Self {
82 value.value()
83 }
84}
85
86impl PartialEq for FloatValue {
87 fn eq(&self, other: &Self) -> bool {
88 self.0 == other.0
89 }
90}
91
92impl Eq for FloatValue {}
93
94impl std::hash::Hash for FloatValue {
95 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
96 self.0.hash(state);
97 }
98}
99
100impl 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}
105
106pub 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 }
127
128 let abs = n.abs();
129 let sign = if n < 0.0 { "-" } else { "" };
130
131 if abs >= 1e21 || (abs > 0.0 && abs < 1e-6) {
132 let formatted = format!("{:e}", abs);
135 let (coeff, exp_str) = formatted.split_once('e').unwrap();
137 let exp: i32 = exp_str.parse().unwrap();
138 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 format!("{}{}", sign, abs as i64)
147 } else {
148 format!("{}", n)
150 }
151}
152
153#[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}
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq)]
177pub enum ReactFunctionType {
178 Component,
179 Hook,
180 Other,
181}
182
183#[derive(Debug, Clone)]
184pub enum ParamPattern {
185 Place(Place),
186 Spread(SpreadPattern),
187}
188
189#[derive(Debug, Clone)]
191pub struct HIR {
192 pub entry: BlockId,
193 pub blocks: FxIndexMap<BlockId, BasicBlock>,
194}
195
196#[derive(Debug, Clone, Copy, PartialEq, Eq)]
198pub enum BlockKind {
199 Block,
200 Value,
201 Loop,
202 Sequence,
203 Catch,
204}
205
206impl 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}
217
218#[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: FxIndexSet<BlockId>,
226 pub phis: Vec<Phi>,
227}
228
229#[derive(Debug, Clone)]
231pub struct Phi {
232 pub place: Place,
233 pub operands: FxIndexMap<BlockId, Place>,
234}
235
236#[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}
391
392impl Terminal {
393 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 }
420
421 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 }
448
449 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}
477
478#[derive(Debug, Clone, Copy, PartialEq, Eq)]
479pub enum ReturnVariant {
480 Void,
481 Implicit,
482 Explicit,
483}
484
485#[derive(Debug, Clone, Copy, PartialEq, Eq)]
486pub enum GotoVariant {
487 Break,
488 Continue,
489 Try,
490}
491
492#[derive(Debug, Clone)]
493pub struct Case {
494 pub test: Option<Place>,
495 pub block: BlockId,
496}
497
498#[derive(Debug, Clone, Copy, PartialEq, Eq)]
499pub enum LogicalOperator {
500 And,
501 Or,
502 NullishCoalescing,
503}
504
505impl 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}
514
515#[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}
527
528#[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}
539
540#[derive(Debug, Clone)]
541pub struct LValue {
542 pub place: Place,
543 pub kind: InstructionKind,
544}
545
546#[derive(Debug, Clone)]
547pub struct LValuePattern {
548 pub pattern: Pattern,
549 pub kind: InstructionKind,
550}
551
552#[derive(Debug, Clone)]
553pub enum Pattern {
554 Array(ArrayPattern),
555 Object(ObjectPattern),
556}
557
558#[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 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 original_node: Option<react_compiler_ast::OriginalNode>,
784 loc: Option<SourceLocation>,
785 },
786}
787
788impl 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}
837
838#[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}
850
851#[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}
876
877impl 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}
905
906#[derive(Debug, Clone, Copy, PartialEq, Eq)]
907pub enum UnaryOperator {
908 Minus,
909 Plus,
910 Not,
911 BitwiseNot,
912 TypeOf,
913 Void,
914}
915
916impl 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}
928
929#[derive(Debug, Clone, Copy, PartialEq, Eq)]
930pub enum UpdateOperator {
931 Increment,
932 Decrement,
933}
934
935impl 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}
943
944#[derive(Debug, Clone, Copy, PartialEq, Eq)]
945pub enum FunctionExpressionType {
946 ArrowFunctionExpression,
947 FunctionExpression,
948 FunctionDeclaration,
949}
950
951#[derive(Debug, Clone)]
952pub struct TemplateQuasi {
953 pub raw: String,
954 pub cooked: Option<String>,
955}
956
957#[derive(Debug, Clone)]
958pub struct ManualMemoDependency {
959 pub root: ManualMemoDependencyRoot,
960 pub path: Vec<DependencyPathEntry>,
961 pub loc: Option<SourceLocation>,
962}
963
964#[derive(Debug, Clone)]
965pub enum ManualMemoDependencyRoot {
966 NamedLocal { value: Place, constant: bool },
967 Global { identifier_name: String },
968}
969
970#[derive(Debug, Clone, PartialEq, Eq)]
971pub struct DependencyPathEntry {
972 pub property: PropertyLiteral,
973 pub optional: bool,
974 pub loc: Option<SourceLocation>,
975}
976
977#[derive(Debug, Clone)]
982pub struct Place {
983 pub identifier: IdentifierId,
984 pub effect: Effect,
985 pub reactive: bool,
986 pub loc: Option<SourceLocation>,
987}
988
989#[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}
999
1000#[derive(Debug, Clone)]
1001pub struct MutableRange {
1002 pub id: MutableRangeId,
1006 pub start: EvaluationOrder,
1007 pub end: EvaluationOrder,
1008}
1009
1010impl MutableRange {
1011 pub fn contains(&self, eval_order: EvaluationOrder) -> bool {
1014 eval_order >= self.start && eval_order < self.end
1015 }
1016
1017 pub fn same_range(&self, other: &MutableRange) -> bool {
1021 self.id == other.id
1022 }
1023}
1024
1025#[derive(Debug, Clone)]
1026pub enum IdentifierName {
1027 Named(String),
1028 Promoted(String),
1029}
1030
1031impl IdentifierName {
1032 pub fn value(&self) -> &str {
1033 match self {
1034 IdentifierName::Named(v) | IdentifierName::Promoted(v) => v,
1035 }
1036 }
1037}
1038
1039#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
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}
1058
1059impl Effect {
1060 pub fn is_mutable(&self) -> bool {
1064 matches!(
1065 self,
1066 Effect::Capture
1067 | Effect::Store
1068 | Effect::ConditionallyMutate
1069 | Effect::ConditionallyMutateIterator
1070 | Effect::Mutate
1071 )
1072 }
1073}
1074
1075impl 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}
1089
1090#[derive(Debug, Clone)]
1091pub struct SpreadPattern {
1092 pub place: Place,
1093}
1094
1095#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1096pub enum Hole {
1097 Hole,
1098}
1099
1100#[derive(Debug, Clone)]
1101pub struct ArrayPattern {
1102 pub items: Vec<ArrayPatternElement>,
1103 pub loc: Option<SourceLocation>,
1104}
1105
1106#[derive(Debug, Clone)]
1107pub enum ArrayPatternElement {
1108 Place(Place),
1109 Spread(SpreadPattern),
1110 Hole,
1111}
1112
1113#[derive(Debug, Clone)]
1114pub struct ObjectPattern {
1115 pub properties: Vec<ObjectPropertyOrSpread>,
1116 pub loc: Option<SourceLocation>,
1117}
1118
1119#[derive(Debug, Clone)]
1120pub enum ObjectPropertyOrSpread {
1121 Property(ObjectProperty),
1122 Spread(SpreadPattern),
1123}
1124
1125#[derive(Debug, Clone)]
1126pub struct ObjectProperty {
1127 pub key: ObjectPropertyKey,
1128 pub property_type: ObjectPropertyType,
1129 pub place: Place,
1130}
1131
1132#[derive(Debug, Clone)]
1133pub enum ObjectPropertyKey {
1134 String { name: String },
1135 Identifier { name: String },
1136 Computed { name: Place },
1137 Number { name: FloatValue },
1138}
1139
1140#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1141pub enum ObjectPropertyType {
1142 Property,
1143 Method,
1144}
1145
1146impl 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}
1154
1155#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1156pub enum PropertyLiteral {
1157 String(String),
1158 Number(FloatValue),
1159}
1160
1161impl 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}
1169
1170#[derive(Debug, Clone)]
1171pub enum PlaceOrSpread {
1172 Place(Place),
1173 Spread(SpreadPattern),
1174}
1175
1176#[derive(Debug, Clone)]
1177pub enum ArrayElement {
1178 Place(Place),
1179 Spread(SpreadPattern),
1180 Hole,
1181}
1182
1183#[derive(Debug, Clone)]
1184pub struct LoweredFunction {
1185 pub func: FunctionId,
1186}
1187
1188#[derive(Debug, Clone)]
1189pub struct BuiltinTag {
1190 pub name: String,
1191 pub loc: Option<SourceLocation>,
1192}
1193
1194#[derive(Debug, Clone)]
1195pub enum JsxTag {
1196 Place(Place),
1197 Builtin(BuiltinTag),
1198}
1199
1200#[derive(Debug, Clone)]
1201pub enum JsxAttribute {
1202 SpreadAttribute { argument: Place },
1203 Attribute { name: String, place: Place },
1204}
1205
1206#[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}
1221
1222#[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}
1248
1249#[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}
1271
1272impl NonLocalBinding {
1273 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}
1284
1285#[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}
1314
1315#[derive(Debug, Clone)]
1316pub enum PropertyNameKind {
1317 Literal { value: PropertyLiteral },
1318 Computed { value: Box<Type> },
1319}
1320
1321#[derive(Debug, Clone)]
1326pub struct ReactiveScope {
1327 pub id: ScopeId,
1328 pub range: MutableRange,
1329
1330 pub dependencies: Vec<ReactiveScopeDependency>,
1332
1333 pub declarations: Vec<(IdentifierId, ReactiveScopeDeclaration)>,
1335
1336 pub reassignments: Vec<IdentifierId>,
1338
1339 pub early_return_value: Option<ReactiveScopeEarlyReturn>,
1341
1342 pub merged: Vec<ScopeId>,
1344
1345 pub loc: Option<SourceLocation>,
1347}
1348
1349#[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}
1357
1358#[derive(Debug, Clone)]
1360pub struct ReactiveScopeDeclaration {
1361 pub identifier: IdentifierId,
1362 pub scope: ScopeId,
1363}
1364
1365#[derive(Debug, Clone)]
1367pub struct ReactiveScopeEarlyReturn {
1368 pub value: IdentifierId,
1369 pub loc: Option<SourceLocation>,
1370 pub label: BlockId,
1371}
1372
1373use crate::object_shape::FunctionSignature;
1378use crate::type_config::ValueKind;
1379use crate::type_config::ValueReason;
1380
1381#[derive(Debug, Clone, PartialEq, Eq)]
1383pub enum MutationReason {
1384 AssignCurrentProperty,
1385}
1386
1387#[derive(Debug, Clone)]
1390pub enum AliasingEffect {
1391 Freeze { value: Place, reason: ValueReason },
1393 Mutate {
1395 value: Place,
1396 reason: Option<MutationReason>,
1397 },
1398 MutateConditionally { value: Place },
1400 MutateTransitive { value: Place },
1402 MutateTransitiveConditionally { value: Place },
1404 Capture { from: Place, into: Place },
1406 Alias { from: Place, into: Place },
1408 MaybeAlias { from: Place, into: Place },
1410 Assign { from: Place, into: Place },
1412 Create {
1414 into: Place,
1415 value: ValueKind,
1416 reason: ValueReason,
1417 },
1418 CreateFrom { from: Place, into: Place },
1420 ImmutableCapture { from: Place, into: Place },
1422 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 CreateFunction {
1434 captures: Vec<Place>,
1435 function_id: FunctionId,
1436 into: Place,
1437 },
1438 MutateFrozen {
1440 place: Place,
1441 error: CompilerDiagnostic,
1442 },
1443 MutateGlobal {
1445 place: Place,
1446 error: CompilerDiagnostic,
1447 },
1448 Impure {
1450 place: Place,
1451 error: CompilerDiagnostic,
1452 },
1453 Render { place: Place },
1455}
1456
1457#[derive(Debug, Clone)]
1459pub enum PlaceOrSpreadOrHole {
1460 Place(Place),
1461 Spread(SpreadPattern),
1462 Hole,
1463}
1464
1465#[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}
1476
1477use 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;
1489
1490pub fn is_primitive_type(ty: &Type) -> bool {
1492 matches!(ty, Type::Primitive)
1493}
1494
1495pub fn is_props_type(ty: &Type) -> bool {
1497 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_PROPS_ID)
1498}
1499
1500pub fn is_array_type(ty: &Type) -> bool {
1502 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_ARRAY_ID)
1503}
1504
1505pub fn is_set_type(ty: &Type) -> bool {
1507 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_SET_ID)
1508}
1509
1510pub fn is_map_type(ty: &Type) -> bool {
1512 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_MAP_ID)
1513}
1514
1515pub fn is_jsx_type(ty: &Type) -> bool {
1517 matches!(ty, Type::Object { shape_id: Some(id) } if id == BUILT_IN_JSX_ID)
1518}
1519
1520pub 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}
1524
1525pub 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}
1529
1530pub fn is_ref_or_ref_value(ty: &Type) -> bool {
1532 is_use_ref_type(ty) || is_ref_value_type(ty)
1533}
1534
1535pub 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}
1539
1540pub 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}
1544
1545pub 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}
1549
1550pub 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}
1554
1555pub 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}
1559
1560pub 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}
1564
1565pub 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}
1570
1571pub 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_ID
1577 )
1578}
1579
1580pub 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}
1584
1585pub 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}
1589
1590#[cfg(test)]
1591mod tests {
1592 use super::*;
1593
1594 #[test]
1595 fn test_format_js_number() {
1596 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");
1606
1607 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");
1612
1613 assert_eq!(format_js_number(1e20), "100000000000000000000");
1615 assert_eq!(format_js_number(1e-6), "0.000001");
1616
1617 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");
1622
1623 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");
1627
1628 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}