compiler/crates/react_compiler_hir/src/globals.rs RUST 2,382 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 2,382.
1// Copyright (c) Meta Platforms, Inc. and affiliates.2//3// This source code is licensed under the MIT license found in the4// LICENSE file in the root directory of this source tree.56//! Global type registry and built-in shape definitions, ported from Globals.ts.7//!8//! Provides `DEFAULT_SHAPES` (built-in object shapes) and `DEFAULT_GLOBALS`9//! (global variable types including React hooks and JS built-ins).1011use rustc_hash::FxHashMap;12use std::sync::LazyLock;1314use crate::Effect;15use crate::Type;16use crate::object_shape::*;17use crate::type_config::AliasingEffectConfig;18use crate::type_config::AliasingSignatureConfig;19use crate::type_config::ApplyArgConfig;20use crate::type_config::ApplyArgHoleKind;21use crate::type_config::BuiltInTypeRef;22use crate::type_config::TypeConfig;23use crate::type_config::TypeReferenceConfig;24use crate::type_config::ValueKind;25use crate::type_config::ValueReason;2627/// Type alias matching TS `Global = BuiltInType | PolyType`.28/// In the Rust port, both map to our `Type` enum.29pub type Global = Type;3031/// Registry mapping global names to their types.32///33/// Supports two modes:34/// - **Builder mode** (`base=None`): wraps a single FxHashMap, used during35///   `build_default_globals` to construct the static base.36/// - **Overlay mode** (`base=Some`): holds a `&'static FxHashMap` base plus a small37///   extras FxHashMap. Lookups check extras first, then base. Inserts go into extras.38///   Cloning only copies the extras map (the base pointer is shared).39pub struct GlobalRegistry {40    base: Option<&'static FxHashMap<String, Global>>,41    entries: FxHashMap<String, Global>,42}4344impl GlobalRegistry {45    /// Create an empty builder-mode registry.46    pub fn new() -> Self {47        Self {48            base: None,49            entries: FxHashMap::default(),50        }51    }5253    /// Create an overlay-mode registry backed by a static base.54    pub fn with_base(base: &'static FxHashMap<String, Global>) -> Self {55        Self {56            base: Some(base),57            entries: FxHashMap::default(),58        }59    }6061    pub fn get(&self, key: &str) -> Option<&Global> {62        self.entries63            .get(key)64            .or_else(|| self.base.and_then(|b| b.get(key)))65    }6667    pub fn insert(&mut self, key: String, value: Global) {68        self.entries.insert(key, value);69    }7071    pub fn contains_key(&self, key: &str) -> bool {72        self.entries.contains_key(key) || self.base.map_or(false, |b| b.contains_key(key))73    }7475    /// Iterate over all keys in the registry (base + extras).76    /// Keys in extras that shadow base keys appear only once.77    pub fn keys(&self) -> impl Iterator<Item = &String> {78        let base_keys = self79            .base80            .into_iter()81            .flat_map(|b| b.keys())82            .filter(|k| !self.entries.contains_key(k.as_str()));83        self.entries.keys().chain(base_keys)84    }8586    /// Consume the registry and return the inner FxHashMap.87    /// Only valid in builder mode (no base).88    pub fn into_inner(self) -> FxHashMap<String, Global> {89        debug_assert!(90            self.base.is_none(),91            "into_inner() called on overlay-mode GlobalRegistry"92        );93        self.entries94    }95}9697impl Clone for GlobalRegistry {98    fn clone(&self) -> Self {99        Self {100            base: self.base,101            entries: self.entries.clone(),102        }103    }104}105106// =============================================================================107// Static base registries (initialized once, shared across all Environments)108// =============================================================================109110struct BaseRegistries {111    shapes: FxHashMap<String, ObjectShape>,112    globals: FxHashMap<String, Global>,113}114115static BASE: LazyLock<BaseRegistries> = LazyLock::new(|| {116    let mut shapes = build_builtin_shapes();117    let globals = build_default_globals(&mut shapes);118    BaseRegistries {119        shapes: shapes.into_inner(),120        globals: globals.into_inner(),121    }122});123124/// Get a reference to the static base shapes registry.125pub fn base_shapes() -> &'static FxHashMap<String, ObjectShape> {126    &BASE.shapes127}128129/// Get a reference to the static base globals registry.130pub fn base_globals() -> &'static FxHashMap<String, Global> {131    &BASE.globals132}133134// =============================================================================135// installTypeConfig — converts TypeConfig to internal Type136// =============================================================================137138/// Convert a user-provided TypeConfig into an internal Type, registering shapes139/// as needed. Ported from TS `installTypeConfig` in Globals.ts.140/// If `errors` is provided, hook-name vs hook-type consistency validation141/// errors are collected there.142pub fn install_type_config(143    _globals: &mut GlobalRegistry,144    shapes: &mut ShapeRegistry,145    type_config: &TypeConfig,146    module_name: &str,147    _loc: (),148) -> Global {149    install_type_config_inner(_globals, shapes, type_config, module_name, _loc, &mut None)150}151152/// Like `install_type_config` but collects validation errors.153pub fn install_type_config_with_errors(154    _globals: &mut GlobalRegistry,155    shapes: &mut ShapeRegistry,156    type_config: &TypeConfig,157    module_name: &str,158    _loc: (),159    errors: &mut Vec<String>,160) -> Global {161    install_type_config_inner(162        _globals,163        shapes,164        type_config,165        module_name,166        _loc,167        &mut Some(errors),168    )169}170171fn install_type_config_inner(172    _globals: &mut GlobalRegistry,173    shapes: &mut ShapeRegistry,174    type_config: &TypeConfig,175    module_name: &str,176    _loc: (),177    errors: &mut Option<&mut Vec<String>>,178) -> Global {179    match type_config {180        TypeConfig::TypeReference(TypeReferenceConfig { name }) => match name {181            BuiltInTypeRef::Array => Type::Object {182                shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),183            },184            BuiltInTypeRef::MixedReadonly => Type::Object {185                shape_id: Some(BUILT_IN_MIXED_READONLY_ID.to_string()),186            },187            BuiltInTypeRef::Primitive => Type::Primitive,188            BuiltInTypeRef::Ref => Type::Object {189                shape_id: Some(BUILT_IN_USE_REF_ID.to_string()),190            },191            BuiltInTypeRef::Any => Type::Poly,192        },193        TypeConfig::Function(func_config) => {194            // Compute return type first to avoid double-borrow of shapes195            let return_type = install_type_config_inner(196                _globals,197                shapes,198                &func_config.return_type,199                module_name,200                (),201                errors,202            );203            add_function(204                shapes,205                Vec::new(),206                FunctionSignatureBuilder {207                    positional_params: func_config.positional_params.clone(),208                    rest_param: func_config.rest_param,209                    callee_effect: func_config.callee_effect,210                    return_type,211                    return_value_kind: func_config.return_value_kind,212                    no_alias: func_config.no_alias.unwrap_or(false),213                    mutable_only_if_operands_are_mutable: func_config214                        .mutable_only_if_operands_are_mutable215                        .unwrap_or(false),216                    impure: func_config.impure.unwrap_or(false),217                    canonical_name: func_config.canonical_name.clone(),218                    aliasing: func_config.aliasing.clone(),219                    known_incompatible: func_config.known_incompatible.clone(),220                    ..Default::default()221                },222                None,223                false,224            )225        }226        TypeConfig::Hook(hook_config) => {227            // Compute return type first to avoid double-borrow of shapes228            let return_type = install_type_config_inner(229                _globals,230                shapes,231                &hook_config.return_type,232                module_name,233                (),234                errors,235            );236            add_hook(237                shapes,238                HookSignatureBuilder {239                    hook_kind: HookKind::Custom,240                    positional_params: hook_config.positional_params.clone().unwrap_or_default(),241                    rest_param: hook_config.rest_param.or(Some(Effect::Freeze)),242                    callee_effect: Effect::Read,243                    return_type,244                    return_value_kind: hook_config.return_value_kind.unwrap_or(ValueKind::Frozen),245                    no_alias: hook_config.no_alias.unwrap_or(false),246                    aliasing: hook_config.aliasing.clone(),247                    known_incompatible: hook_config.known_incompatible.clone(),248                    ..Default::default()249                },250                None,251            )252        }253        TypeConfig::Object(obj_config) => {254            let properties: Vec<(String, Type)> = obj_config255                .properties256                .as_ref()257                .map(|props| {258                    props259                        .iter()260                        .map(|(key, value)| {261                            let ty = install_type_config_inner(262                                _globals,263                                shapes,264                                value,265                                module_name,266                                (),267                                errors,268                            );269                            // Validate hook-name vs hook-type consistency (matching TS installTypeConfig)270                            if let Some(errs) = errors {271                                let expect_hook = crate::environment::is_hook_name(key);272                                let is_hook = match &ty {273                                    Type::Function { shape_id: Some(id), .. } => {274                                        shapes.get(id)275                                            .and_then(|shape| shape.function_type.as_ref())276                                            .and_then(|ft| ft.hook_kind.as_ref())277                                            .is_some()278                                    }279                                    _ => false,280                                };281                                if expect_hook != is_hook {282                                    errs.push(format!(283                                        "Expected type for object property '{}' from module '{}' {} based on the property name",284                                        key,285                                        module_name,286                                        if expect_hook { "to be a hook" } else { "not to be a hook" }287                                    ));288                                }289                            }290                            (key.clone(), ty)291                        })292                        .collect()293                })294                .unwrap_or_default();295            add_object(shapes, None, properties)296        }297    }298}299300// =============================================================================301// Build built-in shapes (BUILTIN_SHAPES from ObjectShape.ts)302// =============================================================================303304/// Build the built-in shapes registry. This corresponds to TS `BUILTIN_SHAPES`305/// defined at module level in ObjectShape.ts.306pub fn build_builtin_shapes() -> ShapeRegistry {307    let mut shapes = ShapeRegistry::new();308309    // BuiltInProps: { ref: UseRefType }310    add_object(311        &mut shapes,312        Some(BUILT_IN_PROPS_ID),313        vec![(314            "ref".to_string(),315            Type::Object {316                shape_id: Some(BUILT_IN_USE_REF_ID.to_string()),317            },318        )],319    );320321    build_array_shape(&mut shapes);322    build_set_shape(&mut shapes);323    build_map_shape(&mut shapes);324    build_weak_set_shape(&mut shapes);325    build_weak_map_shape(&mut shapes);326    build_object_shape(&mut shapes);327    build_ref_shapes(&mut shapes);328    build_state_shapes(&mut shapes);329    build_hook_shapes(&mut shapes);330    build_misc_shapes(&mut shapes);331332    shapes333}334335fn simple_function(336    shapes: &mut ShapeRegistry,337    positional_params: Vec<Effect>,338    rest_param: Option<Effect>,339    return_type: Type,340    return_value_kind: ValueKind,341) -> Type {342    add_function(343        shapes,344        Vec::new(),345        FunctionSignatureBuilder {346            positional_params,347            rest_param,348            return_type,349            return_value_kind,350            ..Default::default()351        },352        None,353        false,354    )355}356357/// Shorthand for a pure function returning Primitive.358fn pure_primitive_fn(shapes: &mut ShapeRegistry) -> Type {359    simple_function(360        shapes,361        Vec::new(),362        Some(Effect::Read),363        Type::Primitive,364        ValueKind::Primitive,365    )366}367368fn build_array_shape(shapes: &mut ShapeRegistry) {369    let index_of = pure_primitive_fn(shapes);370    let includes = pure_primitive_fn(shapes);371    let pop = add_function(372        shapes,373        Vec::new(),374        FunctionSignatureBuilder {375            callee_effect: Effect::Store,376            return_type: Type::Poly,377            return_value_kind: ValueKind::Mutable,378            ..Default::default()379        },380        None,381        false,382    );383    let at = add_function(384        shapes,385        Vec::new(),386        FunctionSignatureBuilder {387            positional_params: vec![Effect::Read],388            callee_effect: Effect::Capture,389            return_type: Type::Poly,390            return_value_kind: ValueKind::Mutable,391            ..Default::default()392        },393        None,394        false,395    );396    let concat = add_function(397        shapes,398        Vec::new(),399        FunctionSignatureBuilder {400            rest_param: Some(Effect::Capture),401            return_type: Type::Object {402                shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),403            },404            return_value_kind: ValueKind::Mutable,405            callee_effect: Effect::Capture,406            ..Default::default()407        },408        None,409        false,410    );411    let join = pure_primitive_fn(shapes);412    let slice = add_function(413        shapes,414        Vec::new(),415        FunctionSignatureBuilder {416            rest_param: Some(Effect::Read),417            callee_effect: Effect::Capture,418            return_type: Type::Object {419                shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),420            },421            return_value_kind: ValueKind::Mutable,422            ..Default::default()423        },424        None,425        false,426    );427    let map = add_function(428        shapes,429        Vec::new(),430        FunctionSignatureBuilder {431            rest_param: Some(Effect::ConditionallyMutate),432            callee_effect: Effect::ConditionallyMutate,433            return_type: Type::Object {434                shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),435            },436            return_value_kind: ValueKind::Mutable,437            no_alias: true,438            mutable_only_if_operands_are_mutable: true,439            aliasing: Some(AliasingSignatureConfig {440                receiver: "@receiver".to_string(),441                params: vec!["@callback".to_string()],442                rest: None,443                returns: "@returns".to_string(),444                temporaries: vec![445                    "@item".to_string(),446                    "@callbackReturn".to_string(),447                    "@thisArg".to_string(),448                ],449                effects: vec![450                    // Map creates a new mutable array451                    AliasingEffectConfig::Create {452                        into: "@returns".to_string(),453                        value: ValueKind::Mutable,454                        reason: ValueReason::KnownReturnSignature,455                    },456                    // The first arg to the callback is an item extracted from the receiver array457                    AliasingEffectConfig::CreateFrom {458                        from: "@receiver".to_string(),459                        into: "@item".to_string(),460                    },461                    // The undefined this for the callback462                    AliasingEffectConfig::Create {463                        into: "@thisArg".to_string(),464                        value: ValueKind::Primitive,465                        reason: ValueReason::KnownReturnSignature,466                    },467                    // Calls the callback, returning the result into a temporary468                    AliasingEffectConfig::Apply {469                        receiver: "@thisArg".to_string(),470                        function: "@callback".to_string(),471                        mutates_function: false,472                        args: vec![473                            ApplyArgConfig::Place("@item".to_string()),474                            ApplyArgConfig::Hole {475                                kind: ApplyArgHoleKind::Hole,476                            },477                            ApplyArgConfig::Place("@receiver".to_string()),478                        ],479                        into: "@callbackReturn".to_string(),480                    },481                    // Captures the result of the callback into the return array482                    AliasingEffectConfig::Capture {483                        from: "@callbackReturn".to_string(),484                        into: "@returns".to_string(),485                    },486                ],487            }),488            ..Default::default()489        },490        None,491        false,492    );493    let filter = add_function(494        shapes,495        Vec::new(),496        FunctionSignatureBuilder {497            rest_param: Some(Effect::ConditionallyMutate),498            callee_effect: Effect::ConditionallyMutate,499            return_type: Type::Object {500                shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),501            },502            return_value_kind: ValueKind::Mutable,503            no_alias: true,504            mutable_only_if_operands_are_mutable: true,505            ..Default::default()506        },507        None,508        false,509    );510    let find = add_function(511        shapes,512        Vec::new(),513        FunctionSignatureBuilder {514            rest_param: Some(Effect::ConditionallyMutate),515            callee_effect: Effect::ConditionallyMutate,516            return_type: Type::Poly,517            return_value_kind: ValueKind::Mutable,518            no_alias: true,519            mutable_only_if_operands_are_mutable: true,520            ..Default::default()521        },522        None,523        false,524    );525    let find_index = add_function(526        shapes,527        Vec::new(),528        FunctionSignatureBuilder {529            rest_param: Some(Effect::ConditionallyMutate),530            callee_effect: Effect::ConditionallyMutate,531            return_type: Type::Primitive,532            return_value_kind: ValueKind::Primitive,533            no_alias: true,534            mutable_only_if_operands_are_mutable: true,535            ..Default::default()536        },537        None,538        false,539    );540    let every = add_function(541        shapes,542        Vec::new(),543        FunctionSignatureBuilder {544            rest_param: Some(Effect::ConditionallyMutate),545            callee_effect: Effect::ConditionallyMutate,546            return_type: Type::Primitive,547            return_value_kind: ValueKind::Primitive,548            no_alias: true,549            mutable_only_if_operands_are_mutable: true,550            ..Default::default()551        },552        None,553        false,554    );555    let some = add_function(556        shapes,557        Vec::new(),558        FunctionSignatureBuilder {559            rest_param: Some(Effect::ConditionallyMutate),560            callee_effect: Effect::ConditionallyMutate,561            return_type: Type::Primitive,562            return_value_kind: ValueKind::Primitive,563            no_alias: true,564            mutable_only_if_operands_are_mutable: true,565            ..Default::default()566        },567        None,568        false,569    );570    let flat_map = add_function(571        shapes,572        Vec::new(),573        FunctionSignatureBuilder {574            rest_param: Some(Effect::ConditionallyMutate),575            callee_effect: Effect::ConditionallyMutate,576            return_type: Type::Object {577                shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),578            },579            return_value_kind: ValueKind::Mutable,580            no_alias: true,581            mutable_only_if_operands_are_mutable: true,582            ..Default::default()583        },584        None,585        false,586    );587    let length = Type::Primitive;588    let push = add_function(589        shapes,590        Vec::new(),591        FunctionSignatureBuilder {592            rest_param: Some(Effect::Capture),593            callee_effect: Effect::Store,594            return_type: Type::Primitive,595            return_value_kind: ValueKind::Primitive,596            aliasing: Some(AliasingSignatureConfig {597                receiver: "@receiver".to_string(),598                params: Vec::new(),599                rest: Some("@rest".to_string()),600                returns: "@returns".to_string(),601                temporaries: Vec::new(),602                effects: vec![603                    // Push directly mutates the array itself604                    AliasingEffectConfig::Mutate {605                        value: "@receiver".to_string(),606                    },607                    // The arguments are captured into the array608                    AliasingEffectConfig::Capture {609                        from: "@rest".to_string(),610                        into: "@receiver".to_string(),611                    },612                    // Returns the new length, a primitive613                    AliasingEffectConfig::Create {614                        into: "@returns".to_string(),615                        value: ValueKind::Primitive,616                        reason: ValueReason::KnownReturnSignature,617                    },618                ],619            }),620            ..Default::default()621        },622        None,623        false,624    );625626    add_object(627        shapes,628        Some(BUILT_IN_ARRAY_ID),629        vec![630            ("indexOf".to_string(), index_of),631            ("includes".to_string(), includes),632            ("pop".to_string(), pop),633            ("at".to_string(), at),634            ("concat".to_string(), concat),635            ("length".to_string(), length),636            ("push".to_string(), push),637            ("slice".to_string(), slice),638            ("map".to_string(), map),639            ("flatMap".to_string(), flat_map),640            ("filter".to_string(), filter),641            ("every".to_string(), every),642            ("some".to_string(), some),643            ("find".to_string(), find),644            ("findIndex".to_string(), find_index),645            ("join".to_string(), join),646            // TODO: rest of Array properties647        ],648    );649}650651fn build_set_shape(shapes: &mut ShapeRegistry) {652    let has = add_function(653        shapes,654        Vec::new(),655        FunctionSignatureBuilder {656            positional_params: vec![Effect::Read],657            return_type: Type::Primitive,658            return_value_kind: ValueKind::Primitive,659            ..Default::default()660        },661        None,662        false,663    );664    let add = add_function(665        shapes,666        Vec::new(),667        FunctionSignatureBuilder {668            positional_params: vec![Effect::Capture],669            callee_effect: Effect::Store,670            return_type: Type::Object {671                shape_id: Some(BUILT_IN_SET_ID.to_string()),672            },673            return_value_kind: ValueKind::Mutable,674            aliasing: Some(AliasingSignatureConfig {675                receiver: "@receiver".to_string(),676                params: Vec::new(),677                rest: Some("@rest".to_string()),678                returns: "@returns".to_string(),679                temporaries: Vec::new(),680                effects: vec![681                    // Set.add returns the receiver Set682                    AliasingEffectConfig::Assign {683                        from: "@receiver".to_string(),684                        into: "@returns".to_string(),685                    },686                    // Set.add mutates the set itself687                    AliasingEffectConfig::Mutate {688                        value: "@receiver".to_string(),689                    },690                    // Captures the rest params into the set691                    AliasingEffectConfig::Capture {692                        from: "@rest".to_string(),693                        into: "@receiver".to_string(),694                    },695                ],696            }),697            ..Default::default()698        },699        None,700        false,701    );702    let clear = add_function(703        shapes,704        Vec::new(),705        FunctionSignatureBuilder {706            callee_effect: Effect::Store,707            return_type: Type::Primitive,708            return_value_kind: ValueKind::Primitive,709            ..Default::default()710        },711        None,712        false,713    );714    let delete = add_function(715        shapes,716        Vec::new(),717        FunctionSignatureBuilder {718            positional_params: vec![Effect::Read],719            callee_effect: Effect::Store,720            return_type: Type::Primitive,721            return_value_kind: ValueKind::Primitive,722            ..Default::default()723        },724        None,725        false,726    );727    let size = Type::Primitive;728    let difference = add_function(729        shapes,730        Vec::new(),731        FunctionSignatureBuilder {732            positional_params: vec![Effect::Capture],733            callee_effect: Effect::Capture,734            return_type: Type::Object {735                shape_id: Some(BUILT_IN_SET_ID.to_string()),736            },737            return_value_kind: ValueKind::Mutable,738            ..Default::default()739        },740        None,741        false,742    );743    let union = add_function(744        shapes,745        Vec::new(),746        FunctionSignatureBuilder {747            positional_params: vec![Effect::Capture],748            callee_effect: Effect::Capture,749            return_type: Type::Object {750                shape_id: Some(BUILT_IN_SET_ID.to_string()),751            },752            return_value_kind: ValueKind::Mutable,753            ..Default::default()754        },755        None,756        false,757    );758    let symmetrical_difference = add_function(759        shapes,760        Vec::new(),761        FunctionSignatureBuilder {762            positional_params: vec![Effect::Capture],763            callee_effect: Effect::Capture,764            return_type: Type::Object {765                shape_id: Some(BUILT_IN_SET_ID.to_string()),766            },767            return_value_kind: ValueKind::Mutable,768            ..Default::default()769        },770        None,771        false,772    );773    let is_subset_of = add_function(774        shapes,775        Vec::new(),776        FunctionSignatureBuilder {777            positional_params: vec![Effect::Read],778            callee_effect: Effect::Read,779            return_type: Type::Primitive,780            return_value_kind: ValueKind::Primitive,781            ..Default::default()782        },783        None,784        false,785    );786    let is_superset_of = add_function(787        shapes,788        Vec::new(),789        FunctionSignatureBuilder {790            positional_params: vec![Effect::Read],791            callee_effect: Effect::Read,792            return_type: Type::Primitive,793            return_value_kind: ValueKind::Primitive,794            ..Default::default()795        },796        None,797        false,798    );799    let for_each = add_function(800        shapes,801        Vec::new(),802        FunctionSignatureBuilder {803            rest_param: Some(Effect::ConditionallyMutate),804            callee_effect: Effect::ConditionallyMutate,805            return_type: Type::Primitive,806            return_value_kind: ValueKind::Primitive,807            no_alias: true,808            mutable_only_if_operands_are_mutable: true,809            ..Default::default()810        },811        None,812        false,813    );814    let values = add_function(815        shapes,816        Vec::new(),817        FunctionSignatureBuilder {818            callee_effect: Effect::Capture,819            return_type: Type::Poly,820            return_value_kind: ValueKind::Mutable,821            ..Default::default()822        },823        None,824        false,825    );826    let keys = add_function(827        shapes,828        Vec::new(),829        FunctionSignatureBuilder {830            callee_effect: Effect::Capture,831            return_type: Type::Poly,832            return_value_kind: ValueKind::Mutable,833            ..Default::default()834        },835        None,836        false,837    );838    let entries = add_function(839        shapes,840        Vec::new(),841        FunctionSignatureBuilder {842            callee_effect: Effect::Capture,843            return_type: Type::Poly,844            return_value_kind: ValueKind::Mutable,845            ..Default::default()846        },847        None,848        false,849    );850851    add_object(852        shapes,853        Some(BUILT_IN_SET_ID),854        vec![855            ("add".to_string(), add),856            ("clear".to_string(), clear),857            ("delete".to_string(), delete),858            ("has".to_string(), has),859            ("size".to_string(), size),860            ("difference".to_string(), difference),861            ("union".to_string(), union),862            ("symmetricalDifference".to_string(), symmetrical_difference),863            ("isSubsetOf".to_string(), is_subset_of),864            ("isSupersetOf".to_string(), is_superset_of),865            ("forEach".to_string(), for_each),866            ("values".to_string(), values),867            ("keys".to_string(), keys),868            ("entries".to_string(), entries),869        ],870    );871}872873fn build_map_shape(shapes: &mut ShapeRegistry) {874    let has = add_function(875        shapes,876        Vec::new(),877        FunctionSignatureBuilder {878            positional_params: vec![Effect::Read],879            return_type: Type::Primitive,880            return_value_kind: ValueKind::Primitive,881            ..Default::default()882        },883        None,884        false,885    );886    let get = add_function(887        shapes,888        Vec::new(),889        FunctionSignatureBuilder {890            positional_params: vec![Effect::Read],891            callee_effect: Effect::Capture,892            return_type: Type::Poly,893            return_value_kind: ValueKind::Mutable,894            ..Default::default()895        },896        None,897        false,898    );899    let clear = add_function(900        shapes,901        Vec::new(),902        FunctionSignatureBuilder {903            callee_effect: Effect::Store,904            return_type: Type::Primitive,905            return_value_kind: ValueKind::Primitive,906            ..Default::default()907        },908        None,909        false,910    );911    let set = add_function(912        shapes,913        Vec::new(),914        FunctionSignatureBuilder {915            positional_params: vec![Effect::Capture, Effect::Capture],916            callee_effect: Effect::Store,917            return_type: Type::Object {918                shape_id: Some(BUILT_IN_MAP_ID.to_string()),919            },920            return_value_kind: ValueKind::Mutable,921            ..Default::default()922        },923        None,924        false,925    );926    let delete = add_function(927        shapes,928        Vec::new(),929        FunctionSignatureBuilder {930            positional_params: vec![Effect::Read],931            callee_effect: Effect::Store,932            return_type: Type::Primitive,933            return_value_kind: ValueKind::Primitive,934            ..Default::default()935        },936        None,937        false,938    );939    let size = Type::Primitive;940    let for_each = add_function(941        shapes,942        Vec::new(),943        FunctionSignatureBuilder {944            rest_param: Some(Effect::ConditionallyMutate),945            callee_effect: Effect::ConditionallyMutate,946            return_type: Type::Primitive,947            return_value_kind: ValueKind::Primitive,948            no_alias: true,949            mutable_only_if_operands_are_mutable: true,950            ..Default::default()951        },952        None,953        false,954    );955    let values = add_function(956        shapes,957        Vec::new(),958        FunctionSignatureBuilder {959            callee_effect: Effect::Capture,960            return_type: Type::Poly,961            return_value_kind: ValueKind::Mutable,962            ..Default::default()963        },964        None,965        false,966    );967    let keys = add_function(968        shapes,969        Vec::new(),970        FunctionSignatureBuilder {971            callee_effect: Effect::Capture,972            return_type: Type::Poly,973            return_value_kind: ValueKind::Mutable,974            ..Default::default()975        },976        None,977        false,978    );979    let entries = add_function(980        shapes,981        Vec::new(),982        FunctionSignatureBuilder {983            callee_effect: Effect::Capture,984            return_type: Type::Poly,985            return_value_kind: ValueKind::Mutable,986            ..Default::default()987        },988        None,989        false,990    );991992    add_object(993        shapes,994        Some(BUILT_IN_MAP_ID),995        vec![996            ("has".to_string(), has),997            ("get".to_string(), get),998            ("set".to_string(), set),999            ("clear".to_string(), clear),1000            ("delete".to_string(), delete),1001            ("size".to_string(), size),1002            ("forEach".to_string(), for_each),1003            ("values".to_string(), values),1004            ("keys".to_string(), keys),1005            ("entries".to_string(), entries),1006        ],1007    );1008}10091010fn build_weak_set_shape(shapes: &mut ShapeRegistry) {1011    let has = pure_primitive_fn(shapes);1012    let add = add_function(1013        shapes,1014        Vec::new(),1015        FunctionSignatureBuilder {1016            positional_params: vec![Effect::Capture],1017            callee_effect: Effect::Store,1018            return_type: Type::Object {1019                shape_id: Some(BUILT_IN_WEAK_SET_ID.to_string()),1020            },1021            return_value_kind: ValueKind::Mutable,1022            ..Default::default()1023        },1024        None,1025        false,1026    );1027    let delete = add_function(1028        shapes,1029        Vec::new(),1030        FunctionSignatureBuilder {1031            positional_params: vec![Effect::Read],1032            callee_effect: Effect::Store,1033            return_type: Type::Primitive,1034            return_value_kind: ValueKind::Primitive,1035            ..Default::default()1036        },1037        None,1038        false,1039    );10401041    add_object(1042        shapes,1043        Some(BUILT_IN_WEAK_SET_ID),1044        vec![1045            ("has".to_string(), has),1046            ("add".to_string(), add),1047            ("delete".to_string(), delete),1048        ],1049    );1050}10511052fn build_weak_map_shape(shapes: &mut ShapeRegistry) {1053    let has = pure_primitive_fn(shapes);1054    let get = add_function(1055        shapes,1056        Vec::new(),1057        FunctionSignatureBuilder {1058            positional_params: vec![Effect::Read],1059            callee_effect: Effect::Capture,1060            return_type: Type::Poly,1061            return_value_kind: ValueKind::Mutable,1062            ..Default::default()1063        },1064        None,1065        false,1066    );1067    let set = add_function(1068        shapes,1069        Vec::new(),1070        FunctionSignatureBuilder {1071            positional_params: vec![Effect::Capture, Effect::Capture],1072            callee_effect: Effect::Store,1073            return_type: Type::Object {1074                shape_id: Some(BUILT_IN_WEAK_MAP_ID.to_string()),1075            },1076            return_value_kind: ValueKind::Mutable,1077            ..Default::default()1078        },1079        None,1080        false,1081    );1082    let delete = add_function(1083        shapes,1084        Vec::new(),1085        FunctionSignatureBuilder {1086            positional_params: vec![Effect::Read],1087            callee_effect: Effect::Store,1088            return_type: Type::Primitive,1089            return_value_kind: ValueKind::Primitive,1090            ..Default::default()1091        },1092        None,1093        false,1094    );10951096    add_object(1097        shapes,1098        Some(BUILT_IN_WEAK_MAP_ID),1099        vec![1100            ("has".to_string(), has),1101            ("get".to_string(), get),1102            ("set".to_string(), set),1103            ("delete".to_string(), delete),1104        ],1105    );1106}11071108fn build_object_shape(shapes: &mut ShapeRegistry) {1109    // BuiltInObject: has toString() returning Primitive (matches TS BuiltInObjectId shape)1110    let to_string = add_function(1111        shapes,1112        Vec::new(),1113        FunctionSignatureBuilder {1114            return_type: Type::Primitive,1115            return_value_kind: ValueKind::Primitive,1116            ..Default::default()1117        },1118        None,1119        false,1120    );1121    add_object(1122        shapes,1123        Some(BUILT_IN_OBJECT_ID),1124        vec![("toString".to_string(), to_string)],1125    );1126    // BuiltInFunction: empty shape1127    add_object(shapes, Some(BUILT_IN_FUNCTION_ID), Vec::new());1128    // BuiltInJsx: empty shape1129    add_object(shapes, Some(BUILT_IN_JSX_ID), Vec::new());1130    // BuiltInMixedReadonly: has explicit method types + wildcard returning MixedReadonly1131    // (matches TS BuiltInMixedReadonlyId shape)1132    let mixed_to_string = add_function(1133        shapes,1134        Vec::new(),1135        FunctionSignatureBuilder {1136            rest_param: Some(Effect::Read),1137            return_type: Type::Primitive,1138            return_value_kind: ValueKind::Primitive,1139            ..Default::default()1140        },1141        None,1142        false,1143    );1144    let mixed_index_of = add_function(1145        shapes,1146        Vec::new(),1147        FunctionSignatureBuilder {1148            rest_param: Some(Effect::Read),1149            return_type: Type::Primitive,1150            return_value_kind: ValueKind::Primitive,1151            ..Default::default()1152        },1153        None,1154        false,1155    );1156    let mixed_includes = add_function(1157        shapes,1158        Vec::new(),1159        FunctionSignatureBuilder {1160            rest_param: Some(Effect::Read),1161            return_type: Type::Primitive,1162            return_value_kind: ValueKind::Primitive,1163            ..Default::default()1164        },1165        None,1166        false,1167    );1168    let mixed_at = add_function(1169        shapes,1170        Vec::new(),1171        FunctionSignatureBuilder {1172            positional_params: vec![Effect::Read],1173            return_type: Type::Object {1174                shape_id: Some(BUILT_IN_MIXED_READONLY_ID.to_string()),1175            },1176            callee_effect: Effect::Capture,1177            return_value_kind: ValueKind::Frozen,1178            ..Default::default()1179        },1180        None,1181        false,1182    );1183    let mixed_map = add_function(1184        shapes,1185        Vec::new(),1186        FunctionSignatureBuilder {1187            rest_param: Some(Effect::ConditionallyMutate),1188            return_type: Type::Object {1189                shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),1190            },1191            callee_effect: Effect::ConditionallyMutate,1192            return_value_kind: ValueKind::Mutable,1193            no_alias: true,1194            ..Default::default()1195        },1196        None,1197        false,1198    );1199    let mixed_flat_map = add_function(1200        shapes,1201        Vec::new(),1202        FunctionSignatureBuilder {1203            rest_param: Some(Effect::ConditionallyMutate),1204            return_type: Type::Object {1205                shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),1206            },1207            callee_effect: Effect::ConditionallyMutate,1208            return_value_kind: ValueKind::Mutable,1209            no_alias: true,1210            ..Default::default()1211        },1212        None,1213        false,1214    );1215    let mixed_filter = add_function(1216        shapes,1217        Vec::new(),1218        FunctionSignatureBuilder {1219            rest_param: Some(Effect::ConditionallyMutate),1220            return_type: Type::Object {1221                shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),1222            },1223            callee_effect: Effect::ConditionallyMutate,1224            return_value_kind: ValueKind::Mutable,1225            no_alias: true,1226            ..Default::default()1227        },1228        None,1229        false,1230    );1231    let mixed_concat = add_function(1232        shapes,1233        Vec::new(),1234        FunctionSignatureBuilder {1235            rest_param: Some(Effect::Capture),1236            return_type: Type::Object {1237                shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),1238            },1239            callee_effect: Effect::Capture,1240            return_value_kind: ValueKind::Mutable,1241            ..Default::default()1242        },1243        None,1244        false,1245    );1246    let mixed_slice = add_function(1247        shapes,1248        Vec::new(),1249        FunctionSignatureBuilder {1250            rest_param: Some(Effect::Read),1251            return_type: Type::Object {1252                shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),1253            },1254            callee_effect: Effect::Capture,1255            return_value_kind: ValueKind::Mutable,1256            ..Default::default()1257        },1258        None,1259        false,1260    );1261    let mixed_every = add_function(1262        shapes,1263        Vec::new(),1264        FunctionSignatureBuilder {1265            rest_param: Some(Effect::ConditionallyMutate),1266            return_type: Type::Primitive,1267            callee_effect: Effect::ConditionallyMutate,1268            return_value_kind: ValueKind::Primitive,1269            no_alias: true,1270            mutable_only_if_operands_are_mutable: true,1271            ..Default::default()1272        },1273        None,1274        false,1275    );1276    let mixed_some = add_function(1277        shapes,1278        Vec::new(),1279        FunctionSignatureBuilder {1280            rest_param: Some(Effect::ConditionallyMutate),1281            return_type: Type::Primitive,1282            callee_effect: Effect::ConditionallyMutate,1283            return_value_kind: ValueKind::Primitive,1284            no_alias: true,1285            mutable_only_if_operands_are_mutable: true,1286            ..Default::default()1287        },1288        None,1289        false,1290    );1291    let mixed_find = add_function(1292        shapes,1293        Vec::new(),1294        FunctionSignatureBuilder {1295            rest_param: Some(Effect::ConditionallyMutate),1296            return_type: Type::Object {1297                shape_id: Some(BUILT_IN_MIXED_READONLY_ID.to_string()),1298            },1299            callee_effect: Effect::ConditionallyMutate,1300            return_value_kind: ValueKind::Frozen,1301            no_alias: true,1302            mutable_only_if_operands_are_mutable: true,1303            ..Default::default()1304        },1305        None,1306        false,1307    );1308    let mixed_find_index = add_function(1309        shapes,1310        Vec::new(),1311        FunctionSignatureBuilder {1312            rest_param: Some(Effect::ConditionallyMutate),1313            return_type: Type::Primitive,1314            callee_effect: Effect::ConditionallyMutate,1315            return_value_kind: ValueKind::Primitive,1316            no_alias: true,1317            mutable_only_if_operands_are_mutable: true,1318            ..Default::default()1319        },1320        None,1321        false,1322    );1323    let mixed_join = add_function(1324        shapes,1325        Vec::new(),1326        FunctionSignatureBuilder {1327            rest_param: Some(Effect::Read),1328            return_type: Type::Primitive,1329            return_value_kind: ValueKind::Primitive,1330            ..Default::default()1331        },1332        None,1333        false,1334    );1335    let mut mixed_props = FxHashMap::default();1336    mixed_props.insert("toString".to_string(), mixed_to_string);1337    mixed_props.insert("indexOf".to_string(), mixed_index_of);1338    mixed_props.insert("includes".to_string(), mixed_includes);1339    mixed_props.insert("at".to_string(), mixed_at);1340    mixed_props.insert("map".to_string(), mixed_map);1341    mixed_props.insert("flatMap".to_string(), mixed_flat_map);1342    mixed_props.insert("filter".to_string(), mixed_filter);1343    mixed_props.insert("concat".to_string(), mixed_concat);1344    mixed_props.insert("slice".to_string(), mixed_slice);1345    mixed_props.insert("every".to_string(), mixed_every);1346    mixed_props.insert("some".to_string(), mixed_some);1347    mixed_props.insert("find".to_string(), mixed_find);1348    mixed_props.insert("findIndex".to_string(), mixed_find_index);1349    mixed_props.insert("join".to_string(), mixed_join);1350    mixed_props.insert(1351        "*".to_string(),1352        Type::Object {1353            shape_id: Some(BUILT_IN_MIXED_READONLY_ID.to_string()),1354        },1355    );1356    shapes.insert(1357        BUILT_IN_MIXED_READONLY_ID.to_string(),1358        ObjectShape {1359            properties: mixed_props,1360            function_type: None,1361        },1362    );1363}13641365fn build_ref_shapes(shapes: &mut ShapeRegistry) {1366    // BuiltInUseRefId: { current: Object { shapeId: BuiltInRefValue } }1367    add_object(1368        shapes,1369        Some(BUILT_IN_USE_REF_ID),1370        vec![(1371            "current".to_string(),1372            Type::Object {1373                shape_id: Some(BUILT_IN_REF_VALUE_ID.to_string()),1374            },1375        )],1376    );1377    // BuiltInRefValue: { *: Object { shapeId: BuiltInRefValue } } (self-referencing)1378    add_object(1379        shapes,1380        Some(BUILT_IN_REF_VALUE_ID),1381        vec![(1382            "*".to_string(),1383            Type::Object {1384                shape_id: Some(BUILT_IN_REF_VALUE_ID.to_string()),1385            },1386        )],1387    );1388}13891390fn build_state_shapes(shapes: &mut ShapeRegistry) {1391    // BuiltInSetState: function that freezes its argument1392    let set_state = add_function(1393        shapes,1394        Vec::new(),1395        FunctionSignatureBuilder {1396            rest_param: Some(Effect::Freeze),1397            return_type: Type::Primitive,1398            return_value_kind: ValueKind::Primitive,1399            ..Default::default()1400        },1401        Some(BUILT_IN_SET_STATE_ID),1402        false,1403    );14041405    // BuiltInUseState: object with [0] = Poly (state), [1] = setState function1406    add_object(1407        shapes,1408        Some(BUILT_IN_USE_STATE_ID),1409        vec![("0".to_string(), Type::Poly), ("1".to_string(), set_state)],1410    );14111412    // BuiltInSetActionState1413    let set_action_state = add_function(1414        shapes,1415        Vec::new(),1416        FunctionSignatureBuilder {1417            rest_param: Some(Effect::Freeze),1418            return_type: Type::Primitive,1419            return_value_kind: ValueKind::Primitive,1420            ..Default::default()1421        },1422        Some(BUILT_IN_SET_ACTION_STATE_ID),1423        false,1424    );14251426    // BuiltInUseActionState: [0] = Poly, [1] = setActionState function1427    add_object(1428        shapes,1429        Some(BUILT_IN_USE_ACTION_STATE_ID),1430        vec![1431            ("0".to_string(), Type::Poly),1432            ("1".to_string(), set_action_state),1433        ],1434    );14351436    // BuiltInDispatch1437    let dispatch = add_function(1438        shapes,1439        Vec::new(),1440        FunctionSignatureBuilder {1441            rest_param: Some(Effect::Freeze),1442            return_type: Type::Primitive,1443            return_value_kind: ValueKind::Primitive,1444            ..Default::default()1445        },1446        Some(BUILT_IN_DISPATCH_ID),1447        false,1448    );14491450    // BuiltInUseReducer: [0] = Poly, [1] = dispatch function1451    add_object(1452        shapes,1453        Some(BUILT_IN_USE_REDUCER_ID),1454        vec![("0".to_string(), Type::Poly), ("1".to_string(), dispatch)],1455    );14561457    // BuiltInStartTransition1458    let start_transition = add_function(1459        shapes,1460        Vec::new(),1461        FunctionSignatureBuilder {1462            // Note: TS uses restParam: null for startTransition1463            return_type: Type::Primitive,1464            return_value_kind: ValueKind::Primitive,1465            ..Default::default()1466        },1467        Some(BUILT_IN_START_TRANSITION_ID),1468        false,1469    );14701471    // BuiltInUseTransition: [0] = Primitive (isPending), [1] = startTransition function1472    add_object(1473        shapes,1474        Some(BUILT_IN_USE_TRANSITION_ID),1475        vec![1476            ("0".to_string(), Type::Primitive),1477            ("1".to_string(), start_transition),1478        ],1479    );14801481    // BuiltInSetOptimistic1482    let set_optimistic = add_function(1483        shapes,1484        Vec::new(),1485        FunctionSignatureBuilder {1486            rest_param: Some(Effect::Freeze),1487            return_type: Type::Primitive,1488            return_value_kind: ValueKind::Primitive,1489            ..Default::default()1490        },1491        Some(BUILT_IN_SET_OPTIMISTIC_ID),1492        false,1493    );14941495    // BuiltInUseOptimistic: [0] = Poly, [1] = setOptimistic function1496    add_object(1497        shapes,1498        Some(BUILT_IN_USE_OPTIMISTIC_ID),1499        vec![1500            ("0".to_string(), Type::Poly),1501            ("1".to_string(), set_optimistic),1502        ],1503    );1504}15051506fn build_hook_shapes(shapes: &mut ShapeRegistry) {1507    // BuiltInEffectEvent function shape (the return value of useEffectEvent)1508    add_function(1509        shapes,1510        Vec::new(),1511        FunctionSignatureBuilder {1512            rest_param: Some(Effect::ConditionallyMutate),1513            callee_effect: Effect::ConditionallyMutate,1514            return_type: Type::Poly,1515            return_value_kind: ValueKind::Mutable,1516            ..Default::default()1517        },1518        Some(BUILT_IN_EFFECT_EVENT_ID),1519        false,1520    );1521}15221523fn build_misc_shapes(shapes: &mut ShapeRegistry) {1524    // ReanimatedSharedValue: empty properties (matching TS)1525    add_object(shapes, Some(REANIMATED_SHARED_VALUE_ID), Vec::new());1526}15271528/// Build the reanimated module type. Ported from TS `getReanimatedModuleType`.1529pub fn get_reanimated_module_type(shapes: &mut ShapeRegistry) -> Type {1530    let mut reanimated_type: Vec<(String, Type)> = Vec::new();15311532    // hooks that freeze args and return frozen value1533    let frozen_hooks = [1534        "useFrameCallback",1535        "useAnimatedStyle",1536        "useAnimatedProps",1537        "useAnimatedScrollHandler",1538        "useAnimatedReaction",1539        "useWorkletCallback",1540    ];1541    for hook in &frozen_hooks {1542        let hook_type = add_hook(1543            shapes,1544            HookSignatureBuilder {1545                rest_param: Some(Effect::Freeze),1546                return_type: Type::Poly,1547                return_value_kind: ValueKind::Frozen,1548                no_alias: true,1549                hook_kind: HookKind::Custom,1550                ..Default::default()1551            },1552            None,1553        );1554        reanimated_type.push((hook.to_string(), hook_type));1555    }15561557    // hooks that return a mutable value (modelled as shared value)1558    let mutable_hooks = ["useSharedValue", "useDerivedValue"];1559    for hook in &mutable_hooks {1560        let hook_type = add_hook(1561            shapes,1562            HookSignatureBuilder {1563                rest_param: Some(Effect::Freeze),1564                return_type: Type::Object {1565                    shape_id: Some(REANIMATED_SHARED_VALUE_ID.to_string()),1566                },1567                return_value_kind: ValueKind::Mutable,1568                no_alias: true,1569                hook_kind: HookKind::Custom,1570                ..Default::default()1571            },1572            None,1573        );1574        reanimated_type.push((hook.to_string(), hook_type));1575    }15761577    // functions that return mutable value1578    let funcs = [1579        "withTiming",1580        "withSpring",1581        "createAnimatedPropAdapter",1582        "withDecay",1583        "withRepeat",1584        "runOnUI",1585        "executeOnUIRuntimeSync",1586    ];1587    for func_name in &funcs {1588        let func_type = add_function(1589            shapes,1590            Vec::new(),1591            FunctionSignatureBuilder {1592                rest_param: Some(Effect::Read),1593                return_type: Type::Poly,1594                return_value_kind: ValueKind::Mutable,1595                no_alias: true,1596                ..Default::default()1597            },1598            None,1599            false,1600        );1601        reanimated_type.push((func_name.to_string(), func_type));1602    }16031604    add_object(shapes, None, reanimated_type)1605}16061607// =============================================================================1608// Build default globals (DEFAULT_GLOBALS from Globals.ts)1609// =============================================================================16101611/// Build the default globals registry. This corresponds to TS `DEFAULT_GLOBALS`.1612///1613/// Requires a mutable reference to the shapes registry because some globals1614/// (like Object.keys, Array.isArray) register new shapes.1615pub fn build_default_globals(shapes: &mut ShapeRegistry) -> GlobalRegistry {1616    let mut globals = GlobalRegistry::new();16171618    // React APIs — returns the list so we can reuse them for the React namespace1619    let react_apis = build_react_apis(shapes, &mut globals);16201621    // Untyped globals (treated as Poly) — must come before typed globals1622    // so typed definitions take priority (matching TS ordering)1623    for name in UNTYPED_GLOBALS {1624        globals.insert(name.to_string(), Type::Poly);1625    }16261627    // Typed JS globals (overwrites Poly entries from UNTYPED_GLOBALS).1628    // Returns the list of typed globals for use as globalThis/global properties.1629    let typed_globals = build_typed_globals(shapes, &mut globals, react_apis);16301631    // globalThis and global — populated with all typed globals as properties1632    // (matching TS: `addObject(DEFAULT_SHAPES, 'globalThis', TYPED_GLOBALS)`)1633    globals.insert(1634        "globalThis".to_string(),1635        add_object(shapes, Some("globalThis"), typed_globals.clone()),1636    );1637    globals.insert(1638        "global".to_string(),1639        add_object(shapes, Some("global"), typed_globals),1640    );16411642    globals1643}16441645const UNTYPED_GLOBALS: &[&str] = &[1646    "Object",1647    "Function",1648    "RegExp",1649    "Date",1650    "Error",1651    "TypeError",1652    "RangeError",1653    "ReferenceError",1654    "SyntaxError",1655    "URIError",1656    "EvalError",1657    "DataView",1658    "Float32Array",1659    "Float64Array",1660    "Int8Array",1661    "Int16Array",1662    "Int32Array",1663    "WeakMap",1664    "Uint8Array",1665    "Uint8ClampedArray",1666    "Uint16Array",1667    "Uint32Array",1668    "ArrayBuffer",1669    "JSON",1670    "console",1671    "eval",1672];16731674/// Build the React API types (REACT_APIS from TS). Returns the list of (name, type) pairs1675/// so they can be reused as properties of the React namespace object (matching TS behavior1676/// where the SAME type objects are used in both DEFAULT_GLOBALS and the React namespace).1677fn build_react_apis(1678    shapes: &mut ShapeRegistry,1679    globals: &mut GlobalRegistry,1680) -> Vec<(String, Type)> {1681    let mut react_apis: Vec<(String, Type)> = Vec::new();16821683    // useContext1684    let use_context = add_hook(1685        shapes,1686        HookSignatureBuilder {1687            rest_param: Some(Effect::Read),1688            return_type: Type::Poly,1689            return_value_kind: ValueKind::Frozen,1690            return_value_reason: Some(ValueReason::Context),1691            hook_kind: HookKind::UseContext,1692            ..Default::default()1693        },1694        Some(BUILT_IN_USE_CONTEXT_HOOK_ID),1695    );1696    react_apis.push(("useContext".to_string(), use_context));16971698    // useState1699    let use_state = add_hook(1700        shapes,1701        HookSignatureBuilder {1702            rest_param: Some(Effect::Freeze),1703            return_type: Type::Object {1704                shape_id: Some(BUILT_IN_USE_STATE_ID.to_string()),1705            },1706            return_value_kind: ValueKind::Frozen,1707            return_value_reason: Some(ValueReason::State),1708            hook_kind: HookKind::UseState,1709            ..Default::default()1710        },1711        None,1712    );1713    react_apis.push(("useState".to_string(), use_state));17141715    // useActionState1716    let use_action_state = add_hook(1717        shapes,1718        HookSignatureBuilder {1719            rest_param: Some(Effect::Freeze),1720            return_type: Type::Object {1721                shape_id: Some(BUILT_IN_USE_ACTION_STATE_ID.to_string()),1722            },1723            return_value_kind: ValueKind::Frozen,1724            return_value_reason: Some(ValueReason::State),1725            hook_kind: HookKind::UseActionState,1726            ..Default::default()1727        },1728        None,1729    );1730    react_apis.push(("useActionState".to_string(), use_action_state));17311732    // useReducer1733    let use_reducer = add_hook(1734        shapes,1735        HookSignatureBuilder {1736            rest_param: Some(Effect::Freeze),1737            return_type: Type::Object {1738                shape_id: Some(BUILT_IN_USE_REDUCER_ID.to_string()),1739            },1740            return_value_kind: ValueKind::Frozen,1741            return_value_reason: Some(ValueReason::ReducerState),1742            hook_kind: HookKind::UseReducer,1743            ..Default::default()1744        },1745        None,1746    );1747    react_apis.push(("useReducer".to_string(), use_reducer));17481749    // useRef1750    let use_ref = add_hook(1751        shapes,1752        HookSignatureBuilder {1753            rest_param: Some(Effect::Capture),1754            return_type: Type::Object {1755                shape_id: Some(BUILT_IN_USE_REF_ID.to_string()),1756            },1757            return_value_kind: ValueKind::Mutable,1758            hook_kind: HookKind::UseRef,1759            ..Default::default()1760        },1761        None,1762    );1763    react_apis.push(("useRef".to_string(), use_ref));17641765    // useImperativeHandle1766    let use_imperative_handle = add_hook(1767        shapes,1768        HookSignatureBuilder {1769            rest_param: Some(Effect::Freeze),1770            return_type: Type::Primitive,1771            return_value_kind: ValueKind::Frozen,1772            hook_kind: HookKind::UseImperativeHandle,1773            ..Default::default()1774        },1775        None,1776    );1777    react_apis.push(("useImperativeHandle".to_string(), use_imperative_handle));17781779    // useMemo1780    let use_memo = add_hook(1781        shapes,1782        HookSignatureBuilder {1783            rest_param: Some(Effect::Freeze),1784            return_type: Type::Poly,1785            return_value_kind: ValueKind::Frozen,1786            hook_kind: HookKind::UseMemo,1787            ..Default::default()1788        },1789        None,1790    );1791    react_apis.push(("useMemo".to_string(), use_memo));17921793    // useCallback1794    let use_callback = add_hook(1795        shapes,1796        HookSignatureBuilder {1797            rest_param: Some(Effect::Freeze),1798            return_type: Type::Poly,1799            return_value_kind: ValueKind::Frozen,1800            hook_kind: HookKind::UseCallback,1801            ..Default::default()1802        },1803        None,1804    );1805    react_apis.push(("useCallback".to_string(), use_callback));18061807    // useEffect (with aliasing signature)1808    let use_effect = add_hook(1809        shapes,1810        HookSignatureBuilder {1811            rest_param: Some(Effect::Freeze),1812            return_type: Type::Primitive,1813            return_value_kind: ValueKind::Frozen,1814            hook_kind: HookKind::UseEffect,1815            aliasing: Some(AliasingSignatureConfig {1816                receiver: "@receiver".to_string(),1817                params: Vec::new(),1818                rest: Some("@rest".to_string()),1819                returns: "@returns".to_string(),1820                temporaries: vec!["@effect".to_string()],1821                effects: vec![1822                    AliasingEffectConfig::Freeze {1823                        value: "@rest".to_string(),1824                        reason: ValueReason::Effect,1825                    },1826                    AliasingEffectConfig::Create {1827                        into: "@effect".to_string(),1828                        value: ValueKind::Frozen,1829                        reason: ValueReason::KnownReturnSignature,1830                    },1831                    AliasingEffectConfig::Capture {1832                        from: "@rest".to_string(),1833                        into: "@effect".to_string(),1834                    },1835                    AliasingEffectConfig::Create {1836                        into: "@returns".to_string(),1837                        value: ValueKind::Primitive,1838                        reason: ValueReason::KnownReturnSignature,1839                    },1840                ],1841            }),1842            ..Default::default()1843        },1844        Some(BUILT_IN_USE_EFFECT_HOOK_ID),1845    );1846    react_apis.push(("useEffect".to_string(), use_effect));18471848    // useLayoutEffect1849    let use_layout_effect = add_hook(1850        shapes,1851        HookSignatureBuilder {1852            rest_param: Some(Effect::Freeze),1853            return_type: Type::Poly,1854            return_value_kind: ValueKind::Frozen,1855            hook_kind: HookKind::UseLayoutEffect,1856            ..Default::default()1857        },1858        Some(BUILT_IN_USE_LAYOUT_EFFECT_HOOK_ID),1859    );1860    react_apis.push(("useLayoutEffect".to_string(), use_layout_effect));18611862    // useInsertionEffect1863    let use_insertion_effect = add_hook(1864        shapes,1865        HookSignatureBuilder {1866            rest_param: Some(Effect::Freeze),1867            return_type: Type::Poly,1868            return_value_kind: ValueKind::Frozen,1869            hook_kind: HookKind::UseInsertionEffect,1870            ..Default::default()1871        },1872        Some(BUILT_IN_USE_INSERTION_EFFECT_HOOK_ID),1873    );1874    react_apis.push(("useInsertionEffect".to_string(), use_insertion_effect));18751876    // useTransition1877    let use_transition = add_hook(1878        shapes,1879        HookSignatureBuilder {1880            rest_param: None,1881            return_type: Type::Object {1882                shape_id: Some(BUILT_IN_USE_TRANSITION_ID.to_string()),1883            },1884            return_value_kind: ValueKind::Frozen,1885            hook_kind: HookKind::UseTransition,1886            ..Default::default()1887        },1888        None,1889    );1890    react_apis.push(("useTransition".to_string(), use_transition));18911892    // useOptimistic1893    let use_optimistic = add_hook(1894        shapes,1895        HookSignatureBuilder {1896            rest_param: Some(Effect::Freeze),1897            return_type: Type::Object {1898                shape_id: Some(BUILT_IN_USE_OPTIMISTIC_ID.to_string()),1899            },1900            return_value_kind: ValueKind::Frozen,1901            return_value_reason: Some(ValueReason::State),1902            hook_kind: HookKind::UseOptimistic,1903            ..Default::default()1904        },1905        None,1906    );1907    react_apis.push(("useOptimistic".to_string(), use_optimistic));19081909    // use (not a hook, it's a function)1910    let use_fn = add_function(1911        shapes,1912        Vec::new(),1913        FunctionSignatureBuilder {1914            rest_param: Some(Effect::Freeze),1915            return_type: Type::Poly,1916            return_value_kind: ValueKind::Frozen,1917            ..Default::default()1918        },1919        Some(BUILT_IN_USE_OPERATOR_ID),1920        false,1921    );1922    react_apis.push(("use".to_string(), use_fn));19231924    // useEffectEvent1925    let use_effect_event = add_hook(1926        shapes,1927        HookSignatureBuilder {1928            rest_param: Some(Effect::Freeze),1929            return_type: Type::Function {1930                shape_id: Some(BUILT_IN_EFFECT_EVENT_ID.to_string()),1931                return_type: Box::new(Type::Poly),1932                is_constructor: false,1933            },1934            return_value_kind: ValueKind::Frozen,1935            hook_kind: HookKind::UseEffectEvent,1936            ..Default::default()1937        },1938        Some(BUILT_IN_USE_EFFECT_EVENT_ID),1939    );1940    react_apis.push(("useEffectEvent".to_string(), use_effect_event));19411942    // Insert all React APIs as standalone globals1943    for (name, ty) in &react_apis {1944        globals.insert(name.clone(), ty.clone());1945    }19461947    react_apis1948}19491950/// Build typed globals and return them as a list for use as globalThis/global properties.1951fn build_typed_globals(1952    shapes: &mut ShapeRegistry,1953    globals: &mut GlobalRegistry,1954    react_apis: Vec<(String, Type)>,1955) -> Vec<(String, Type)> {1956    let mut typed_globals: Vec<(String, Type)> = Vec::new();1957    // Object1958    let obj_keys = add_function(1959        shapes,1960        Vec::new(),1961        FunctionSignatureBuilder {1962            positional_params: vec![Effect::Read],1963            return_type: Type::Object {1964                shape_id: Some(BUILT_IN_ARRAY_ID.to_string()),1965            },1966            return_value_kind: ValueKind::Mutable,1967            aliasing: Some(AliasingSignatureConfig {1968                receiver: "@receiver".to_string(),1969                params: vec!["@object".to_string()],1970                rest: None,1971                returns: "@returns".to_string(),1972                temporaries: Vec::new(),1973                effects: vec![1974                    AliasingEffectConfig::Create {1975                        into: "@returns".to_string(),1976                        value: ValueKind::Mutable,1977                        reason: ValueReason::KnownReturnSignature,1978                    },1979                    // Only keys are captured, and keys are immutable1980                    AliasingEffectConfig::ImmutableCapture {1981                        from: "@object".to_string(),1982                        into: "@returns".to_string(),1983                    },1984                ],1985            }),1986            ..Default::default()1987        },1988        None,1989        false,1990    );1991    let obj_from_entries = add_function(1992        shapes,1993        Vec::new(),1994        FunctionSignatureBuilder {1995            positional_params: vec![Effect::ConditionallyMutate],1996            return_type: Type::Object {1997                shape_id: Some(BUILT_IN_OBJECT_ID.to_string()),1998            },1999            return_value_kind: ValueKind::Mutable,2000            ..Default::default()

Code quality findings 15

Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
// BuiltInUseState: object with [0] = Poly (state), [1] = setState function
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use crate::object_shape::*;
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
let is_hook = match &ty {
Performance Info: Calling .to_string() (especially on &str) allocates a new String. If done repeatedly in loops, consider alternatives like working with &str or using crates like `itoa`/`ryu` for number-to-string conversion.
info performance to-string-in-loop
reanimated_type.push((hook.to_string(), hook_type));
Performance Info: Calling .push() repeatedly inside a loop without prior capacity reservation can lead to multiple reallocations. Consider using `Vec::with_capacity(n)` or `vec.reserve(n)` if the approximate number of elements is known.
info performance push-without-reserve
reanimated_type.push((hook.to_string(), hook_type));
Performance Info: Calling .to_string() (especially on &str) allocates a new String. If done repeatedly in loops, consider alternatives like working with &str or using crates like `itoa`/`ryu` for number-to-string conversion.
info performance to-string-in-loop
shape_id: Some(REANIMATED_SHARED_VALUE_ID.to_string()),
Performance Info: Calling .to_string() (especially on &str) allocates a new String. If done repeatedly in loops, consider alternatives like working with &str or using crates like `itoa`/`ryu` for number-to-string conversion.
info performance to-string-in-loop
globals.insert(name.to_string(), Type::Poly);
Performance Info: Calling .to_string() (especially on &str) allocates a new String. If done repeatedly in loops, consider alternatives like working with &str or using crates like `itoa`/`ryu` for number-to-string conversion.
info performance to-string-in-loop
react_apis.push(("useEffectEvent".to_string(), use_effect_event));
Performance Info: Calling .push() repeatedly inside a loop without prior capacity reservation can lead to multiple reallocations. Consider using `Vec::with_capacity(n)` or `vec.reserve(n)` if the approximate number of elements is known.
info performance push-without-reserve
react_apis.push(("useEffectEvent".to_string(), use_effect_event));
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info performance clone-in-loop
globals.insert(name.clone(), ty.clone());
Performance Info: Calling .to_string() (especially on &str) allocates a new String. If done repeatedly in loops, consider alternatives like working with &str or using crates like `itoa`/`ryu` for number-to-string conversion.
info performance to-string-in-loop
.map(|name| (name.to_string(), pure_primitive_fn(shapes)))
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info performance clone-in-loop
typed_globals.push(("console".to_string(), console_global.clone()));
Performance Info: Calling .to_string() (especially on &str) allocates a new String. If done repeatedly in loops, consider alternatives like working with &str or using crates like `itoa`/`ryu` for number-to-string conversion.
info performance to-string-in-loop
typed_globals.push(("console".to_string(), console_global.clone()));
Performance Info: Calling .push() repeatedly inside a loop without prior capacity reservation can lead to multiple reallocations. Consider using `Vec::with_capacity(n)` or `vec.reserve(n)` if the approximate number of elements is known.
info performance push-without-reserve
typed_globals.push(("console".to_string(), console_global.clone()));
Performance Info: Calling .to_string() (especially on &str) allocates a new String. If done repeatedly in loops, consider alternatives like working with &str or using crates like `itoa`/`ryu` for number-to-string conversion.
info performance to-string-in-loop
globals.insert("console".to_string(), console_global);

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.