Skip to main content

rexlang_engine/
engine.rs

1//! Core engine implementation for Rex.
2
3use std::collections::{BTreeMap, HashMap, HashSet};
4use std::fmt::Write as _;
5use std::future::Future;
6use std::hash::{Hash, Hasher};
7use std::sync::{Arc, Mutex};
8
9use async_recursion::async_recursion;
10use futures::{FutureExt, future::BoxFuture, pin_mut};
11use rexlang_ast::expr::{
12    ClassDecl, Decl, DeclareFnDecl, Expr, FnDecl, InstanceDecl, NameRef, Pattern, Program, Scope,
13    Symbol, TypeConstraint, TypeDecl, TypeExpr, Var, intern, sym, sym_eq,
14};
15use rexlang_lexer::span::Span;
16use rexlang_typesystem::{
17    AdtDecl, BuiltinTypeId, CollectAdtsError, Instance, Predicate, PreparedInstanceDecl, Scheme,
18    Subst, Type, TypeError, TypeKind, TypeSystem, TypeVarSupply, TypedExpr, TypedExprKind, Types,
19    compose_subst, entails, infer_typed, infer_with_gas, instantiate, unify,
20};
21use rexlang_util::GasMeter;
22
23use crate::libraries::{
24    CanonicalSymbol, Library, LibraryExports, LibraryId, LibrarySystem, ResolveRequest,
25    ResolvedLibrary, ResolvedLibraryContent, SymbolKind, VirtualLibraryModule,
26    interface_decls_from_program, library_key_for_library, parse_program_from_source,
27    prefix_for_library, qualify_program, virtual_export_name,
28};
29use crate::prelude::{
30    inject_boolean_ops, inject_equality_ops, inject_json_primops, inject_list_builtins,
31    inject_numeric_ops, inject_option_result_builtins, inject_order_ops, inject_prelude_adts,
32    inject_show_ops,
33};
34use crate::value::{Closure, Heap, Pointer, Value, list_to_vec};
35use crate::{
36    CancellationToken, EngineError, Env, FromPointer, IntoPointer, RexType, evaluator::EvaluatorRef,
37};
38
39pub trait RexDefault<State>
40where
41    State: Clone + Send + Sync + 'static,
42{
43    fn rex_default(engine: &Engine<State>) -> Result<Pointer, EngineError>;
44}
45
46pub const ROOT_LIBRARY_NAME: &str = "__root__";
47pub const PRELUDE_LIBRARY_NAME: &str = "Prelude";
48
49#[derive(Clone, Debug, PartialEq, Eq)]
50pub enum PreludeMode {
51    Enabled,
52    Disabled,
53}
54
55#[derive(Clone, Debug)]
56pub struct EngineOptions {
57    pub prelude: PreludeMode,
58    pub default_imports: Vec<String>,
59}
60
61impl Default for EngineOptions {
62    fn default() -> Self {
63        Self {
64            prelude: PreludeMode::Enabled,
65            default_imports: vec![PRELUDE_LIBRARY_NAME.to_string()],
66        }
67    }
68}
69
70/// Shared ADT registration surface for derived and manually implemented Rust types.
71pub trait RexAdt: RexType {
72    fn rex_adt_decl() -> Result<AdtDecl, EngineError>;
73
74    fn rex_adt_family() -> Result<Vec<AdtDecl>, EngineError> {
75        let mut out = Vec::new();
76        <Self as RexType>::collect_rex_family(&mut out)?;
77        Ok(out)
78    }
79
80    fn inject_rex<State: Clone + Send + Sync + 'static>(
81        engine: &mut Engine<State>,
82    ) -> Result<(), EngineError>
83    where
84        Self: Sized,
85    {
86        let mut family = Vec::new();
87        <Self as RexType>::collect_rex_family(&mut family)?;
88        for adt in order_adt_family(family)? {
89            engine.inject_adt(adt)?;
90        }
91        Ok(())
92    }
93}
94
95pub(crate) fn check_runtime_cancelled<State: Clone + Send + Sync + 'static>(
96    runtime: &RuntimeSnapshot<State>,
97) -> Result<(), EngineError> {
98    if runtime.cancel.is_cancelled() {
99        Err(EngineError::Cancelled)
100    } else {
101        Ok(())
102    }
103}
104
105fn alloc_uint_literal_as<State: Clone + Send + Sync + 'static>(
106    engine: &RuntimeSnapshot<State>,
107    value: u64,
108    typ: &Type,
109) -> Result<Pointer, EngineError> {
110    match typ.as_ref() {
111        TypeKind::Var(_) => {
112            engine
113                .heap
114                .alloc_i32(i32::try_from(value).map_err(|_| EngineError::NativeType {
115                    expected: "i32".into(),
116                    got: value.to_string(),
117                })?)
118        }
119        TypeKind::Con(tc) => match tc.builtin_id {
120            Some(BuiltinTypeId::U8) => {
121                engine
122                    .heap
123                    .alloc_u8(u8::try_from(value).map_err(|_| EngineError::NativeType {
124                        expected: "u8".into(),
125                        got: value.to_string(),
126                    })?)
127            }
128            Some(BuiltinTypeId::U16) => {
129                engine.heap.alloc_u16(u16::try_from(value).map_err(|_| {
130                    EngineError::NativeType {
131                        expected: "u16".into(),
132                        got: value.to_string(),
133                    }
134                })?)
135            }
136            Some(BuiltinTypeId::U32) => {
137                engine.heap.alloc_u32(u32::try_from(value).map_err(|_| {
138                    EngineError::NativeType {
139                        expected: "u32".into(),
140                        got: value.to_string(),
141                    }
142                })?)
143            }
144            Some(BuiltinTypeId::U64) => engine.heap.alloc_u64(value),
145            Some(BuiltinTypeId::I8) => {
146                engine
147                    .heap
148                    .alloc_i8(i8::try_from(value).map_err(|_| EngineError::NativeType {
149                        expected: "i8".into(),
150                        got: value.to_string(),
151                    })?)
152            }
153            Some(BuiltinTypeId::I16) => {
154                engine.heap.alloc_i16(i16::try_from(value).map_err(|_| {
155                    EngineError::NativeType {
156                        expected: "i16".into(),
157                        got: value.to_string(),
158                    }
159                })?)
160            }
161            Some(BuiltinTypeId::I32) => {
162                engine.heap.alloc_i32(i32::try_from(value).map_err(|_| {
163                    EngineError::NativeType {
164                        expected: "i32".into(),
165                        got: value.to_string(),
166                    }
167                })?)
168            }
169            Some(BuiltinTypeId::I64) => {
170                engine.heap.alloc_i64(i64::try_from(value).map_err(|_| {
171                    EngineError::NativeType {
172                        expected: "i64".into(),
173                        got: value.to_string(),
174                    }
175                })?)
176            }
177            _ => Err(EngineError::NativeType {
178                expected: "integral".into(),
179                got: typ.to_string(),
180            }),
181        },
182        _ => Err(EngineError::NativeType {
183            expected: "integral".into(),
184            got: typ.to_string(),
185        }),
186    }
187}
188
189fn alloc_int_literal_as<State: Clone + Send + Sync + 'static>(
190    engine: &RuntimeSnapshot<State>,
191    value: i64,
192    typ: &Type,
193) -> Result<Pointer, EngineError> {
194    match typ.as_ref() {
195        TypeKind::Var(_) => {
196            engine
197                .heap
198                .alloc_i32(i32::try_from(value).map_err(|_| EngineError::NativeType {
199                    expected: "i32".into(),
200                    got: value.to_string(),
201                })?)
202        }
203        TypeKind::Con(tc) => match tc.builtin_id {
204            Some(BuiltinTypeId::I8) => {
205                engine
206                    .heap
207                    .alloc_i8(i8::try_from(value).map_err(|_| EngineError::NativeType {
208                        expected: "i8".into(),
209                        got: value.to_string(),
210                    })?)
211            }
212            Some(BuiltinTypeId::I16) => {
213                engine.heap.alloc_i16(i16::try_from(value).map_err(|_| {
214                    EngineError::NativeType {
215                        expected: "i16".into(),
216                        got: value.to_string(),
217                    }
218                })?)
219            }
220            Some(BuiltinTypeId::I32) => {
221                engine.heap.alloc_i32(i32::try_from(value).map_err(|_| {
222                    EngineError::NativeType {
223                        expected: "i32".into(),
224                        got: value.to_string(),
225                    }
226                })?)
227            }
228            Some(BuiltinTypeId::I64) => engine.heap.alloc_i64(value),
229            Some(BuiltinTypeId::U8) => {
230                engine
231                    .heap
232                    .alloc_u8(u8::try_from(value).map_err(|_| EngineError::NativeType {
233                        expected: "u8".into(),
234                        got: value.to_string(),
235                    })?)
236            }
237            Some(BuiltinTypeId::U16) => {
238                engine.heap.alloc_u16(u16::try_from(value).map_err(|_| {
239                    EngineError::NativeType {
240                        expected: "u16".into(),
241                        got: value.to_string(),
242                    }
243                })?)
244            }
245            Some(BuiltinTypeId::U32) => {
246                engine.heap.alloc_u32(u32::try_from(value).map_err(|_| {
247                    EngineError::NativeType {
248                        expected: "u32".into(),
249                        got: value.to_string(),
250                    }
251                })?)
252            }
253            Some(BuiltinTypeId::U64) => {
254                engine.heap.alloc_u64(u64::try_from(value).map_err(|_| {
255                    EngineError::NativeType {
256                        expected: "u64".into(),
257                        got: value.to_string(),
258                    }
259                })?)
260            }
261            _ => Err(EngineError::NativeType {
262                expected: "integral".into(),
263                got: typ.to_string(),
264            }),
265        },
266        _ => Err(EngineError::NativeType {
267            expected: "integral".into(),
268            got: typ.to_string(),
269        }),
270    }
271}
272
273pub(crate) fn type_head_is_var(typ: &Type) -> bool {
274    let mut cur = typ;
275    while let TypeKind::App(head, _) = cur.as_ref() {
276        cur = head;
277    }
278    matches!(cur.as_ref(), TypeKind::Var(..))
279}
280
281fn sanitize_type_name_for_symbol(typ: &Type) -> String {
282    typ.to_string()
283        .chars()
284        .map(|ch| if ch.is_ascii_alphanumeric() { ch } else { '_' })
285        .collect()
286}
287
288pub type NativeFuture<'a> = BoxFuture<'a, Result<Pointer, EngineError>>;
289type NativeId = u64;
290pub(crate) const RUNTIME_LINK_ABI_VERSION: u32 = 1;
291pub type SyncNativeCallable<State> = Arc<
292    dyn for<'a> Fn(EvaluatorRef<'a, State>, &'a Type, &'a [Pointer]) -> Result<Pointer, EngineError>
293        + Send
294        + Sync
295        + 'static,
296>;
297pub type AsyncNativeCallable<State> = Arc<
298    dyn for<'a> Fn(EvaluatorRef<'a, State>, Type, &'a [Pointer]) -> NativeFuture<'a>
299        + Send
300        + Sync
301        + 'static,
302>;
303pub type AsyncNativeCallableCancellable<State> = Arc<
304    dyn for<'a> Fn(
305            EvaluatorRef<'a, State>,
306            CancellationToken,
307            Type,
308            &'a [Pointer],
309        ) -> NativeFuture<'a>
310        + Send
311        + Sync
312        + 'static,
313>;
314
315type ExportInjector<State> =
316    Box<dyn FnOnce(&mut Engine<State>, &str) -> Result<(), EngineError> + Send + 'static>;
317
318struct NativeRegistration<State: Clone + Send + Sync + 'static> {
319    scheme: Scheme,
320    arity: usize,
321    callable: NativeCallable<State>,
322    gas_cost: u64,
323}
324
325impl<State: Clone + Send + Sync + 'static> NativeRegistration<State> {
326    fn sync(scheme: Scheme, arity: usize, func: SyncNativeCallable<State>, gas_cost: u64) -> Self {
327        Self {
328            scheme,
329            arity,
330            callable: NativeCallable::Sync(func),
331            gas_cost,
332        }
333    }
334
335    fn r#async(
336        scheme: Scheme,
337        arity: usize,
338        func: AsyncNativeCallable<State>,
339        gas_cost: u64,
340    ) -> Self {
341        Self {
342            scheme,
343            arity,
344            callable: NativeCallable::Async(func),
345            gas_cost,
346        }
347    }
348
349    fn async_cancellable(
350        scheme: Scheme,
351        arity: usize,
352        func: AsyncNativeCallableCancellable<State>,
353        gas_cost: u64,
354    ) -> Self {
355        Self {
356            scheme,
357            arity,
358            callable: NativeCallable::AsyncCancellable(func),
359            gas_cost,
360        }
361    }
362}
363
364pub trait Handler<State: Clone + Send + Sync + 'static, Sig>: Send + Sync + 'static {
365    fn interface_decl(export_name: &str) -> DeclareFnDecl;
366    fn interface_decl_for(&self, export_name: &str) -> DeclareFnDecl {
367        Self::interface_decl(export_name)
368    }
369    fn inject(self, engine: &mut Engine<State>, export_name: &str) -> Result<(), EngineError>;
370}
371
372pub trait AsyncHandler<State: Clone + Send + Sync + 'static, Sig>: Send + Sync + 'static {
373    fn interface_decl(export_name: &str) -> DeclareFnDecl;
374    fn interface_decl_for(&self, export_name: &str) -> DeclareFnDecl {
375        Self::interface_decl(export_name)
376    }
377    fn inject_async(self, engine: &mut Engine<State>, export_name: &str)
378    -> Result<(), EngineError>;
379}
380
381#[derive(Debug, Clone, Copy)]
382struct NativeCallableSig;
383
384#[derive(Debug, Clone, Copy)]
385struct AsyncNativeCallableSig;
386
387pub struct Export<State: Clone + Send + Sync + 'static> {
388    pub name: String,
389    interface: DeclareFnDecl,
390    injector: ExportInjector<State>,
391}
392
393impl<State> Export<State>
394where
395    State: Clone + Send + Sync + 'static,
396{
397    fn from_injector(
398        name: impl Into<String>,
399        interface: DeclareFnDecl,
400        injector: ExportInjector<State>,
401    ) -> Result<Self, EngineError> {
402        let name = name.into();
403        if name.trim().is_empty() {
404            return Err(EngineError::Internal("export name cannot be empty".into()));
405        }
406        let normalized = normalize_name(&name).to_string();
407        Ok(Self {
408            name: normalized,
409            interface,
410            injector,
411        })
412    }
413
414    pub fn from_handler<Sig, H>(name: impl Into<String>, handler: H) -> Result<Self, EngineError>
415    where
416        H: Handler<State, Sig>,
417    {
418        let name = name.into();
419        let normalized = normalize_name(&name).to_string();
420        let interface = handler.interface_decl_for(&normalized);
421        let injector: ExportInjector<State> =
422            Box::new(move |engine, qualified_name| handler.inject(engine, qualified_name));
423        Self::from_injector(name, interface, injector)
424    }
425
426    pub fn from_async_handler<Sig, H>(
427        name: impl Into<String>,
428        handler: H,
429    ) -> Result<Self, EngineError>
430    where
431        H: AsyncHandler<State, Sig>,
432    {
433        let name = name.into();
434        let normalized = normalize_name(&name).to_string();
435        let interface = handler.interface_decl_for(&normalized);
436        let injector: ExportInjector<State> =
437            Box::new(move |engine, qualified_name| handler.inject_async(engine, qualified_name));
438        Self::from_injector(name, interface, injector)
439    }
440
441    pub fn from_native<F>(
442        name: impl Into<String>,
443        scheme: Scheme,
444        arity: usize,
445        handler: F,
446    ) -> Result<Self, EngineError>
447    where
448        F: for<'a> Fn(
449                EvaluatorRef<'a, State>,
450                &'a Type,
451                &'a [Pointer],
452            ) -> Result<Pointer, EngineError>
453            + Send
454            + Sync
455            + 'static,
456    {
457        Self::from_native_with_gas_cost(name, scheme, arity, 0, handler)
458    }
459
460    pub fn from_native_with_gas_cost<F>(
461        name: impl Into<String>,
462        scheme: Scheme,
463        arity: usize,
464        gas_cost: u64,
465        handler: F,
466    ) -> Result<Self, EngineError>
467    where
468        F: for<'a> Fn(
469                EvaluatorRef<'a, State>,
470                &'a Type,
471                &'a [Pointer],
472            ) -> Result<Pointer, EngineError>
473            + Send
474            + Sync
475            + 'static,
476    {
477        validate_native_export_scheme(&scheme, arity)?;
478        let name = name.into();
479        let normalized = normalize_name(&name).to_string();
480        let interface = declare_fn_decl_from_scheme(&normalized, &scheme);
481        let handler = Arc::new(handler);
482        let injector: ExportInjector<State> = Box::new(move |engine, qualified_name| {
483            let handler = Arc::clone(&handler);
484            let func: SyncNativeCallable<State> =
485                Arc::new(move |engine, typ: &Type, args: &[Pointer]| handler(engine, typ, args));
486            let registration = NativeRegistration::sync(scheme.clone(), arity, func, gas_cost);
487            engine.register_native_registration(ROOT_LIBRARY_NAME, qualified_name, registration)
488        });
489        Self::from_injector(name, interface, injector)
490    }
491
492    pub fn from_native_async<F>(
493        name: impl Into<String>,
494        scheme: Scheme,
495        arity: usize,
496        handler: F,
497    ) -> Result<Self, EngineError>
498    where
499        F: for<'a> Fn(EvaluatorRef<'a, State>, Type, Vec<Pointer>) -> NativeFuture<'a>
500            + Send
501            + Sync
502            + 'static,
503    {
504        Self::from_native_async_with_gas_cost(name, scheme, arity, 0, handler)
505    }
506
507    pub fn from_native_async_with_gas_cost<F>(
508        name: impl Into<String>,
509        scheme: Scheme,
510        arity: usize,
511        gas_cost: u64,
512        handler: F,
513    ) -> Result<Self, EngineError>
514    where
515        F: for<'a> Fn(EvaluatorRef<'a, State>, Type, Vec<Pointer>) -> NativeFuture<'a>
516            + Send
517            + Sync
518            + 'static,
519    {
520        validate_native_export_scheme(&scheme, arity)?;
521        let name = name.into();
522        let normalized = normalize_name(&name).to_string();
523        let interface = declare_fn_decl_from_scheme(&normalized, &scheme);
524        let handler = Arc::new(handler);
525        let injector: ExportInjector<State> = Box::new(move |engine, qualified_name| {
526            let handler = Arc::clone(&handler);
527            let func: AsyncNativeCallable<State> = Arc::new(move |engine, typ, args| {
528                let args = args.to_vec();
529                let handler = Arc::clone(&handler);
530                handler(engine, typ, args)
531            });
532            let registration = NativeRegistration::r#async(scheme.clone(), arity, func, gas_cost);
533            engine.register_native_registration(ROOT_LIBRARY_NAME, qualified_name, registration)
534        });
535        Self::from_injector(name, interface, injector)
536    }
537
538    pub fn from_native_async_cancellable_with_gas_cost<F>(
539        name: impl Into<String>,
540        scheme: Scheme,
541        arity: usize,
542        gas_cost: u64,
543        handler: F,
544    ) -> Result<Self, EngineError>
545    where
546        F: for<'a> Fn(
547                EvaluatorRef<'a, State>,
548                CancellationToken,
549                Type,
550                &'a [Pointer],
551            ) -> NativeFuture<'a>
552            + Send
553            + Sync
554            + 'static,
555    {
556        validate_native_export_scheme(&scheme, arity)?;
557        let name = name.into();
558        let normalized = normalize_name(&name).to_string();
559        let interface = declare_fn_decl_from_scheme(&normalized, &scheme);
560        let handler = Arc::new(handler);
561        let injector: ExportInjector<State> = Box::new(move |engine, qualified_name| {
562            let handler = Arc::clone(&handler);
563            let func: AsyncNativeCallableCancellable<State> =
564                Arc::new(move |engine, token, typ, args| handler(engine, token, typ, args));
565            let registration =
566                NativeRegistration::async_cancellable(scheme.clone(), arity, func, gas_cost);
567            engine.register_native_registration(ROOT_LIBRARY_NAME, qualified_name, registration)
568        });
569        Self::from_injector(name, interface, injector)
570    }
571
572    pub fn from_value<V>(name: impl Into<String>, value: V) -> Result<Self, EngineError>
573    where
574        V: IntoPointer + RexType + Clone + Send + Sync + 'static,
575    {
576        let name = name.into();
577        let typ = V::rex_type();
578        let interface = declare_fn_decl_from_scheme(
579            normalize_name(&name).as_ref(),
580            &Scheme::new(vec![], vec![], typ.clone()),
581        );
582        let name = interface.name.name.to_string();
583        let injector: ExportInjector<State> = Box::new(move |engine, qualified_name| {
584            let stored = value.clone();
585            let func: SyncNativeCallable<State> =
586                Arc::new(move |engine, _: &Type, _args: &[Pointer]| {
587                    stored.clone().into_pointer(&engine.heap)
588                });
589            let registration =
590                NativeRegistration::sync(Scheme::new(vec![], vec![], typ.clone()), 0, func, 0);
591            engine.register_native_registration(ROOT_LIBRARY_NAME, qualified_name, registration)
592        });
593        Self::from_injector(name, interface, injector)
594    }
595
596    pub fn from_value_typed(
597        name: impl Into<String>,
598        typ: Type,
599        value: Value,
600    ) -> Result<Self, EngineError> {
601        let name = name.into();
602        let interface = declare_fn_decl_from_scheme(
603            normalize_name(&name).as_ref(),
604            &Scheme::new(vec![], vec![], typ.clone()),
605        );
606        let name = interface.name.name.to_string();
607        let injector: ExportInjector<State> = Box::new(move |engine, qualified_name| {
608            let stored = value.clone();
609            let func: SyncNativeCallable<State> =
610                Arc::new(move |engine, _: &Type, _args: &[Pointer]| {
611                    engine.heap.alloc_value(stored.clone())
612                });
613            let registration =
614                NativeRegistration::sync(Scheme::new(vec![], vec![], typ.clone()), 0, func, 0);
615            engine.register_native_registration(ROOT_LIBRARY_NAME, qualified_name, registration)
616        });
617        Self::from_injector(name, interface, injector)
618    }
619}
620
621fn declare_fn_decl_from_scheme(export_name: &str, scheme: &Scheme) -> DeclareFnDecl {
622    let (params, ret) = decompose_fun_type(&scheme.typ);
623    DeclareFnDecl {
624        span: Span::default(),
625        is_pub: true,
626        name: Var {
627            span: Span::default(),
628            name: intern(export_name),
629        },
630        params: params
631            .into_iter()
632            .enumerate()
633            .map(|(idx, ty)| {
634                (
635                    Var {
636                        span: Span::default(),
637                        name: intern(&format!("arg{idx}")),
638                    },
639                    type_expr_from_type(&ty),
640                )
641            })
642            .collect(),
643        ret: type_expr_from_type(&ret),
644        constraints: scheme
645            .preds
646            .iter()
647            .map(|pred| TypeConstraint {
648                class: NameRef::Unqualified(pred.class.clone()),
649                typ: type_expr_from_type(&pred.typ),
650            })
651            .collect(),
652    }
653}
654
655fn render_type_decl(decl: &TypeDecl) -> String {
656    let head = if decl.params.is_empty() {
657        decl.name.to_string()
658    } else {
659        format!(
660            "{} {}",
661            decl.name,
662            decl.params
663                .iter()
664                .map(ToString::to_string)
665                .collect::<Vec<_>>()
666                .join(" ")
667        )
668    };
669    let variants = decl
670        .variants
671        .iter()
672        .map(|variant| {
673            if variant.args.is_empty() {
674                variant.name.to_string()
675            } else {
676                format!(
677                    "{} {}",
678                    variant.name,
679                    variant
680                        .args
681                        .iter()
682                        .map(|arg| if matches!(arg, TypeExpr::Fun(..)) {
683                            format!("({arg})")
684                        } else {
685                            arg.to_string()
686                        })
687                        .collect::<Vec<_>>()
688                        .join(" ")
689                )
690            }
691        })
692        .collect::<Vec<_>>()
693        .join(" | ");
694    format!("pub type {head} = {variants}")
695}
696
697fn render_declare_fn_decl(decl: &DeclareFnDecl) -> String {
698    let mut sig = decl.ret.clone();
699    for (_, ann) in decl.params.iter().rev() {
700        sig = TypeExpr::Fun(Span::default(), Box::new(ann.clone()), Box::new(sig));
701    }
702    let mut out = format!("pub declare fn {} : {}", decl.name.name, sig);
703    if !decl.constraints.is_empty() {
704        let preds = decl
705            .constraints
706            .iter()
707            .map(|pred| format!("{} {}", pred.class, pred.typ))
708            .collect::<Vec<_>>()
709            .join(", ");
710        out.push_str(" where ");
711        out.push_str(&preds);
712    }
713    out
714}
715
716fn render_virtual_decl(decl: &Decl) -> Option<String> {
717    match decl {
718        Decl::Type(td) => Some(render_type_decl(td)),
719        Decl::DeclareFn(df) => Some(render_declare_fn_decl(df)),
720        _ => None,
721    }
722}
723
724fn decompose_fun_type(typ: &Type) -> (Vec<Type>, Type) {
725    let mut params = Vec::new();
726    let mut cur = typ.clone();
727    while let Some((arg, ret)) = split_fun(&cur) {
728        params.push(arg);
729        cur = ret;
730    }
731    (params, cur)
732}
733
734fn type_expr_from_type(typ: &Type) -> TypeExpr {
735    match typ.as_ref() {
736        TypeKind::Var(tv) => {
737            let name = tv
738                .name
739                .clone()
740                .unwrap_or_else(|| intern(&format!("t{}", tv.id)));
741            TypeExpr::Name(Span::default(), NameRef::Unqualified(name))
742        }
743        TypeKind::Con(con) => {
744            TypeExpr::Name(Span::default(), NameRef::Unqualified(con.name.clone()))
745        }
746        TypeKind::App(fun, arg) => {
747            if let TypeKind::App(head, err) = fun.as_ref()
748                && let TypeKind::Con(con) = head.as_ref()
749                && con.builtin_id == Some(BuiltinTypeId::Result)
750                && con.arity == 2
751            {
752                let result =
753                    TypeExpr::Name(Span::default(), NameRef::Unqualified(con.name.clone()));
754                let ok_expr = type_expr_from_type(arg);
755                let err_expr = type_expr_from_type(err);
756                let app1 = TypeExpr::App(Span::default(), Box::new(result), Box::new(ok_expr));
757                return TypeExpr::App(Span::default(), Box::new(app1), Box::new(err_expr));
758            }
759            TypeExpr::App(
760                Span::default(),
761                Box::new(type_expr_from_type(fun)),
762                Box::new(type_expr_from_type(arg)),
763            )
764        }
765        TypeKind::Fun(arg, ret) => TypeExpr::Fun(
766            Span::default(),
767            Box::new(type_expr_from_type(arg)),
768            Box::new(type_expr_from_type(ret)),
769        ),
770        TypeKind::Tuple(elems) => TypeExpr::Tuple(
771            Span::default(),
772            elems.iter().map(type_expr_from_type).collect(),
773        ),
774        TypeKind::Record(fields) => TypeExpr::Record(
775            Span::default(),
776            fields
777                .iter()
778                .map(|(name, ty)| (name.clone(), type_expr_from_type(ty)))
779                .collect(),
780        ),
781    }
782}
783
784fn library_local_type_names_from_declarations(declarations: &[String]) -> HashSet<Symbol> {
785    let mut out = HashSet::new();
786    for declaration in declarations {
787        let mut s = declaration.trim_start();
788        if let Some(rest) = s.strip_prefix("pub ") {
789            s = rest.trim_start();
790        }
791        let Some(rest) = s.strip_prefix("type ") else {
792            continue;
793        };
794        let name: String = rest
795            .chars()
796            .take_while(|c| c.is_ascii_alphanumeric() || *c == '_')
797            .collect();
798        if !name.is_empty() {
799            out.insert(sym(&name));
800        }
801    }
802    out
803}
804
805fn library_local_type_names_from_decls(decls: &[Decl]) -> HashSet<Symbol> {
806    let mut out = HashSet::new();
807    for decl in decls {
808        if let Decl::Type(td) = decl {
809            out.insert(td.name.clone());
810        }
811    }
812    out
813}
814
815fn render_virtual_module_source(decls: &[Decl]) -> Option<String> {
816    let rendered = decls
817        .iter()
818        .filter_map(render_virtual_decl)
819        .collect::<Vec<_>>()
820        .join("\n");
821    (!rendered.is_empty()).then_some(rendered)
822}
823
824fn build_virtual_library_source<State: Clone + Send + Sync + 'static>(
825    declarations: &[String],
826    exports: &[Export<State>],
827) -> String {
828    let mut lines = declarations.to_vec();
829    lines.extend(
830        exports
831            .iter()
832            .map(|export| render_declare_fn_decl(&export.interface)),
833    );
834    lines.join("\n")
835}
836
837fn qualify_library_type_refs(
838    typ: &Type,
839    library_name: &str,
840    local_type_names: &HashSet<Symbol>,
841) -> Type {
842    match typ.as_ref() {
843        TypeKind::Con(tc) => {
844            if local_type_names.contains(&tc.name) {
845                Type::con(
846                    virtual_export_name(library_name, tc.name.as_ref()),
847                    tc.arity,
848                )
849            } else {
850                typ.clone()
851            }
852        }
853        TypeKind::App(f, x) => Type::app(
854            qualify_library_type_refs(f, library_name, local_type_names),
855            qualify_library_type_refs(x, library_name, local_type_names),
856        ),
857        TypeKind::Fun(a, b) => Type::fun(
858            qualify_library_type_refs(a, library_name, local_type_names),
859            qualify_library_type_refs(b, library_name, local_type_names),
860        ),
861        TypeKind::Tuple(elems) => Type::tuple(
862            elems
863                .iter()
864                .map(|t| qualify_library_type_refs(t, library_name, local_type_names))
865                .collect(),
866        ),
867        TypeKind::Record(fields) => Type::new(TypeKind::Record(
868            fields
869                .iter()
870                .map(|(k, v)| {
871                    (
872                        k.clone(),
873                        qualify_library_type_refs(v, library_name, local_type_names),
874                    )
875                })
876                .collect(),
877        )),
878        TypeKind::Var(_) => typ.clone(),
879    }
880}
881
882fn qualify_library_scheme_refs(
883    scheme: &Scheme,
884    library_name: &str,
885    local_type_names: &HashSet<Symbol>,
886) -> Scheme {
887    let typ = qualify_library_type_refs(&scheme.typ, library_name, local_type_names);
888    let preds = scheme
889        .preds
890        .iter()
891        .map(|pred| {
892            Predicate::new(
893                pred.class.clone(),
894                qualify_library_type_refs(&pred.typ, library_name, local_type_names),
895            )
896        })
897        .collect();
898    Scheme::new(scheme.vars.clone(), preds, typ)
899}
900
901/// Convert ADT collection conflicts into an embedder-facing `EngineError`.
902///
903/// # Examples
904///
905/// ```rust,ignore
906/// use rex_engine::collect_adts_error_to_engine;
907/// use rexlang_typesystem::{collect_adts_in_types, Type};
908///
909/// let err = collect_adts_in_types(vec![
910///     Type::user_con("Thing", 1),
911///     Type::user_con("Thing", 2),
912/// ])
913/// .unwrap_err();
914///
915/// let engine_err = collect_adts_error_to_engine(err);
916/// assert!(engine_err.to_string().contains("conflicting ADT definitions"));
917/// ```
918pub fn collect_adts_error_to_engine(err: CollectAdtsError) -> EngineError {
919    let details = err
920        .conflicts
921        .into_iter()
922        .map(|conflict| {
923            let defs = conflict
924                .definitions
925                .iter()
926                .map(ToString::to_string)
927                .collect::<Vec<_>>()
928                .join(", ");
929            format!("{}: [{defs}]", conflict.name)
930        })
931        .collect::<Vec<_>>()
932        .join("; ");
933    EngineError::Custom(format!(
934        "conflicting ADT definitions discovered in input types: {details}"
935    ))
936}
937
938fn native_export_arg_types(
939    scheme: &Scheme,
940    arity: usize,
941) -> Result<(Vec<Type>, Type), EngineError> {
942    let mut args = Vec::with_capacity(arity);
943    let mut rest = scheme.typ.clone();
944    for _ in 0..arity {
945        let Some((arg, tail)) = split_fun(&rest) else {
946            return Err(EngineError::Internal(format!(
947                "native export type `{}` does not accept {arity} argument(s)",
948                scheme.typ
949            )));
950        };
951        args.push(arg);
952        rest = tail;
953    }
954    Ok((args, rest))
955}
956
957fn validate_native_export_scheme(scheme: &Scheme, arity: usize) -> Result<(), EngineError> {
958    let _ = native_export_arg_types(scheme, arity)?;
959    Ok(())
960}
961
962macro_rules! define_handler_impl {
963    ([] ; $arity:literal ; $sig:ty) => {
964        impl<State, F, R> Handler<State, $sig> for F
965        where
966            State: Clone + Send + Sync + 'static,
967            F: for<'a> Fn(&'a State) -> Result<R, EngineError> + Send + Sync + 'static,
968            R: IntoPointer + RexType,
969        {
970            fn interface_decl(export_name: &str) -> DeclareFnDecl {
971                let scheme = Scheme::new(vec![], vec![], R::rex_type());
972                declare_fn_decl_from_scheme(export_name, &scheme)
973            }
974
975            fn inject(
976                self,
977                engine: &mut Engine<State>,
978                export_name: &str,
979            ) -> Result<(), EngineError> {
980                let name_sym = normalize_name(export_name);
981                let func: SyncNativeCallable<State> = Arc::new(
982                    move |engine, _: &Type, args: &[Pointer]| {
983                        if args.len() != $arity {
984                            return Err(EngineError::NativeArity {
985                                name: name_sym.clone(),
986                                expected: $arity,
987                                got: args.len(),
988                            });
989                        }
990                        let value = self(engine.state.as_ref())?;
991                        value.into_pointer(&engine.heap)
992                    },
993                );
994                let scheme = Scheme::new(vec![], vec![], R::rex_type());
995                let registration = NativeRegistration::sync(scheme, $arity, func, 0);
996                engine.register_native_registration(ROOT_LIBRARY_NAME, export_name, registration)
997            }
998        }
999
1000    };
1001    ([ $(($arg_ty:ident, $arg_name:ident, $idx:tt)),+ ] ; $arity:literal ; $sig:ty) => {
1002        impl<State, F, R, $($arg_ty),+> Handler<State, $sig> for F
1003        where
1004            State: Clone + Send + Sync + 'static,
1005            F: for<'a> Fn(&'a State, $($arg_ty),+) -> Result<R, EngineError> + Send + Sync + 'static,
1006            R: IntoPointer + RexType,
1007            $($arg_ty: FromPointer + RexType),+
1008        {
1009            fn interface_decl(export_name: &str) -> DeclareFnDecl {
1010                let typ = native_fn_type!($($arg_ty),+ ; R);
1011                let scheme = Scheme::new(vec![], vec![], typ);
1012                declare_fn_decl_from_scheme(export_name, &scheme)
1013            }
1014
1015            fn inject(
1016                self,
1017                engine: &mut Engine<State>,
1018                export_name: &str,
1019            ) -> Result<(), EngineError> {
1020                let name_sym = normalize_name(export_name);
1021                let func: SyncNativeCallable<State> = Arc::new(
1022                    move |engine, _: &Type, args: &[Pointer]| {
1023                        if args.len() != $arity {
1024                            return Err(EngineError::NativeArity {
1025                                name: name_sym.clone(),
1026                                expected: $arity,
1027                                got: args.len(),
1028                            });
1029                        }
1030                        $(let $arg_name = $arg_ty::from_pointer(&engine.heap, &args[$idx])?;)*
1031                        let value = self(engine.state.as_ref(), $($arg_name),+)?;
1032                        value.into_pointer(&engine.heap)
1033                    },
1034                );
1035                let typ = native_fn_type!($($arg_ty),+ ; R);
1036                let scheme = Scheme::new(vec![], vec![], typ);
1037                let registration = NativeRegistration::sync(scheme, $arity, func, 0);
1038                engine.register_native_registration(ROOT_LIBRARY_NAME, export_name, registration)
1039            }
1040        }
1041
1042    };
1043}
1044
1045impl<State> Handler<State, NativeCallableSig> for (Scheme, usize, SyncNativeCallable<State>)
1046where
1047    State: Clone + Send + Sync + 'static,
1048{
1049    fn interface_decl(_export_name: &str) -> DeclareFnDecl {
1050        unreachable!("native callable handlers use interface_decl_for")
1051    }
1052
1053    fn interface_decl_for(&self, export_name: &str) -> DeclareFnDecl {
1054        let (scheme, _, _) = self;
1055        declare_fn_decl_from_scheme(export_name, scheme)
1056    }
1057
1058    fn inject(self, engine: &mut Engine<State>, export_name: &str) -> Result<(), EngineError> {
1059        let (scheme, arity, func) = self;
1060        validate_native_export_scheme(&scheme, arity)?;
1061        let registration = NativeRegistration::sync(scheme, arity, func, 0);
1062        engine.register_native_registration(ROOT_LIBRARY_NAME, export_name, registration)
1063    }
1064}
1065
1066macro_rules! define_async_handler_impl {
1067    ([] ; $arity:literal ; $sig:ty) => {
1068        impl<State, F, Fut, R> AsyncHandler<State, $sig> for F
1069        where
1070            State: Clone + Send + Sync + 'static,
1071            F: for<'a> Fn(&'a State) -> Fut + Send + Sync + 'static,
1072            Fut: Future<Output = Result<R, EngineError>> + Send + 'static,
1073            R: IntoPointer + RexType,
1074        {
1075            fn interface_decl(export_name: &str) -> DeclareFnDecl {
1076                let scheme = Scheme::new(vec![], vec![], R::rex_type());
1077                declare_fn_decl_from_scheme(export_name, &scheme)
1078            }
1079
1080            fn inject_async(
1081                self,
1082                engine: &mut Engine<State>,
1083                export_name: &str,
1084            ) -> Result<(), EngineError> {
1085                let f = Arc::new(self);
1086                let name_sym = normalize_name(export_name);
1087                let func: AsyncNativeCallable<State> = Arc::new(
1088                    move |engine, _: Type, args: &[Pointer]| -> NativeFuture<'_> {
1089                        let f = Arc::clone(&f);
1090                        let name_sym = name_sym.clone();
1091                        async move {
1092                            if args.len() != $arity {
1093                                return Err(EngineError::NativeArity {
1094                                    name: name_sym.clone(),
1095                                    expected: $arity,
1096                                    got: args.len(),
1097                                });
1098                            }
1099                            let value = f(engine.state.as_ref()).await?;
1100                            value.into_pointer(&engine.heap)
1101                        }
1102                        .boxed()
1103                    },
1104                );
1105                let scheme = Scheme::new(vec![], vec![], R::rex_type());
1106                let registration = NativeRegistration::r#async(scheme, $arity, func, 0);
1107                engine.register_native_registration(ROOT_LIBRARY_NAME, export_name, registration)
1108            }
1109        }
1110    };
1111    ([ $(($arg_ty:ident, $arg_name:ident, $idx:tt)),+ ] ; $arity:literal ; $sig:ty) => {
1112        impl<State, F, Fut, R, $($arg_ty),+> AsyncHandler<State, $sig> for F
1113        where
1114            State: Clone + Send + Sync + 'static,
1115            F: for<'a> Fn(&'a State, $($arg_ty),+) -> Fut + Send + Sync + 'static,
1116            Fut: Future<Output = Result<R, EngineError>> + Send + 'static,
1117            R: IntoPointer + RexType,
1118            $($arg_ty: FromPointer + RexType),+
1119        {
1120            fn interface_decl(export_name: &str) -> DeclareFnDecl {
1121                let typ = native_fn_type!($($arg_ty),+ ; R);
1122                let scheme = Scheme::new(vec![], vec![], typ);
1123                declare_fn_decl_from_scheme(export_name, &scheme)
1124            }
1125
1126            fn inject_async(
1127                self,
1128                engine: &mut Engine<State>,
1129                export_name: &str,
1130            ) -> Result<(), EngineError> {
1131                let f = Arc::new(self);
1132                let name_sym = normalize_name(export_name);
1133                let func: AsyncNativeCallable<State> = Arc::new(
1134                    move |engine, _: Type, args: &[Pointer]| -> NativeFuture<'_> {
1135                        let f = Arc::clone(&f);
1136                        let name_sym = name_sym.clone();
1137                        async move {
1138                            if args.len() != $arity {
1139                                return Err(EngineError::NativeArity {
1140                                    name: name_sym.clone(),
1141                                    expected: $arity,
1142                                    got: args.len(),
1143                                });
1144                            }
1145                            $(let $arg_name = $arg_ty::from_pointer(&engine.heap, &args[$idx])?;)*
1146                            let value = f(engine.state.as_ref(), $($arg_name),+).await?;
1147                            value.into_pointer(&engine.heap)
1148                        }
1149                        .boxed()
1150                    },
1151                );
1152                let typ = native_fn_type!($($arg_ty),+ ; R);
1153                let scheme = Scheme::new(vec![], vec![], typ);
1154                let registration = NativeRegistration::r#async(scheme, $arity, func, 0);
1155                engine.register_native_registration(ROOT_LIBRARY_NAME, export_name, registration)
1156            }
1157        }
1158    };
1159}
1160
1161impl<State> AsyncHandler<State, AsyncNativeCallableSig>
1162    for (Scheme, usize, AsyncNativeCallable<State>)
1163where
1164    State: Clone + Send + Sync + 'static,
1165{
1166    fn interface_decl(_export_name: &str) -> DeclareFnDecl {
1167        unreachable!("native async callable handlers use interface_decl_for")
1168    }
1169
1170    fn interface_decl_for(&self, export_name: &str) -> DeclareFnDecl {
1171        let (scheme, _, _) = self;
1172        declare_fn_decl_from_scheme(export_name, scheme)
1173    }
1174
1175    fn inject_async(
1176        self,
1177        engine: &mut Engine<State>,
1178        export_name: &str,
1179    ) -> Result<(), EngineError> {
1180        let (scheme, arity, func) = self;
1181        validate_native_export_scheme(&scheme, arity)?;
1182        let registration = NativeRegistration::r#async(scheme, arity, func, 0);
1183        engine.register_native_registration(ROOT_LIBRARY_NAME, export_name, registration)
1184    }
1185}
1186
1187#[derive(Clone)]
1188pub(crate) enum NativeCallable<State: Clone + Send + Sync + 'static> {
1189    Sync(SyncNativeCallable<State>),
1190    Async(AsyncNativeCallable<State>),
1191    AsyncCancellable(AsyncNativeCallableCancellable<State>),
1192}
1193
1194impl<State: Clone + Send + Sync + 'static> PartialEq for NativeCallable<State> {
1195    fn eq(&self, _other: &NativeCallable<State>) -> bool {
1196        false
1197    }
1198}
1199
1200impl<State: Clone + Send + Sync + 'static> std::fmt::Debug for NativeCallable<State> {
1201    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
1202        match self {
1203            NativeCallable::Sync(_) => write!(f, "Sync"),
1204            NativeCallable::Async(_) => write!(f, "Async"),
1205            NativeCallable::AsyncCancellable(_) => write!(f, "AsyncCancellable"),
1206        }
1207    }
1208}
1209
1210impl<State: Clone + Send + Sync + 'static> NativeCallable<State> {
1211    pub(crate) async fn call(
1212        &self,
1213        runtime: &RuntimeSnapshot<State>,
1214        typ: Type,
1215        args: &[Pointer],
1216    ) -> Result<Pointer, EngineError> {
1217        let token = runtime.cancel.clone();
1218        if token.is_cancelled() {
1219            return Err(EngineError::Cancelled);
1220        }
1221
1222        match self {
1223            NativeCallable::Sync(f) => (f)(EvaluatorRef::new(runtime), &typ, args),
1224            NativeCallable::Async(f) => {
1225                let call_fut = (f)(EvaluatorRef::new(runtime), typ, args).fuse();
1226                let cancel_fut = token.cancelled().fuse();
1227                pin_mut!(call_fut, cancel_fut);
1228                futures::select! {
1229                    _ = cancel_fut => Err(EngineError::Cancelled),
1230                    res = call_fut => {
1231                        if token.is_cancelled() {
1232                            Err(EngineError::Cancelled)
1233                        } else {
1234                            res
1235                        }
1236                    },
1237                }
1238            }
1239            NativeCallable::AsyncCancellable(f) => {
1240                let call_fut = (f)(EvaluatorRef::new(runtime), token.clone(), typ, args).fuse();
1241                let cancel_fut = token.cancelled().fuse();
1242                pin_mut!(call_fut, cancel_fut);
1243                futures::select! {
1244                    _ = cancel_fut => Err(EngineError::Cancelled),
1245                    res = call_fut => {
1246                        if token.is_cancelled() {
1247                            Err(EngineError::Cancelled)
1248                        } else {
1249                            res
1250                        }
1251                    },
1252                }
1253            }
1254        }
1255    }
1256}
1257
1258#[derive(Clone, Debug, PartialEq)]
1259pub struct NativeFn {
1260    native_id: NativeId,
1261    name: Symbol,
1262    arity: usize,
1263    typ: Type,
1264    gas_cost: u64,
1265    applied: Vec<Pointer>,
1266    applied_types: Vec<Type>,
1267}
1268
1269impl NativeFn {
1270    fn new(native_id: NativeId, name: Symbol, arity: usize, typ: Type, gas_cost: u64) -> Self {
1271        Self {
1272            native_id,
1273            name,
1274            arity,
1275            typ,
1276            gas_cost,
1277            applied: Vec::new(),
1278            applied_types: Vec::new(),
1279        }
1280    }
1281
1282    pub(crate) fn from_parts(
1283        native_id: NativeId,
1284        name: Symbol,
1285        arity: usize,
1286        typ: Type,
1287        gas_cost: u64,
1288        applied: Vec<Pointer>,
1289        applied_types: Vec<Type>,
1290    ) -> Self {
1291        Self {
1292            native_id,
1293            name,
1294            arity,
1295            typ,
1296            gas_cost,
1297            applied,
1298            applied_types,
1299        }
1300    }
1301
1302    pub(crate) fn into_parts(
1303        self,
1304    ) -> (NativeId, Symbol, usize, Type, u64, Vec<Pointer>, Vec<Type>) {
1305        (
1306            self.native_id,
1307            self.name,
1308            self.arity,
1309            self.typ,
1310            self.gas_cost,
1311            self.applied,
1312            self.applied_types,
1313        )
1314    }
1315
1316    pub(crate) fn name(&self) -> &Symbol {
1317        &self.name
1318    }
1319
1320    pub(crate) fn is_zero_unapplied(&self) -> bool {
1321        self.arity == 0 && self.applied.is_empty()
1322    }
1323
1324    pub(crate) async fn call_zero<State: Clone + Send + Sync + 'static>(
1325        &self,
1326        runtime: &RuntimeSnapshot<State>,
1327        gas: &mut GasMeter,
1328    ) -> Result<Pointer, EngineError> {
1329        let amount = gas
1330            .costs
1331            .native_call_base
1332            .saturating_add(self.gas_cost)
1333            .saturating_add(gas.costs.native_call_per_arg.saturating_mul(0));
1334        gas.charge(amount)?;
1335        if self.arity != 0 {
1336            return Err(EngineError::NativeArity {
1337                name: self.name.clone(),
1338                expected: self.arity,
1339                got: 0,
1340            });
1341        }
1342        runtime
1343            .native_callable(self.native_id)?
1344            .call(runtime, self.typ.clone(), &[])
1345            .await
1346    }
1347
1348    async fn apply<State: Clone + Send + Sync + 'static>(
1349        mut self,
1350        runtime: &RuntimeSnapshot<State>,
1351        arg: Pointer,
1352        arg_type: Option<&Type>,
1353        gas: &mut GasMeter,
1354    ) -> Result<Pointer, EngineError> {
1355        // `self` is an owned copy cloned from heap storage; we mutate it to
1356        // accumulate partial-application state and never mutate shared values.
1357        if self.arity == 0 {
1358            return Err(EngineError::NativeArity {
1359                name: self.name,
1360                expected: 0,
1361                got: 1,
1362            });
1363        }
1364        let (arg_ty, rest_ty) =
1365            split_fun(&self.typ).ok_or_else(|| EngineError::NotCallable(self.typ.to_string()))?;
1366        let actual_ty = resolve_arg_type(&runtime.heap, arg_type, &arg)?;
1367        let subst = unify(&arg_ty, &actual_ty).map_err(|_| EngineError::NativeType {
1368            expected: arg_ty.to_string(),
1369            got: actual_ty.to_string(),
1370        })?;
1371        self.typ = rest_ty.apply(&subst);
1372        self.applied.push(arg);
1373        self.applied_types.push(actual_ty);
1374        if is_function_type(&self.typ) {
1375            let NativeFn {
1376                native_id,
1377                name,
1378                arity,
1379                typ,
1380                gas_cost,
1381                applied,
1382                applied_types,
1383            } = self;
1384            return runtime.heap.alloc_native(
1385                native_id,
1386                name,
1387                arity,
1388                typ,
1389                gas_cost,
1390                applied,
1391                applied_types,
1392            );
1393        }
1394
1395        let mut full_ty = self.typ.clone();
1396        for arg_ty in self.applied_types.iter().rev() {
1397            full_ty = Type::fun(arg_ty.clone(), full_ty);
1398        }
1399
1400        let amount = gas
1401            .costs
1402            .native_call_base
1403            .saturating_add(self.gas_cost)
1404            .saturating_add(
1405                gas.costs
1406                    .native_call_per_arg
1407                    .saturating_mul(self.applied.len() as u64),
1408            );
1409        gas.charge(amount)?;
1410        runtime
1411            .native_callable(self.native_id)?
1412            .call(runtime, full_ty, &self.applied)
1413            .await
1414    }
1415}
1416
1417#[derive(Clone, Debug, PartialEq)]
1418pub struct OverloadedFn {
1419    name: Symbol,
1420    typ: Type,
1421    applied: Vec<Pointer>,
1422    applied_types: Vec<Type>,
1423}
1424
1425impl OverloadedFn {
1426    pub(crate) fn new(name: Symbol, typ: Type) -> Self {
1427        Self {
1428            name,
1429            typ,
1430            applied: Vec::new(),
1431            applied_types: Vec::new(),
1432        }
1433    }
1434
1435    pub(crate) fn from_parts(
1436        name: Symbol,
1437        typ: Type,
1438        applied: Vec<Pointer>,
1439        applied_types: Vec<Type>,
1440    ) -> Self {
1441        Self {
1442            name,
1443            typ,
1444            applied,
1445            applied_types,
1446        }
1447    }
1448
1449    pub(crate) fn name(&self) -> &Symbol {
1450        &self.name
1451    }
1452
1453    pub(crate) fn into_parts(self) -> (Symbol, Type, Vec<Pointer>, Vec<Type>) {
1454        (self.name, self.typ, self.applied, self.applied_types)
1455    }
1456
1457    async fn apply<State: Clone + Send + Sync + 'static>(
1458        mut self,
1459        runtime: &RuntimeSnapshot<State>,
1460        arg: Pointer,
1461        func_type: Option<&Type>,
1462        arg_type: Option<&Type>,
1463        gas: &mut GasMeter,
1464    ) -> Result<Pointer, EngineError> {
1465        if let Some(expected) = func_type {
1466            let subst = unify(&self.typ, expected).map_err(|_| EngineError::NativeType {
1467                expected: self.typ.to_string(),
1468                got: expected.to_string(),
1469            })?;
1470            self.typ = self.typ.apply(&subst);
1471        }
1472        let (arg_ty, rest_ty) =
1473            split_fun(&self.typ).ok_or_else(|| EngineError::NotCallable(self.typ.to_string()))?;
1474        let actual_ty = resolve_arg_type(&runtime.heap, arg_type, &arg)?;
1475        let subst = unify(&arg_ty, &actual_ty).map_err(|_| EngineError::NativeType {
1476            expected: arg_ty.to_string(),
1477            got: actual_ty.to_string(),
1478        })?;
1479        let rest_ty = rest_ty.apply(&subst);
1480        self.applied.push(arg);
1481        self.applied_types.push(actual_ty);
1482        if is_function_type(&rest_ty) {
1483            return runtime.heap.alloc_overloaded(
1484                self.name,
1485                rest_ty,
1486                self.applied,
1487                self.applied_types,
1488            );
1489        }
1490        let mut full_ty = rest_ty;
1491        for arg_ty in self.applied_types.iter().rev() {
1492            full_ty = Type::fun(arg_ty.clone(), full_ty);
1493        }
1494        if runtime.type_system.class_methods.contains_key(&self.name) {
1495            let mut func = EvaluatorRef::new(runtime)
1496                .resolve_class_method(&self.name, &full_ty, gas)
1497                .await?;
1498            let mut cur_ty = full_ty;
1499            for (applied, applied_ty) in self.applied.into_iter().zip(self.applied_types.iter()) {
1500                let (arg_ty, rest_ty) = split_fun(&cur_ty)
1501                    .ok_or_else(|| EngineError::NotCallable(cur_ty.to_string()))?;
1502                let subst = unify(&arg_ty, applied_ty).map_err(|_| EngineError::NativeType {
1503                    expected: arg_ty.to_string(),
1504                    got: applied_ty.to_string(),
1505                })?;
1506                let rest_ty = rest_ty.apply(&subst);
1507                func = apply(runtime, func, applied, Some(&cur_ty), Some(applied_ty), gas).await?;
1508                cur_ty = rest_ty;
1509            }
1510            return Ok(func);
1511        }
1512
1513        let imp = EvaluatorRef::new(runtime).resolve_native_impl(self.name.as_ref(), &full_ty)?;
1514        let amount = gas
1515            .costs
1516            .native_call_base
1517            .saturating_add(imp.gas_cost)
1518            .saturating_add(
1519                gas.costs
1520                    .native_call_per_arg
1521                    .saturating_mul(self.applied.len() as u64),
1522            );
1523        gas.charge(amount)?;
1524        imp.func.call(runtime, full_ty, &self.applied).await
1525    }
1526}
1527
1528#[derive(Clone)]
1529pub(crate) struct NativeImpl<State: Clone + Send + Sync + 'static> {
1530    id: NativeId,
1531    name: Symbol,
1532    arity: usize,
1533    scheme: Scheme,
1534    pub(crate) func: NativeCallable<State>,
1535    gas_cost: u64,
1536}
1537
1538impl<State: Clone + Send + Sync + 'static> NativeImpl<State> {
1539    pub(crate) fn to_native_fn(&self, typ: Type) -> NativeFn {
1540        NativeFn::new(self.id, self.name.clone(), self.arity, typ, self.gas_cost)
1541    }
1542}
1543
1544#[derive(Clone)]
1545pub(crate) struct NativeRegistry<State: Clone + Send + Sync + 'static> {
1546    next_id: NativeId,
1547    entries: HashMap<Symbol, Vec<NativeImpl<State>>>,
1548    by_id: HashMap<NativeId, NativeImpl<State>>,
1549}
1550
1551impl<State: Clone + Send + Sync + 'static> NativeRegistry<State> {
1552    fn insert(
1553        &mut self,
1554        name: Symbol,
1555        arity: usize,
1556        scheme: Scheme,
1557        func: NativeCallable<State>,
1558        gas_cost: u64,
1559    ) -> Result<(), EngineError> {
1560        let entry = self.entries.entry(name.clone()).or_default();
1561        if entry.iter().any(|existing| existing.scheme == scheme) {
1562            return Err(EngineError::DuplicateImpl {
1563                name,
1564                typ: scheme.typ.to_string(),
1565            });
1566        }
1567        let id = self.next_id;
1568        self.next_id = self.next_id.saturating_add(1);
1569        let imp = NativeImpl::<State> {
1570            id,
1571            name: name.clone(),
1572            arity,
1573            scheme,
1574            func,
1575            gas_cost,
1576        };
1577        self.by_id.insert(id, imp.clone());
1578        entry.push(imp);
1579        Ok(())
1580    }
1581
1582    pub(crate) fn get(&self, name: &Symbol) -> Option<&[NativeImpl<State>]> {
1583        self.entries.get(name).map(|v| v.as_slice())
1584    }
1585
1586    pub(crate) fn has_name(&self, name: &Symbol) -> bool {
1587        self.entries.contains_key(name)
1588    }
1589
1590    fn by_id(&self, id: NativeId) -> Option<&NativeImpl<State>> {
1591        self.by_id.get(&id)
1592    }
1593}
1594
1595impl<State: Clone + Send + Sync + 'static> Default for NativeRegistry<State> {
1596    fn default() -> Self {
1597        Self {
1598            next_id: 0,
1599            entries: HashMap::new(),
1600            by_id: HashMap::new(),
1601        }
1602    }
1603}
1604
1605#[derive(Clone)]
1606pub(crate) struct TypeclassInstance {
1607    head: Type,
1608    def_env: Env,
1609    methods: HashMap<Symbol, Arc<TypedExpr>>,
1610}
1611
1612#[derive(Default, Clone)]
1613pub(crate) struct TypeclassRegistry {
1614    entries: HashMap<Symbol, Vec<TypeclassInstance>>,
1615}
1616
1617impl TypeclassRegistry {
1618    fn insert(
1619        &mut self,
1620        class: Symbol,
1621        head: Type,
1622        def_env: Env,
1623        methods: HashMap<Symbol, Arc<TypedExpr>>,
1624    ) -> Result<(), EngineError> {
1625        let entry = self.entries.entry(class.clone()).or_default();
1626        for existing in entry.iter() {
1627            if unify(&existing.head, &head).is_ok() {
1628                return Err(EngineError::DuplicateTypeclassImpl {
1629                    class,
1630                    typ: head.to_string(),
1631                });
1632            }
1633        }
1634        entry.push(TypeclassInstance {
1635            head,
1636            def_env,
1637            methods,
1638        });
1639        Ok(())
1640    }
1641
1642    pub(crate) fn resolve(
1643        &self,
1644        class: &Symbol,
1645        method: &Symbol,
1646        param_type: &Type,
1647    ) -> Result<(Env, Arc<TypedExpr>, Subst), EngineError> {
1648        let instances =
1649            self.entries
1650                .get(class)
1651                .ok_or_else(|| EngineError::MissingTypeclassImpl {
1652                    class: class.clone(),
1653                    typ: param_type.to_string(),
1654                })?;
1655
1656        let mut matches = Vec::new();
1657        for inst in instances {
1658            if let Ok(s) = unify(&inst.head, param_type) {
1659                matches.push((inst, s));
1660            }
1661        }
1662        match matches.len() {
1663            0 => Err(EngineError::MissingTypeclassImpl {
1664                class: class.clone(),
1665                typ: param_type.to_string(),
1666            }),
1667            1 => {
1668                let (inst, s) = matches.remove(0);
1669                let typed =
1670                    inst.methods
1671                        .get(method)
1672                        .ok_or_else(|| EngineError::MissingTypeclassImpl {
1673                            class: class.clone(),
1674                            typ: param_type.to_string(),
1675                        })?;
1676                Ok((inst.def_env.clone(), typed.clone(), s))
1677            }
1678            _ => Err(EngineError::AmbiguousTypeclassImpl {
1679                class: class.clone(),
1680                typ: param_type.to_string(),
1681            }),
1682        }
1683    }
1684}
1685
1686pub struct Engine<State = ()>
1687where
1688    State: Clone + Send + Sync + 'static,
1689{
1690    pub state: Arc<State>,
1691    env: Env,
1692    natives: NativeRegistry<State>,
1693    typeclasses: TypeclassRegistry,
1694    pub type_system: TypeSystem,
1695    typeclass_cache: Arc<Mutex<HashMap<(Symbol, Type), Pointer>>>,
1696    pub(crate) modules: LibrarySystem,
1697    injected_libraries: HashSet<String>,
1698    pub(crate) library_exports_cache: HashMap<LibraryId, LibraryExports>,
1699    pub(crate) library_interface_cache: HashMap<LibraryId, Vec<Decl>>,
1700    pub(crate) library_sources: HashMap<LibraryId, String>,
1701    pub(crate) library_source_fingerprints: HashMap<LibraryId, String>,
1702    pub(crate) published_cycle_interfaces: HashSet<LibraryId>,
1703    default_imports: Vec<String>,
1704    virtual_libraries: HashMap<String, VirtualLibraryModule>,
1705    library_local_type_names: HashMap<String, HashSet<Symbol>>,
1706    registration_library_context: Option<String>,
1707    cancel: CancellationToken,
1708    pub heap: Heap,
1709}
1710
1711#[derive(Clone)]
1712pub struct CompiledProgram {
1713    pub externs: CompiledExterns,
1714    link_contract: RuntimeLinkContract,
1715    pub(crate) env: Env,
1716    pub(crate) expr: Arc<TypedExpr>,
1717}
1718
1719impl CompiledProgram {
1720    pub(crate) fn new(
1721        externs: CompiledExterns,
1722        link_contract: RuntimeLinkContract,
1723        env: Env,
1724        expr: TypedExpr,
1725    ) -> Self {
1726        Self {
1727            externs,
1728            link_contract,
1729            env,
1730            expr: Arc::new(expr),
1731        }
1732    }
1733
1734    pub fn result_type(&self) -> &Type {
1735        &self.expr.typ
1736    }
1737
1738    pub fn externs(&self) -> &CompiledExterns {
1739        &self.externs
1740    }
1741
1742    pub fn link_contract(&self) -> &RuntimeLinkContract {
1743        &self.link_contract
1744    }
1745
1746    pub fn link_fingerprint(&self) -> u64 {
1747        self.link_contract.fingerprint()
1748    }
1749
1750    pub fn storage_boundary(&self) -> CompiledProgramBoundary {
1751        CompiledProgramBoundary {
1752            contains_prepared_expr: true,
1753            captures_process_local_env: true,
1754            serializable: false,
1755        }
1756    }
1757}
1758
1759#[derive(Clone, Debug, Default, PartialEq, Eq)]
1760pub struct CompiledExterns {
1761    pub natives: Vec<Symbol>,
1762    pub class_methods: Vec<Symbol>,
1763}
1764
1765impl CompiledExterns {
1766    pub fn is_empty(&self) -> bool {
1767        self.natives.is_empty() && self.class_methods.is_empty()
1768    }
1769
1770    pub fn fingerprint(&self) -> u64 {
1771        let mut hasher = std::collections::hash_map::DefaultHasher::new();
1772        "natives".hash(&mut hasher);
1773        self.natives.hash(&mut hasher);
1774        "class_methods".hash(&mut hasher);
1775        self.class_methods.hash(&mut hasher);
1776        hasher.finish()
1777    }
1778
1779    pub fn compatibility_with(&self, capabilities: &RuntimeCapabilities) -> RuntimeCompatibility {
1780        let natives = capabilities.natives.iter().cloned().collect::<HashSet<_>>();
1781        let class_methods = capabilities
1782            .class_methods
1783            .iter()
1784            .cloned()
1785            .collect::<HashSet<_>>();
1786
1787        RuntimeCompatibility {
1788            expected_abi_version: capabilities.abi_version,
1789            actual_abi_version: capabilities.abi_version,
1790            missing_natives: self
1791                .natives
1792                .iter()
1793                .filter(|name| !natives.contains(*name))
1794                .cloned()
1795                .collect(),
1796            incompatible_natives: Vec::new(),
1797            missing_class_methods: self
1798                .class_methods
1799                .iter()
1800                .filter(|name| !class_methods.contains(*name))
1801                .cloned()
1802                .collect(),
1803            incompatible_class_methods: Vec::new(),
1804        }
1805    }
1806}
1807
1808#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1809pub struct NativeRequirement {
1810    pub name: Symbol,
1811    pub typ: Type,
1812}
1813
1814#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1815pub struct ClassMethodRequirement {
1816    pub name: Symbol,
1817    pub typ: Type,
1818}
1819
1820#[derive(Clone, Debug, PartialEq, Eq)]
1821pub struct RuntimeLinkContract {
1822    pub abi_version: u32,
1823    pub natives: Vec<NativeRequirement>,
1824    pub class_methods: Vec<ClassMethodRequirement>,
1825}
1826
1827impl RuntimeLinkContract {
1828    pub fn fingerprint(&self) -> u64 {
1829        let mut hasher = std::collections::hash_map::DefaultHasher::new();
1830        self.abi_version.hash(&mut hasher);
1831        self.natives.hash(&mut hasher);
1832        self.class_methods.hash(&mut hasher);
1833        hasher.finish()
1834    }
1835}
1836
1837#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1838pub struct CompiledProgramBoundary {
1839    pub contains_prepared_expr: bool,
1840    pub captures_process_local_env: bool,
1841    pub serializable: bool,
1842}
1843
1844#[derive(Clone, Debug, PartialEq)]
1845pub struct RuntimeCapabilities {
1846    pub abi_version: u32,
1847    pub natives: Vec<Symbol>,
1848    pub class_methods: Vec<Symbol>,
1849    pub(crate) native_impls: HashMap<Symbol, Vec<NativeCapability>>,
1850    pub(crate) class_method_impls: HashMap<Symbol, ClassMethodCapability>,
1851}
1852
1853impl RuntimeCapabilities {
1854    pub fn fingerprint(&self) -> u64 {
1855        let mut hasher = std::collections::hash_map::DefaultHasher::new();
1856        self.abi_version.hash(&mut hasher);
1857        "natives".hash(&mut hasher);
1858        self.natives.hash(&mut hasher);
1859        "class_methods".hash(&mut hasher);
1860        self.class_methods.hash(&mut hasher);
1861        hasher.finish()
1862    }
1863}
1864
1865#[derive(Clone, Debug, PartialEq)]
1866pub struct NativeCapability {
1867    pub name: Symbol,
1868    pub arity: usize,
1869    pub scheme: Scheme,
1870}
1871
1872#[derive(Clone, Debug, PartialEq)]
1873pub struct ClassMethodCapability {
1874    pub name: Symbol,
1875    pub scheme: Scheme,
1876}
1877
1878#[derive(Clone, Debug, PartialEq, Eq)]
1879pub struct RuntimeCompatibility {
1880    pub expected_abi_version: u32,
1881    pub actual_abi_version: u32,
1882    pub missing_natives: Vec<Symbol>,
1883    pub incompatible_natives: Vec<Symbol>,
1884    pub missing_class_methods: Vec<Symbol>,
1885    pub incompatible_class_methods: Vec<Symbol>,
1886}
1887
1888impl RuntimeCompatibility {
1889    pub fn is_compatible(&self) -> bool {
1890        self.expected_abi_version == self.actual_abi_version
1891            && self.missing_natives.is_empty()
1892            && self.incompatible_natives.is_empty()
1893            && self.missing_class_methods.is_empty()
1894            && self.incompatible_class_methods.is_empty()
1895    }
1896}
1897
1898#[derive(Clone)]
1899pub struct RuntimeSnapshot<State = ()>
1900where
1901    State: Clone + Send + Sync + 'static,
1902{
1903    pub state: Arc<State>,
1904    pub(crate) env: Env,
1905    pub(crate) natives: NativeRegistry<State>,
1906    pub(crate) typeclasses: TypeclassRegistry,
1907    pub type_system: TypeSystem,
1908    pub(crate) typeclass_cache: Arc<Mutex<HashMap<(Symbol, Type), Pointer>>>,
1909    pub(crate) cancel: CancellationToken,
1910    pub heap: Heap,
1911}
1912
1913impl<State> Clone for Engine<State>
1914where
1915    State: Clone + Send + Sync + 'static,
1916{
1917    fn clone(&self) -> Self {
1918        Self {
1919            state: Arc::clone(&self.state),
1920            env: self.env.clone(),
1921            natives: self.natives.clone(),
1922            typeclasses: self.typeclasses.clone(),
1923            type_system: self.type_system.clone(),
1924            typeclass_cache: Arc::clone(&self.typeclass_cache),
1925            modules: self.modules.clone(),
1926            injected_libraries: self.injected_libraries.clone(),
1927            library_exports_cache: self.library_exports_cache.clone(),
1928            library_interface_cache: self.library_interface_cache.clone(),
1929            library_sources: self.library_sources.clone(),
1930            library_source_fingerprints: self.library_source_fingerprints.clone(),
1931            published_cycle_interfaces: self.published_cycle_interfaces.clone(),
1932            default_imports: self.default_imports.clone(),
1933            virtual_libraries: self.virtual_libraries.clone(),
1934            library_local_type_names: self.library_local_type_names.clone(),
1935            registration_library_context: self.registration_library_context.clone(),
1936            cancel: self.cancel.clone(),
1937            heap: self.heap.clone(),
1938        }
1939    }
1940}
1941
1942impl<State> Default for Engine<State>
1943where
1944    State: Clone + Send + Sync + 'static + Default,
1945{
1946    fn default() -> Self {
1947        Self::new(State::default())
1948    }
1949}
1950
1951macro_rules! native_fn_type {
1952    (; $ret:ident) => {
1953        $ret::rex_type()
1954    };
1955    ($arg_ty:ident $(, $rest:ident)* ; $ret:ident) => {
1956        Type::fun($arg_ty::rex_type(), native_fn_type!($($rest),* ; $ret))
1957    };
1958}
1959
1960define_handler_impl!([] ; 0 ; fn() -> R);
1961define_handler_impl!([(A, a, 0)] ; 1 ; fn(A) -> R);
1962define_handler_impl!([(A, a, 0), (B, b, 1)] ; 2 ; fn(A, B) -> R);
1963define_handler_impl!([(A, a, 0), (B, b, 1), (C, c, 2)] ; 3 ; fn(A, B, C) -> R);
1964define_handler_impl!(
1965    [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3)] ; 4 ; fn(A, B, C, D) -> R
1966);
1967define_handler_impl!(
1968    [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4)] ; 5 ; fn(A, B, C, D, E) -> R
1969);
1970define_handler_impl!(
1971    [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4), (G, g, 5)] ; 6 ; fn(A, B, C, D, E, G) -> R
1972);
1973define_handler_impl!(
1974    [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4), (G, g, 5), (H, h, 6)] ; 7 ; fn(A, B, C, D, E, G, H) -> R
1975);
1976define_handler_impl!(
1977    [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4), (G, g, 5), (H, h, 6), (I, i, 7)] ; 8 ; fn(A, B, C, D, E, G, H, I) -> R
1978);
1979
1980define_async_handler_impl!([] ; 0 ; fn() -> R);
1981define_async_handler_impl!([(A, a, 0)] ; 1 ; fn(A) -> R);
1982define_async_handler_impl!([(A, a, 0), (B, b, 1)] ; 2 ; fn(A, B) -> R);
1983define_async_handler_impl!([(A, a, 0), (B, b, 1), (C, c, 2)] ; 3 ; fn(A, B, C) -> R);
1984define_async_handler_impl!(
1985    [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3)] ; 4 ; fn(A, B, C, D) -> R
1986);
1987define_async_handler_impl!(
1988    [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4)] ; 5 ; fn(A, B, C, D, E) -> R
1989);
1990define_async_handler_impl!(
1991    [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4), (G, g, 5)] ; 6 ; fn(A, B, C, D, E, G) -> R
1992);
1993define_async_handler_impl!(
1994    [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4), (G, g, 5), (H, h, 6)] ; 7 ; fn(A, B, C, D, E, G, H) -> R
1995);
1996define_async_handler_impl!(
1997    [(A, a, 0), (B, b, 1), (C, c, 2), (D, d, 3), (E, e, 4), (G, g, 5), (H, h, 6), (I, i, 7)] ; 8 ; fn(A, B, C, D, E, G, H, I) -> R
1998);
1999
2000impl<State> Engine<State>
2001where
2002    State: Clone + Send + Sync + 'static,
2003{
2004    pub(crate) fn env_snapshot(&self) -> Env {
2005        self.env.clone()
2006    }
2007
2008    pub(crate) fn has_native_name(&self, name: &Symbol) -> bool {
2009        self.natives.has_name(name)
2010    }
2011
2012    pub(crate) fn runtime_snapshot(&self) -> RuntimeSnapshot<State> {
2013        RuntimeSnapshot {
2014            state: Arc::clone(&self.state),
2015            env: self.env.clone(),
2016            natives: self.natives.clone(),
2017            typeclasses: self.typeclasses.clone(),
2018            type_system: self.type_system.clone(),
2019            typeclass_cache: Arc::clone(&self.typeclass_cache),
2020            cancel: self.cancel.clone(),
2021            heap: self.heap.clone(),
2022        }
2023    }
2024
2025    pub(crate) fn runtime_capabilities_snapshot(&self) -> RuntimeCapabilities {
2026        let mut natives = self.natives.entries.keys().cloned().collect::<Vec<_>>();
2027        let mut class_methods = self
2028            .type_system
2029            .class_methods
2030            .keys()
2031            .cloned()
2032            .collect::<Vec<_>>();
2033        let mut native_impls = HashMap::new();
2034        for (name, impls) in &self.natives.entries {
2035            let mut caps = impls
2036                .iter()
2037                .map(|imp| NativeCapability {
2038                    name: name.clone(),
2039                    arity: imp.arity,
2040                    scheme: imp.scheme.clone(),
2041                })
2042                .collect::<Vec<_>>();
2043            caps.sort_by(|a, b| {
2044                a.arity
2045                    .cmp(&b.arity)
2046                    .then_with(|| a.scheme.typ.to_string().cmp(&b.scheme.typ.to_string()))
2047            });
2048            native_impls.insert(name.clone(), caps);
2049        }
2050        let mut class_method_impls = HashMap::new();
2051        for (name, info) in &self.type_system.class_methods {
2052            class_method_impls.insert(
2053                name.clone(),
2054                ClassMethodCapability {
2055                    name: name.clone(),
2056                    scheme: info.scheme.clone(),
2057                },
2058            );
2059        }
2060        natives.sort();
2061        class_methods.sort();
2062        RuntimeCapabilities {
2063            abi_version: RUNTIME_LINK_ABI_VERSION,
2064            natives,
2065            class_methods,
2066            native_impls,
2067            class_method_impls,
2068        }
2069    }
2070
2071    pub fn new(state: State) -> Self {
2072        Self {
2073            state: Arc::new(state),
2074            env: Env::new(),
2075            natives: NativeRegistry::<State>::default(),
2076            typeclasses: TypeclassRegistry::default(),
2077            type_system: TypeSystem::new(),
2078            typeclass_cache: Arc::new(Mutex::new(HashMap::new())),
2079            modules: LibrarySystem::default(),
2080            injected_libraries: HashSet::new(),
2081            library_exports_cache: HashMap::new(),
2082            library_interface_cache: HashMap::new(),
2083            library_sources: HashMap::new(),
2084            library_source_fingerprints: HashMap::new(),
2085            published_cycle_interfaces: HashSet::new(),
2086            default_imports: Vec::new(),
2087            virtual_libraries: HashMap::new(),
2088            library_local_type_names: HashMap::new(),
2089            registration_library_context: None,
2090            cancel: CancellationToken::new(),
2091            heap: Heap::new(),
2092        }
2093    }
2094
2095    pub fn with_prelude(state: State) -> Result<Self, EngineError> {
2096        Self::with_options(state, EngineOptions::default())
2097    }
2098
2099    pub fn with_options(state: State, options: EngineOptions) -> Result<Self, EngineError> {
2100        let type_system = match options.prelude {
2101            PreludeMode::Enabled => TypeSystem::new_with_prelude()?,
2102            PreludeMode::Disabled => TypeSystem::new(),
2103        };
2104        let mut engine = Engine {
2105            state: Arc::new(state),
2106            env: Env::new(),
2107            natives: NativeRegistry::<State>::default(),
2108            typeclasses: TypeclassRegistry::default(),
2109            type_system,
2110            typeclass_cache: Arc::new(Mutex::new(HashMap::new())),
2111            modules: LibrarySystem::default(),
2112            injected_libraries: HashSet::new(),
2113            library_exports_cache: HashMap::new(),
2114            library_interface_cache: HashMap::new(),
2115            library_sources: HashMap::new(),
2116            library_source_fingerprints: HashMap::new(),
2117            published_cycle_interfaces: HashSet::new(),
2118            default_imports: options.default_imports,
2119            virtual_libraries: HashMap::new(),
2120            library_local_type_names: HashMap::new(),
2121            registration_library_context: None,
2122            cancel: CancellationToken::new(),
2123            heap: Heap::new(),
2124        };
2125        if matches!(options.prelude, PreludeMode::Enabled) {
2126            engine.inject_prelude()?;
2127            engine.inject_prelude_virtual_module()?;
2128        }
2129        Ok(engine)
2130    }
2131
2132    pub fn into_heap(self) -> Heap {
2133        self.heap
2134    }
2135
2136    pub fn cancellation_token(&self) -> CancellationToken {
2137        self.cancel.clone()
2138    }
2139
2140    pub fn set_default_imports(&mut self, imports: Vec<String>) {
2141        self.default_imports = imports;
2142    }
2143
2144    pub fn default_imports(&self) -> &[String] {
2145        &self.default_imports
2146    }
2147
2148    /// Return a markdown document that inventories the currently-registered
2149    /// engine state.
2150    ///
2151    /// The report includes:
2152    /// - summary counts
2153    /// - libraries and exports
2154    /// - ADTs
2155    /// - functions/values in the type environment
2156    /// - type classes, methods, and instances
2157    /// - native implementations
2158    ///
2159    /// # Examples
2160    ///
2161    /// ```rust,ignore
2162    /// use rex_engine::Engine;
2163    ///
2164    /// let engine = Engine::with_prelude(()).unwrap();
2165    /// let md = engine.registry_markdown();
2166    ///
2167    /// assert!(md.contains("# Engine Registry"));
2168    /// assert!(md.contains("## ADTs"));
2169    /// ```
2170    pub fn registry_markdown(&self) -> String {
2171        fn library_anchor(id: &LibraryId) -> String {
2172            let raw = format!("library-{id}").to_ascii_lowercase();
2173            let mut out = String::with_capacity(raw.len());
2174            let mut prev_dash = false;
2175            for ch in raw.chars() {
2176                let keep = ch.is_ascii_alphanumeric();
2177                let mapped = if keep { ch } else { '-' };
2178                if mapped == '-' {
2179                    if prev_dash {
2180                        continue;
2181                    }
2182                    prev_dash = true;
2183                } else {
2184                    prev_dash = false;
2185                }
2186                out.push(mapped);
2187            }
2188            out.trim_matches('-').to_string()
2189        }
2190
2191        fn symbol_list(symbols: &[Symbol]) -> String {
2192            if symbols.is_empty() {
2193                "(none)".to_string()
2194            } else {
2195                symbols
2196                    .iter()
2197                    .map(|s| format!("`{s}`"))
2198                    .collect::<Vec<_>>()
2199                    .join(", ")
2200            }
2201        }
2202
2203        let mut out = String::new();
2204        let _ = writeln!(&mut out, "# Engine Registry");
2205        let _ = writeln!(&mut out);
2206        let mut library_ids: BTreeMap<String, LibraryId> = BTreeMap::new();
2207        for id in self.library_exports_cache.keys() {
2208            library_ids.insert(id.to_string(), id.clone());
2209        }
2210        for id in self.library_sources.keys() {
2211            library_ids.insert(id.to_string(), id.clone());
2212        }
2213        for library_name in self.virtual_libraries.keys() {
2214            let id = LibraryId::Virtual(library_name.clone());
2215            library_ids.insert(id.to_string(), id);
2216        }
2217        for library_name in &self.injected_libraries {
2218            let id = LibraryId::Virtual(library_name.clone());
2219            library_ids.insert(id.to_string(), id);
2220        }
2221
2222        let _ = writeln!(&mut out, "## Summary");
2223        let env_value_count = self.type_system.env.values.size();
2224        let native_impl_count: usize = self.natives.entries.values().map(Vec::len).sum();
2225        let class_count = self.type_system.classes.classes.len();
2226        let class_instance_count: usize = self
2227            .type_system
2228            .classes
2229            .instances
2230            .values()
2231            .map(Vec::len)
2232            .sum();
2233        let _ = writeln!(&mut out, "- Libraries (all kinds): {}", library_ids.len());
2234        let _ = writeln!(
2235            &mut out,
2236            "- Injected libraries: {}",
2237            self.injected_libraries.len()
2238        );
2239        let _ = writeln!(
2240            &mut out,
2241            "- Virtual libraries: {}",
2242            self.virtual_libraries.len()
2243        );
2244        let _ = writeln!(&mut out, "- ADTs: {}", self.type_system.adts.len());
2245        let _ = writeln!(
2246            &mut out,
2247            "- Values/functions in type env: {env_value_count}"
2248        );
2249        let _ = writeln!(&mut out, "- Type classes: {class_count}");
2250        let _ = writeln!(&mut out, "- Type class instances: {class_instance_count}");
2251        let _ = writeln!(&mut out, "- Native implementations: {native_impl_count}");
2252        let _ = writeln!(&mut out);
2253
2254        let _ = writeln!(&mut out, "## Library Index");
2255        if library_ids.is_empty() {
2256            let _ = writeln!(&mut out, "_No libraries registered._");
2257        } else {
2258            for (display, id) in &library_ids {
2259                let anchor = library_anchor(id);
2260                let _ = writeln!(&mut out, "- [`{display}`](#{anchor})");
2261            }
2262        }
2263        let _ = writeln!(&mut out);
2264
2265        let _ = writeln!(&mut out, "## Libraries");
2266        if library_ids.is_empty() {
2267            let _ = writeln!(&mut out, "_No libraries registered._");
2268            let _ = writeln!(&mut out);
2269        } else {
2270            for (display, id) in library_ids {
2271                let anchor = library_anchor(&id);
2272                let _ = writeln!(&mut out, "<a id=\"{anchor}\"></a>");
2273                let _ = writeln!(&mut out, "### `{display}`");
2274                let virtual_source = match &id {
2275                    LibraryId::Virtual(name) => {
2276                        self.virtual_libraries.get(name).and_then(|module| {
2277                            module
2278                                .source
2279                                .clone()
2280                                .or_else(|| render_virtual_module_source(&module.decls))
2281                        })
2282                    }
2283                    _ => None,
2284                };
2285                if let Some(source) = self.library_sources.get(&id).cloned().or(virtual_source) {
2286                    if source.trim().is_empty() {
2287                        let _ = writeln!(&mut out, "_Module source is empty._");
2288                    } else {
2289                        let _ = writeln!(&mut out, "```rex");
2290                        let _ = writeln!(&mut out, "{}", source.trim_end());
2291                        let _ = writeln!(&mut out, "```");
2292                    }
2293                } else {
2294                    let _ = writeln!(&mut out, "_No captured source for this library._");
2295                }
2296
2297                let exports = self.library_exports_cache.get(&id).or_else(|| match &id {
2298                    LibraryId::Virtual(name) => {
2299                        self.virtual_libraries.get(name).map(|m| &m.exports)
2300                    }
2301                    _ => None,
2302                });
2303                if let Some(exports) = exports {
2304                    let mut values: Vec<Symbol> = exports.values.keys().cloned().collect();
2305                    let mut types: Vec<Symbol> = exports.types.keys().cloned().collect();
2306                    let mut classes: Vec<Symbol> = exports.classes.keys().cloned().collect();
2307                    values.sort();
2308                    types.sort();
2309                    classes.sort();
2310                    let _ = writeln!(&mut out, "- Values: {}", symbol_list(&values));
2311                    let _ = writeln!(&mut out, "- Types: {}", symbol_list(&types));
2312                    let _ = writeln!(&mut out, "- Classes: {}", symbol_list(&classes));
2313                } else {
2314                    let _ = writeln!(&mut out, "- Exports: (none cached)");
2315                }
2316                let _ = writeln!(&mut out);
2317            }
2318        }
2319
2320        let _ = writeln!(&mut out, "## ADTs");
2321        if self.type_system.adts.is_empty() {
2322            let _ = writeln!(&mut out, "_No ADTs registered._");
2323            let _ = writeln!(&mut out);
2324        } else {
2325            let mut adts: Vec<&AdtDecl> = self.type_system.adts.values().collect();
2326            adts.sort_by(|a, b| a.name.cmp(&b.name));
2327            for adt in adts {
2328                let params = if adt.params.is_empty() {
2329                    "(none)".to_string()
2330                } else {
2331                    adt.params
2332                        .iter()
2333                        .map(|p| format!("`{}`", p.name))
2334                        .collect::<Vec<_>>()
2335                        .join(", ")
2336                };
2337                let _ = writeln!(&mut out, "### `{}`", adt.name);
2338                let _ = writeln!(&mut out, "- Parameters: {params}");
2339                if adt.variants.is_empty() {
2340                    let _ = writeln!(&mut out, "- Variants: (none)");
2341                } else {
2342                    let mut variants = adt.variants.clone();
2343                    variants.sort_by(|a, b| a.name.cmp(&b.name));
2344                    let _ = writeln!(&mut out, "- Variants:");
2345                    for variant in variants {
2346                        if variant.args.is_empty() {
2347                            let _ = writeln!(&mut out, "  - `{}`", variant.name);
2348                        } else {
2349                            let args = variant
2350                                .args
2351                                .iter()
2352                                .map(ToString::to_string)
2353                                .collect::<Vec<_>>()
2354                                .join(", ");
2355                            let _ = writeln!(&mut out, "  - `{}`({args})", variant.name);
2356                        }
2357                    }
2358                }
2359                let _ = writeln!(&mut out);
2360            }
2361        }
2362
2363        let _ = writeln!(&mut out, "## Functions and Values");
2364        if self.type_system.env.values.is_empty() {
2365            let _ = writeln!(&mut out, "_No values registered._");
2366            let _ = writeln!(&mut out);
2367        } else {
2368            let mut names: Vec<Symbol> = self
2369                .type_system
2370                .env
2371                .values
2372                .iter()
2373                .map(|(name, _)| name.clone())
2374                .collect();
2375            names.sort();
2376            for name in names {
2377                if let Some(schemes) = self.type_system.env.lookup(&name) {
2378                    let mut scheme_strs: Vec<String> =
2379                        schemes.iter().map(|s| s.typ.to_string()).collect();
2380                    scheme_strs.sort();
2381                    scheme_strs.dedup();
2382                    let joined = scheme_strs
2383                        .into_iter()
2384                        .map(|s| format!("`{s}`"))
2385                        .collect::<Vec<_>>()
2386                        .join(", ");
2387                    let _ = writeln!(&mut out, "- `{name}`: {joined}");
2388                }
2389            }
2390            let _ = writeln!(&mut out);
2391        }
2392
2393        let _ = writeln!(&mut out, "## Type Classes");
2394        if self.type_system.classes.classes.is_empty() {
2395            let _ = writeln!(&mut out, "_No type classes registered._");
2396            let _ = writeln!(&mut out);
2397        } else {
2398            let mut class_names: Vec<Symbol> =
2399                self.type_system.classes.classes.keys().cloned().collect();
2400            class_names.sort();
2401            for class_name in class_names {
2402                let supers = self.type_system.classes.supers_of(&class_name);
2403                let mut supers_sorted = supers;
2404                supers_sorted.sort();
2405                let _ = writeln!(&mut out, "### `{class_name}`");
2406                let _ = writeln!(&mut out, "- Superclasses: {}", symbol_list(&supers_sorted));
2407
2408                let mut methods: Vec<(Symbol, String)> = self
2409                    .type_system
2410                    .class_methods
2411                    .iter()
2412                    .filter(|(_, info)| info.class == class_name)
2413                    .map(|(name, info)| (name.clone(), info.scheme.typ.to_string()))
2414                    .collect();
2415                methods.sort_by(|a, b| a.0.cmp(&b.0));
2416                if methods.is_empty() {
2417                    let _ = writeln!(&mut out, "- Methods: (none)");
2418                } else {
2419                    let _ = writeln!(&mut out, "- Methods:");
2420                    for (method, scheme) in methods {
2421                        let _ = writeln!(&mut out, "  - `{method}`: `{scheme}`");
2422                    }
2423                }
2424
2425                let mut instances = self
2426                    .type_system
2427                    .classes
2428                    .instances
2429                    .get(&class_name)
2430                    .cloned()
2431                    .unwrap_or_default();
2432                instances.sort_by(|a, b| a.head.typ.to_string().cmp(&b.head.typ.to_string()));
2433                if instances.is_empty() {
2434                    let _ = writeln!(&mut out, "- Instances: (none)");
2435                } else {
2436                    let _ = writeln!(&mut out, "- Instances:");
2437                    for instance in instances {
2438                        let ctx = if instance.context.is_empty() {
2439                            String::new()
2440                        } else {
2441                            let mut parts: Vec<String> = instance
2442                                .context
2443                                .iter()
2444                                .map(|pred| format!("{} {}", pred.class, pred.typ))
2445                                .collect();
2446                            parts.sort();
2447                            format!("({}) => ", parts.join(", "))
2448                        };
2449                        let _ = writeln!(
2450                            &mut out,
2451                            "  - `{}{} {}`",
2452                            ctx, instance.head.class, instance.head.typ
2453                        );
2454                    }
2455                }
2456                let _ = writeln!(&mut out);
2457            }
2458        }
2459
2460        let _ = writeln!(&mut out, "## Native Implementations");
2461        if self.natives.entries.is_empty() {
2462            let _ = writeln!(&mut out, "_No native implementations registered._");
2463        } else {
2464            let mut native_names: Vec<Symbol> = self.natives.entries.keys().cloned().collect();
2465            native_names.sort();
2466            for name in native_names {
2467                if let Some(impls) = self.natives.get(&name) {
2468                    let mut rows: Vec<(usize, String, u64)> = impls
2469                        .iter()
2470                        .map(|imp| (imp.arity, imp.scheme.typ.to_string(), imp.gas_cost))
2471                        .collect();
2472                    rows.sort_by(|a, b| a.1.cmp(&b.1));
2473                    let _ = writeln!(&mut out, "### `{name}`");
2474                    for (arity, typ, gas_cost) in rows {
2475                        let _ = writeln!(
2476                            &mut out,
2477                            "- arity `{arity}`, gas `{gas_cost}`, type `{typ}`"
2478                        );
2479                    }
2480                    let _ = writeln!(&mut out);
2481                }
2482            }
2483        }
2484
2485        out
2486    }
2487
2488    pub fn cancel(&self) {
2489        self.cancel.cancel();
2490    }
2491
2492    pub fn inject_library(&mut self, library: Library<State>) -> Result<(), EngineError> {
2493        let library_name = library.name.trim().to_string();
2494        if library_name.is_empty() {
2495            return Err(EngineError::Internal("library name cannot be empty".into()));
2496        }
2497        let is_global = library_name == ROOT_LIBRARY_NAME;
2498        if !is_global && self.injected_libraries.contains(&library_name) {
2499            return Err(EngineError::Internal(format!(
2500                "library `{library_name}` already injected"
2501            )));
2502        }
2503
2504        if is_global {
2505            for adt in &library.staged_adts {
2506                self.inject_adt(adt.clone())?;
2507            }
2508
2509            let staged_adt_names: HashSet<Symbol> = library
2510                .staged_adts
2511                .iter()
2512                .map(|adt| adt.name.clone())
2513                .collect();
2514            let decls = if library.raw_declarations.is_empty() {
2515                library
2516                    .structured_decls
2517                    .iter()
2518                    .filter(|decl| match decl {
2519                        Decl::Type(ty) => !staged_adt_names.contains(&ty.name),
2520                        _ => true,
2521                    })
2522                    .cloned()
2523                    .collect()
2524            } else {
2525                let source = library.raw_declarations.join("\n");
2526                let context = LibraryId::Virtual(ROOT_LIBRARY_NAME.to_string());
2527                parse_program_from_source(&source, Some(&context), None)?.decls
2528            };
2529
2530            for export in library.exports {
2531                self.inject_library_export(ROOT_LIBRARY_NAME, export)?;
2532            }
2533            self.inject_decls(&decls)?;
2534            return Ok(());
2535        }
2536
2537        let library_id = LibraryId::Virtual(library_name.clone());
2538
2539        if library.raw_declarations.is_empty() {
2540            let mut decls = library.structured_decls.clone();
2541            decls.extend(
2542                library
2543                    .exports
2544                    .iter()
2545                    .map(|export| Decl::DeclareFn(export.interface.clone())),
2546            );
2547            let local_type_names = library_local_type_names_from_decls(&decls);
2548            self.library_local_type_names
2549                .insert(library_name.clone(), local_type_names);
2550
2551            let program = Program {
2552                decls,
2553                expr: Arc::new(Expr::Tuple(Span::default(), vec![])),
2554            };
2555            let prefix = prefix_for_library(&library_id);
2556            let exports = crate::libraries::exports_from_program(&program, &prefix, &library_id);
2557            let qualified = qualify_program(&program, &prefix);
2558            let interfaces = interface_decls_from_program(&qualified);
2559            self.library_exports_cache
2560                .insert(library_id.clone(), exports.clone());
2561            self.library_interface_cache
2562                .insert(library_id.clone(), interfaces.clone());
2563            self.virtual_libraries.insert(
2564                library_name.clone(),
2565                VirtualLibraryModule {
2566                    exports,
2567                    decls: program.decls.clone(),
2568                    source: None,
2569                },
2570            );
2571
2572            for export in library.exports {
2573                self.inject_library_export(&library_name, export)?;
2574            }
2575
2576            self.inject_decls(&qualified.decls)?;
2577            let resolver_module_name = library_name.clone();
2578            let resolver_program = program;
2579            self.add_resolver(
2580                format!("injected:{library_name}"),
2581                move |req: ResolveRequest| {
2582                    let requested = req
2583                        .library_name
2584                        .split_once('#')
2585                        .map(|(base, _)| base)
2586                        .unwrap_or(req.library_name.as_str());
2587                    if requested != resolver_module_name {
2588                        return Ok(None);
2589                    }
2590                    Ok(Some(ResolvedLibrary {
2591                        id: LibraryId::Virtual(resolver_module_name.clone()),
2592                        content: ResolvedLibraryContent::Program(resolver_program.clone()),
2593                    }))
2594                },
2595            );
2596        } else {
2597            let full_source =
2598                build_virtual_library_source(&library.raw_declarations, &library.exports);
2599            let local_type_names =
2600                library_local_type_names_from_declarations(&library.raw_declarations);
2601            self.library_local_type_names
2602                .insert(library_name.clone(), local_type_names);
2603            self.library_sources
2604                .insert(library_id.clone(), full_source.clone());
2605
2606            for export in library.exports {
2607                self.inject_library_export(&library_name, export)?;
2608            }
2609            let resolver_module_name = library_name.clone();
2610            let resolver_source = full_source;
2611            self.add_resolver(
2612                format!("injected:{library_name}"),
2613                move |req: ResolveRequest| {
2614                    let requested = req
2615                        .library_name
2616                        .split_once('#')
2617                        .map(|(base, _)| base)
2618                        .unwrap_or(req.library_name.as_str());
2619                    if requested != resolver_module_name {
2620                        return Ok(None);
2621                    }
2622                    Ok(Some(ResolvedLibrary {
2623                        id: LibraryId::Virtual(resolver_module_name.clone()),
2624                        content: ResolvedLibraryContent::Source(resolver_source.clone()),
2625                    }))
2626                },
2627            );
2628        }
2629
2630        self.injected_libraries.insert(library_name);
2631        Ok(())
2632    }
2633
2634    fn library_export_symbol(library_name: &str, export_name: &str) -> String {
2635        if library_name == ROOT_LIBRARY_NAME {
2636            normalize_name(export_name).to_string()
2637        } else {
2638            virtual_export_name(library_name, export_name)
2639        }
2640    }
2641
2642    fn inject_library_export(
2643        &mut self,
2644        library_name: &str,
2645        export: Export<State>,
2646    ) -> Result<(), EngineError> {
2647        let Export {
2648            name,
2649            interface: _,
2650            injector,
2651        } = export;
2652        let qualified_name = Self::library_export_symbol(library_name, &name);
2653        let previous_context = self.registration_library_context.clone();
2654        self.registration_library_context = if library_name == ROOT_LIBRARY_NAME {
2655            None
2656        } else {
2657            Some(library_name.to_string())
2658        };
2659        let result = injector(self, &qualified_name);
2660        self.registration_library_context = previous_context;
2661        result
2662    }
2663
2664    fn inject_root_export(&mut self, export: Export<State>) -> Result<(), EngineError> {
2665        self.inject_library_export(ROOT_LIBRARY_NAME, export)
2666    }
2667
2668    fn register_native_registration(
2669        &mut self,
2670        library_name: &str,
2671        export_name: &str,
2672        registration: NativeRegistration<State>,
2673    ) -> Result<(), EngineError> {
2674        let NativeRegistration {
2675            mut scheme,
2676            arity,
2677            callable,
2678            gas_cost,
2679        } = registration;
2680        let scheme_module = if library_name == ROOT_LIBRARY_NAME {
2681            self.registration_library_context
2682                .as_deref()
2683                .unwrap_or(ROOT_LIBRARY_NAME)
2684        } else {
2685            library_name
2686        };
2687        if scheme_module != ROOT_LIBRARY_NAME
2688            && let Some(local_type_names) = self.library_local_type_names.get(scheme_module)
2689        {
2690            scheme = qualify_library_scheme_refs(&scheme, scheme_module, local_type_names);
2691        }
2692        let name = normalize_name(&Self::library_export_symbol(library_name, export_name));
2693        self.register_native(name, scheme, arity, callable, gas_cost)
2694    }
2695
2696    pub(crate) fn export<Sig, H>(
2697        &mut self,
2698        name: impl Into<String>,
2699        handler: H,
2700    ) -> Result<(), EngineError>
2701    where
2702        H: Handler<State, Sig>,
2703    {
2704        self.inject_root_export(Export::from_handler(name, handler)?)
2705    }
2706
2707    pub(crate) fn export_native<F>(
2708        &mut self,
2709        name: impl Into<String>,
2710        scheme: Scheme,
2711        arity: usize,
2712        handler: F,
2713    ) -> Result<(), EngineError>
2714    where
2715        F: for<'a> Fn(
2716                EvaluatorRef<'a, State>,
2717                &'a Type,
2718                &'a [Pointer],
2719            ) -> Result<Pointer, EngineError>
2720            + Send
2721            + Sync
2722            + 'static,
2723    {
2724        self.export_native_with_gas_cost(name, scheme, arity, 0, handler)
2725    }
2726
2727    pub fn inject_rex_default_instance<T>(&mut self) -> Result<(), EngineError>
2728    where
2729        T: RexType + RexDefault<State>,
2730    {
2731        let class = sym("Default");
2732        let method = sym("default");
2733        let head_ty = T::rex_type();
2734
2735        if !self.type_system.class_methods.contains_key(&method) {
2736            return Err(EngineError::UnknownVar(method));
2737        }
2738        if !head_ty.ftv().is_empty() {
2739            return Err(EngineError::UnsupportedExpr);
2740        }
2741
2742        if let Some(instances) = self.type_system.classes.instances.get(&class)
2743            && instances
2744                .iter()
2745                .any(|existing| unify(&existing.head.typ, &head_ty).is_ok())
2746        {
2747            return Err(EngineError::DuplicateTypeclassImpl {
2748                class,
2749                typ: head_ty.to_string(),
2750            });
2751        }
2752
2753        let native_name = format!(
2754            "__rex_default_for_{}",
2755            sanitize_type_name_for_symbol(&head_ty)
2756        );
2757        let native_scheme = Scheme::new(vec![], vec![], head_ty.clone());
2758        let engine_for_default = self.clone();
2759        self.export_native(
2760            native_name.clone(),
2761            native_scheme,
2762            0,
2763            move |engine, _, _| {
2764                let _ = engine;
2765                T::rex_default(&engine_for_default)
2766            },
2767        )?;
2768
2769        self.type_system.register_instance(
2770            "Default",
2771            Instance::new(vec![], Predicate::new(class.clone(), head_ty.clone())),
2772        );
2773
2774        let mut methods: HashMap<Symbol, Arc<TypedExpr>> = HashMap::new();
2775        methods.insert(
2776            method.clone(),
2777            Arc::new(TypedExpr::new(
2778                head_ty.clone(),
2779                TypedExprKind::Var {
2780                    name: sym(&native_name),
2781                    overloads: vec![],
2782                },
2783            )),
2784        );
2785
2786        self.typeclasses
2787            .insert(class, head_ty, self.env.clone(), methods)?;
2788
2789        Ok(())
2790    }
2791
2792    pub(crate) fn export_native_async<F>(
2793        &mut self,
2794        name: impl Into<String>,
2795        scheme: Scheme,
2796        arity: usize,
2797        handler: F,
2798    ) -> Result<(), EngineError>
2799    where
2800        F: for<'a> Fn(EvaluatorRef<'a, State>, Type, Vec<Pointer>) -> NativeFuture<'a>
2801            + Send
2802            + Sync
2803            + 'static,
2804    {
2805        self.export_native_async_with_gas_cost(name, scheme, arity, 0, handler)
2806    }
2807
2808    pub(crate) fn export_value<V: IntoPointer + RexType>(
2809        &mut self,
2810        name: &str,
2811        value: V,
2812    ) -> Result<(), EngineError> {
2813        let typ = V::rex_type();
2814        let value = value.into_pointer(&self.heap)?;
2815        let func: SyncNativeCallable<State> =
2816            Arc::new(move |_engine, _: &Type, _args: &[Pointer]| Ok(value));
2817        let scheme = Scheme::new(vec![], vec![], typ);
2818        let registration = NativeRegistration::sync(scheme, 0, func, 0);
2819        self.register_native_registration(ROOT_LIBRARY_NAME, name, registration)
2820    }
2821
2822    pub(crate) fn export_native_with_gas_cost<F>(
2823        &mut self,
2824        name: impl Into<String>,
2825        scheme: Scheme,
2826        arity: usize,
2827        gas_cost: u64,
2828        handler: F,
2829    ) -> Result<(), EngineError>
2830    where
2831        F: for<'a> Fn(
2832                EvaluatorRef<'a, State>,
2833                &'a Type,
2834                &'a [Pointer],
2835            ) -> Result<Pointer, EngineError>
2836            + Send
2837            + Sync
2838            + 'static,
2839    {
2840        validate_native_export_scheme(&scheme, arity)?;
2841        let name = name.into();
2842        let handler = Arc::new(handler);
2843        let func: SyncNativeCallable<State> =
2844            Arc::new(move |engine, typ: &Type, args: &[Pointer]| handler(engine, typ, args));
2845        let registration = NativeRegistration::sync(scheme, arity, func, gas_cost);
2846        self.register_native_registration(ROOT_LIBRARY_NAME, &name, registration)
2847    }
2848
2849    pub(crate) fn export_native_async_with_gas_cost<F>(
2850        &mut self,
2851        name: impl Into<String>,
2852        scheme: Scheme,
2853        arity: usize,
2854        gas_cost: u64,
2855        handler: F,
2856    ) -> Result<(), EngineError>
2857    where
2858        F: for<'a> Fn(EvaluatorRef<'a, State>, Type, Vec<Pointer>) -> NativeFuture<'a>
2859            + Send
2860            + Sync
2861            + 'static,
2862    {
2863        validate_native_export_scheme(&scheme, arity)?;
2864        let name = name.into();
2865        let handler = Arc::new(handler);
2866        let func: AsyncNativeCallable<State> = Arc::new(move |engine, typ, args| {
2867            let handler = Arc::clone(&handler);
2868            handler(engine, typ, args.to_vec())
2869        });
2870        let registration = NativeRegistration::r#async(scheme, arity, func, gas_cost);
2871        self.register_native_registration(ROOT_LIBRARY_NAME, &name, registration)
2872    }
2873
2874    pub fn adt_decl(&mut self, name: &str, params: &[&str]) -> AdtDecl {
2875        let name_sym = sym(name);
2876        let param_syms: Vec<Symbol> = params.iter().map(|p| sym(p)).collect();
2877        AdtDecl::new(&name_sym, &param_syms, &mut self.type_system.supply)
2878    }
2879
2880    /// Seed an `AdtDecl` from a Rex type constructor.
2881    ///
2882    /// Accepted shapes:
2883    /// - `Type::con("Foo", 0)` -> `Foo` with no params
2884    /// - `Foo a b` (where args are type vars) -> `Foo` with params inferred from vars
2885    /// - `Type::con("Foo", n)` (bare higher-kinded head) -> `Foo` with generated params `t0..t{n-1}`
2886    pub fn adt_decl_from_type(&mut self, typ: &Type) -> Result<AdtDecl, EngineError> {
2887        let (name, arity, args) = type_head_and_args(typ)?;
2888        let param_names: Vec<String> = if args.is_empty() {
2889            (0..arity).map(|i| format!("t{i}")).collect()
2890        } else {
2891            let mut names = Vec::with_capacity(args.len());
2892            for arg in args {
2893                match arg.as_ref() {
2894                    TypeKind::Var(tv) => {
2895                        let name = tv
2896                            .name
2897                            .as_ref()
2898                            .map(|s| s.to_string())
2899                            .unwrap_or_else(|| format!("t{}", tv.id));
2900                        names.push(name);
2901                    }
2902                    _ => {
2903                        return Err(EngineError::Custom(format!(
2904                            "cannot infer ADT params from `{typ}`: expected type variables, got `{arg}`"
2905                        )));
2906                    }
2907                }
2908            }
2909            names
2910        };
2911        let param_refs: Vec<&str> = param_names.iter().map(|s| s.as_str()).collect();
2912        Ok(self.adt_decl(name.as_ref(), &param_refs))
2913    }
2914
2915    /// Same as `adt_decl_from_type`, but uses explicit parameter names.
2916    pub fn adt_decl_from_type_with_params(
2917        &mut self,
2918        typ: &Type,
2919        params: &[&str],
2920    ) -> Result<AdtDecl, EngineError> {
2921        let (name, arity, _args) = type_head_and_args(typ)?;
2922        if arity != params.len() {
2923            return Err(EngineError::Custom(format!(
2924                "type `{}` expects {} parameters, got {}",
2925                name,
2926                arity,
2927                params.len()
2928            )));
2929        }
2930        Ok(self.adt_decl(name.as_ref(), params))
2931    }
2932
2933    pub(crate) fn inject_adt(&mut self, adt: AdtDecl) -> Result<(), EngineError> {
2934        let register_type = match self.type_system.adts.get(&adt.name) {
2935            Some(existing) if adt_shape_eq(existing, &adt) => false,
2936            Some(existing) => {
2937                return Err(EngineError::Custom(format!(
2938                    "conflicting ADT registration for `{}`: existing={} new={}",
2939                    adt.name,
2940                    adt_shape(existing),
2941                    adt_shape(&adt)
2942                )));
2943            }
2944            None => true,
2945        };
2946
2947        // Type system gets the constructor schemes; runtime gets constructor functions
2948        // that build `Value::Adt` with the constructor tag and evaluated args.
2949        if register_type {
2950            self.type_system.register_adt(&adt);
2951        }
2952        for (ctor, scheme) in adt.constructor_schemes() {
2953            if self
2954                .natives
2955                .get(&ctor)
2956                .is_some_and(|existing| existing.iter().any(|imp| imp.scheme == scheme))
2957            {
2958                continue;
2959            }
2960            let ctor_name = ctor.clone();
2961            let func = Arc::new(
2962                move |engine: EvaluatorRef<'_, State>, _: &Type, args: &[Pointer]| {
2963                    engine.heap.alloc_adt(ctor_name.clone(), args.to_vec())
2964                },
2965            );
2966            let arity = type_arity(&scheme.typ);
2967            self.register_native(ctor, scheme, arity, NativeCallable::Sync(func), 0)?;
2968        }
2969        Ok(())
2970    }
2971
2972    pub(crate) fn inject_type_decl(&mut self, decl: &TypeDecl) -> Result<(), EngineError> {
2973        let adt = self
2974            .type_system
2975            .adt_from_decl(decl)
2976            .map_err(EngineError::Type)?;
2977        self.inject_adt(adt)
2978    }
2979
2980    pub(crate) fn inject_class_decl(&mut self, decl: &ClassDecl) -> Result<(), EngineError> {
2981        self.type_system
2982            .register_class_decl(decl)
2983            .map_err(EngineError::Type)
2984    }
2985
2986    pub(crate) fn inject_instance_decl(&mut self, decl: &InstanceDecl) -> Result<(), EngineError> {
2987        let prepared = self
2988            .type_system
2989            .register_instance_decl(decl)
2990            .map_err(EngineError::Type)?;
2991        self.register_typeclass_instance(decl, &prepared)
2992    }
2993
2994    pub(crate) fn inject_fn_decls(&mut self, decls: &[FnDecl]) -> Result<(), EngineError> {
2995        if decls.is_empty() {
2996            return Ok(());
2997        }
2998
2999        // Register declared types first so bodies can typecheck mutually-recursively.
3000        self.type_system
3001            .register_fn_decls(decls)
3002            .map_err(EngineError::Type)?;
3003
3004        // Build a recursive runtime environment with placeholders, then fill each slot.
3005        let mut env_rec = self.env.clone();
3006        let mut slots = Vec::with_capacity(decls.len());
3007        for decl in decls {
3008            if let Some(existing) = env_rec.get(&decl.name.name) {
3009                slots.push(existing);
3010            } else {
3011                let placeholder = self.heap.alloc_uninitialized(decl.name.name.clone())?;
3012                env_rec = env_rec.extend(decl.name.name.clone(), placeholder);
3013                slots.push(placeholder);
3014            }
3015        }
3016
3017        let saved_env = self.env.clone();
3018        self.env = env_rec.clone();
3019
3020        let result: Result<(), EngineError> = (|| {
3021            for (decl, slot) in decls.iter().zip(slots.iter()) {
3022                let mut lam_body = decl.body.clone();
3023                for (idx, (param, ann)) in decl.params.iter().enumerate().rev() {
3024                    let lam_constraints = if idx == 0 {
3025                        decl.constraints.clone()
3026                    } else {
3027                        Vec::new()
3028                    };
3029                    let span = param.span;
3030                    lam_body = Arc::new(Expr::Lam(
3031                        span,
3032                        Scope::new_sync(),
3033                        param.clone(),
3034                        Some(ann.clone()),
3035                        lam_constraints,
3036                        lam_body,
3037                    ));
3038                }
3039
3040                let typed = self.type_check_expr(lam_body.as_ref())?;
3041                let (param_ty, _ret_ty) = split_fun(&typed.typ)
3042                    .ok_or_else(|| EngineError::NotCallable(typed.typ.to_string()))?;
3043                let TypedExprKind::Lam { param, body } = &typed.kind else {
3044                    return Err(EngineError::Internal(
3045                        "fn declaration did not lower to lambda".into(),
3046                    ));
3047                };
3048                let ptr = self.heap.alloc_closure(
3049                    self.env.clone(),
3050                    param.clone(),
3051                    param_ty,
3052                    typed.typ.clone(),
3053                    Arc::new(body.as_ref().clone()),
3054                )?;
3055                let value = self.heap.get(&ptr)?;
3056                self.heap.overwrite(slot, value.as_ref().clone())?;
3057            }
3058            Ok(())
3059        })();
3060
3061        if result.is_err() {
3062            self.env = saved_env;
3063            return result;
3064        }
3065
3066        self.env = env_rec;
3067        Ok(())
3068    }
3069
3070    pub(crate) fn inject_decls(&mut self, decls: &[Decl]) -> Result<(), EngineError> {
3071        let mut pending_fns: Vec<FnDecl> = Vec::new();
3072        for decl in decls {
3073            if let Decl::Fn(fd) = decl {
3074                pending_fns.push(fd.clone());
3075                continue;
3076            }
3077            if !pending_fns.is_empty() {
3078                self.inject_fn_decls(&pending_fns)?;
3079                pending_fns.clear();
3080            }
3081
3082            match decl {
3083                Decl::Type(ty) => self.inject_type_decl(ty)?,
3084                Decl::Class(class_decl) => self.inject_class_decl(class_decl)?,
3085                Decl::Instance(inst_decl) => self.inject_instance_decl(inst_decl)?,
3086                Decl::Fn(..) => {}
3087                Decl::DeclareFn(df) => {
3088                    self.type_system
3089                        .inject_declare_fn_decl(df)
3090                        .map_err(EngineError::Type)?;
3091                }
3092                Decl::Import(..) => {}
3093            }
3094        }
3095        if !pending_fns.is_empty() {
3096            self.inject_fn_decls(&pending_fns)?;
3097        }
3098        Ok(())
3099    }
3100
3101    pub(crate) fn publish_runtime_decl_interfaces(
3102        &mut self,
3103        decls: &[DeclareFnDecl],
3104    ) -> Result<(), EngineError> {
3105        for df in decls {
3106            if self.env.get(&df.name.name).is_some() {
3107                continue;
3108            }
3109            let placeholder = self.heap.alloc_uninitialized(df.name.name.clone())?;
3110            self.env = self.env.extend(df.name.name.clone(), placeholder);
3111        }
3112        Ok(())
3113    }
3114
3115    pub fn inject_instance(&mut self, class: &str, inst: Instance) {
3116        self.type_system.register_instance(class, inst);
3117    }
3118
3119    fn inject_prelude(&mut self) -> Result<(), EngineError> {
3120        inject_prelude_adts(self)?;
3121        inject_equality_ops(self)?;
3122        inject_order_ops(self)?;
3123        inject_show_ops(self)?;
3124        inject_boolean_ops(self)?;
3125        inject_numeric_ops(self)?;
3126        inject_list_builtins(self)?;
3127        inject_option_result_builtins(self)?;
3128        inject_json_primops(self)?;
3129        self.register_prelude_typeclass_instances()?;
3130        Ok(())
3131    }
3132
3133    fn inject_prelude_virtual_module(&mut self) -> Result<(), EngineError> {
3134        if self.virtual_libraries.contains_key(PRELUDE_LIBRARY_NAME) {
3135            return Ok(());
3136        }
3137
3138        let module_key =
3139            library_key_for_library(&LibraryId::Virtual(PRELUDE_LIBRARY_NAME.to_string()));
3140        let mut values: HashMap<Symbol, CanonicalSymbol> = HashMap::new();
3141        for (name, _) in self.type_system.env.values.iter() {
3142            if !name.as_ref().starts_with("@m") {
3143                values.insert(
3144                    name.clone(),
3145                    CanonicalSymbol::from_symbol(
3146                        module_key,
3147                        SymbolKind::Value,
3148                        name.clone(),
3149                        name.clone(),
3150                    ),
3151                );
3152            }
3153        }
3154
3155        let mut types: HashMap<Symbol, CanonicalSymbol> = HashMap::new();
3156        for name in self.type_system.adts.keys() {
3157            if !name.as_ref().starts_with("@m") {
3158                types.insert(
3159                    name.clone(),
3160                    CanonicalSymbol::from_symbol(
3161                        module_key,
3162                        SymbolKind::Type,
3163                        name.clone(),
3164                        name.clone(),
3165                    ),
3166                );
3167            }
3168        }
3169
3170        let mut classes: HashMap<Symbol, CanonicalSymbol> = HashMap::new();
3171        for name in self.type_system.class_info.keys() {
3172            if !name.as_ref().starts_with("@m") {
3173                classes.insert(
3174                    name.clone(),
3175                    CanonicalSymbol::from_symbol(
3176                        module_key,
3177                        SymbolKind::Class,
3178                        name.clone(),
3179                        name.clone(),
3180                    ),
3181                );
3182            }
3183        }
3184
3185        self.virtual_libraries.insert(
3186            PRELUDE_LIBRARY_NAME.to_string(),
3187            VirtualLibraryModule {
3188                exports: LibraryExports {
3189                    values,
3190                    types,
3191                    classes,
3192                },
3193                decls: Vec::new(),
3194                source: None,
3195            },
3196        );
3197        Ok(())
3198    }
3199
3200    pub(crate) fn virtual_library_exports(&self, library_name: &str) -> Option<LibraryExports> {
3201        self.virtual_libraries
3202            .get(library_name)
3203            .map(|module| module.exports.clone())
3204    }
3205
3206    fn register_prelude_typeclass_instances(&mut self) -> Result<(), EngineError> {
3207        // The type system prelude injects the *heads* of the standard instances.
3208        // The evaluator also needs the *method bodies* so class method lookup can
3209        // produce actual values at runtime.
3210        let program =
3211            rexlang_typesystem::prelude_typeclasses_program().map_err(EngineError::Type)?;
3212        for decl in program.decls.iter() {
3213            let Decl::Instance(inst_decl) = decl else {
3214                continue;
3215            };
3216            if inst_decl.methods.is_empty() {
3217                continue;
3218            }
3219            let prepared = self
3220                .type_system
3221                .prepare_instance_decl(inst_decl)
3222                .map_err(EngineError::Type)?;
3223            self.register_typeclass_instance(inst_decl, &prepared)?;
3224        }
3225        Ok(())
3226    }
3227
3228    fn register_native(
3229        &mut self,
3230        name: Symbol,
3231        scheme: Scheme,
3232        arity: usize,
3233        func: NativeCallable<State>,
3234        gas_cost: u64,
3235    ) -> Result<(), EngineError> {
3236        let expected = type_arity(&scheme.typ);
3237        if expected != arity {
3238            return Err(EngineError::NativeArity {
3239                name: name.clone(),
3240                expected,
3241                got: arity,
3242            });
3243        }
3244        self.register_type_scheme(&name, &scheme)?;
3245        self.natives.insert(name, arity, scheme, func, gas_cost)
3246    }
3247
3248    fn register_type_scheme(
3249        &mut self,
3250        name: &Symbol,
3251        injected: &Scheme,
3252    ) -> Result<(), EngineError> {
3253        let schemes = self.type_system.env.lookup(name);
3254        match schemes {
3255            None => {
3256                self.type_system.add_value(name.as_ref(), injected.clone());
3257                Ok(())
3258            }
3259            Some(schemes) => {
3260                let has_poly = schemes
3261                    .iter()
3262                    .any(|s| !s.vars.is_empty() || !s.preds.is_empty());
3263                if has_poly {
3264                    for existing in schemes {
3265                        if scheme_accepts(&self.type_system, existing, &injected.typ)? {
3266                            return Ok(());
3267                        }
3268                    }
3269                    Err(EngineError::InvalidInjection {
3270                        name: name.clone(),
3271                        typ: injected.typ.to_string(),
3272                    })
3273                } else {
3274                    if schemes.iter().any(|s| s == injected) {
3275                        return Ok(());
3276                    }
3277                    self.type_system
3278                        .add_overload(name.as_ref(), injected.clone());
3279                    Ok(())
3280                }
3281            }
3282        }
3283    }
3284
3285    pub(crate) fn infer_type(
3286        &mut self,
3287        expr: &Expr,
3288        gas: &mut GasMeter,
3289    ) -> Result<(Vec<Predicate>, Type), EngineError> {
3290        infer_with_gas(&mut self.type_system, expr, gas).map_err(EngineError::Type)
3291    }
3292
3293    fn type_check_expr(&mut self, expr: &Expr) -> Result<TypedExpr, EngineError> {
3294        type_check_engine(self, expr)
3295    }
3296
3297    fn check_natives(&self, expr: &TypedExpr) -> Result<(), EngineError> {
3298        check_natives_in_engine(self, expr)
3299    }
3300
3301    fn register_typeclass_instance(
3302        &mut self,
3303        decl: &InstanceDecl,
3304        prepared: &PreparedInstanceDecl,
3305    ) -> Result<(), EngineError> {
3306        let mut methods: HashMap<Symbol, Arc<TypedExpr>> = HashMap::new();
3307        for method in &decl.methods {
3308            let typed = self
3309                .type_system
3310                .typecheck_instance_method(prepared, method)
3311                .map_err(EngineError::Type)?;
3312            self.check_natives(&typed)?;
3313            methods.insert(method.name.clone(), Arc::new(typed));
3314        }
3315
3316        self.typeclasses.insert(
3317            prepared.class.clone(),
3318            prepared.head.clone(),
3319            self.env.clone(),
3320            methods,
3321        )?;
3322        Ok(())
3323    }
3324
3325    pub(crate) fn lookup_scheme(&self, name: &Symbol) -> Result<Scheme, EngineError> {
3326        let schemes = self
3327            .type_system
3328            .env
3329            .lookup(name)
3330            .ok_or_else(|| EngineError::UnknownVar(name.clone()))?;
3331        if schemes.len() != 1 {
3332            return Err(EngineError::AmbiguousOverload { name: name.clone() });
3333        }
3334        Ok(schemes[0].clone())
3335    }
3336}
3337
3338pub(crate) fn type_check_engine<State>(
3339    engine: &mut Engine<State>,
3340    expr: &Expr,
3341) -> Result<TypedExpr, EngineError>
3342where
3343    State: Clone + Send + Sync + 'static,
3344{
3345    if let Some(span) = first_hole_span(expr) {
3346        return Err(EngineError::Type(TypeError::Spanned {
3347            span,
3348            error: Box::new(TypeError::UnsupportedExpr(
3349                "typed hole `?` must be filled before evaluation",
3350            )),
3351        }));
3352    }
3353    let (typed, preds, _ty) = infer_typed(&mut engine.type_system, expr)?;
3354    let (typed, preds) = default_ambiguous_types(engine, typed, preds)?;
3355    check_predicates_in_engine(engine, &preds)?;
3356    check_natives_in_engine(engine, &typed)?;
3357    Ok(typed)
3358}
3359
3360fn check_predicates_in_engine<State>(
3361    engine: &Engine<State>,
3362    preds: &[Predicate],
3363) -> Result<(), EngineError>
3364where
3365    State: Clone + Send + Sync + 'static,
3366{
3367    for pred in preds {
3368        if pred.typ.ftv().is_empty() {
3369            let ok = entails(&engine.type_system.classes, &[], pred)?;
3370            if !ok {
3371                return Err(EngineError::Type(TypeError::NoInstance(
3372                    pred.class.clone(),
3373                    pred.typ.to_string(),
3374                )));
3375            }
3376        }
3377    }
3378    Ok(())
3379}
3380
3381fn check_natives_in_engine<State>(
3382    engine: &Engine<State>,
3383    expr: &TypedExpr,
3384) -> Result<(), EngineError>
3385where
3386    State: Clone + Send + Sync + 'static,
3387{
3388    enum Frame<'b> {
3389        Expr(&'b TypedExpr),
3390        Push(Symbol),
3391        PushMany(Vec<Symbol>),
3392        Pop(usize),
3393    }
3394
3395    let mut bound: Vec<Symbol> = Vec::new();
3396    let mut stack = vec![Frame::Expr(expr)];
3397    while let Some(frame) = stack.pop() {
3398        match frame {
3399            Frame::Expr(expr) => match &expr.kind {
3400                TypedExprKind::Var { name, overloads } => {
3401                    if bound.iter().any(|n| n == name) {
3402                        continue;
3403                    }
3404                    if !engine.natives.has_name(name) {
3405                        if engine.env.get(name).is_some() {
3406                            continue;
3407                        }
3408                        if engine.type_system.class_methods.contains_key(name) {
3409                            continue;
3410                        }
3411                        return Err(EngineError::UnknownVar(name.clone()));
3412                    }
3413                    if !overloads.is_empty()
3414                        && expr.typ.ftv().is_empty()
3415                        && !overloads.iter().any(|t| unify(t, &expr.typ).is_ok())
3416                    {
3417                        return Err(EngineError::MissingImpl {
3418                            name: name.clone(),
3419                            typ: expr.typ.to_string(),
3420                        });
3421                    }
3422                    if expr.typ.ftv().is_empty()
3423                        && !has_native_impl_in_engine(engine, name, &expr.typ)
3424                    {
3425                        return Err(EngineError::MissingImpl {
3426                            name: name.clone(),
3427                            typ: expr.typ.to_string(),
3428                        });
3429                    }
3430                }
3431                TypedExprKind::Tuple(elems) | TypedExprKind::List(elems) => {
3432                    for elem in elems.iter().rev() {
3433                        stack.push(Frame::Expr(elem));
3434                    }
3435                }
3436                TypedExprKind::Dict(kvs) => {
3437                    for v in kvs.values().rev() {
3438                        stack.push(Frame::Expr(v));
3439                    }
3440                }
3441                TypedExprKind::RecordUpdate { base, updates } => {
3442                    for v in updates.values().rev() {
3443                        stack.push(Frame::Expr(v));
3444                    }
3445                    stack.push(Frame::Expr(base));
3446                }
3447                TypedExprKind::App(f, x) => {
3448                    stack.push(Frame::Expr(x));
3449                    stack.push(Frame::Expr(f));
3450                }
3451                TypedExprKind::Project { expr, .. } => stack.push(Frame::Expr(expr)),
3452                TypedExprKind::Lam { param, body } => {
3453                    stack.push(Frame::Pop(1));
3454                    stack.push(Frame::Expr(body));
3455                    stack.push(Frame::Push(param.clone()));
3456                }
3457                TypedExprKind::Let { name, def, body } => {
3458                    stack.push(Frame::Pop(1));
3459                    stack.push(Frame::Expr(body));
3460                    stack.push(Frame::Push(name.clone()));
3461                    stack.push(Frame::Expr(def));
3462                }
3463                TypedExprKind::LetRec { bindings, body } => {
3464                    if !bindings.is_empty() {
3465                        stack.push(Frame::Pop(bindings.len()));
3466                        stack.push(Frame::Expr(body));
3467                        for (_, def) in bindings.iter().rev() {
3468                            stack.push(Frame::Expr(def));
3469                        }
3470                        stack.push(Frame::PushMany(
3471                            bindings.iter().map(|(name, _)| name.clone()).collect(),
3472                        ));
3473                    } else {
3474                        stack.push(Frame::Expr(body));
3475                    }
3476                }
3477                TypedExprKind::Ite {
3478                    cond,
3479                    then_expr,
3480                    else_expr,
3481                } => {
3482                    stack.push(Frame::Expr(else_expr));
3483                    stack.push(Frame::Expr(then_expr));
3484                    stack.push(Frame::Expr(cond));
3485                }
3486                TypedExprKind::Match { scrutinee, arms } => {
3487                    for (pat, arm_expr) in arms.iter().rev() {
3488                        let mut bindings = Vec::new();
3489                        collect_pattern_bindings(pat, &mut bindings);
3490                        let count = bindings.len();
3491                        if count != 0 {
3492                            stack.push(Frame::Pop(count));
3493                            stack.push(Frame::Expr(arm_expr));
3494                            stack.push(Frame::PushMany(bindings));
3495                        } else {
3496                            stack.push(Frame::Expr(arm_expr));
3497                        }
3498                    }
3499                    stack.push(Frame::Expr(scrutinee));
3500                }
3501                TypedExprKind::Bool(..)
3502                | TypedExprKind::Uint(..)
3503                | TypedExprKind::Int(..)
3504                | TypedExprKind::Float(..)
3505                | TypedExprKind::String(..)
3506                | TypedExprKind::Uuid(..)
3507                | TypedExprKind::DateTime(..) => {}
3508                TypedExprKind::Hole => return Err(EngineError::UnsupportedExpr),
3509            },
3510            Frame::Push(sym) => bound.push(sym),
3511            Frame::PushMany(syms) => bound.extend(syms),
3512            Frame::Pop(count) => bound.truncate(bound.len().saturating_sub(count)),
3513        }
3514    }
3515    Ok(())
3516}
3517
3518fn has_native_impl_in_engine<State>(engine: &Engine<State>, name: &str, typ: &Type) -> bool
3519where
3520    State: Clone + Send + Sync + 'static,
3521{
3522    let sym_name = sym(name);
3523    engine
3524        .natives
3525        .get(&sym_name)
3526        .map(|impls| impls.iter().any(|imp| impl_matches_type(imp, typ)))
3527        .unwrap_or(false)
3528}
3529
3530impl<State> RuntimeSnapshot<State>
3531where
3532    State: Clone + Send + Sync + 'static,
3533{
3534    fn native_callable(&self, id: NativeId) -> Result<NativeCallable<State>, EngineError> {
3535        self.natives
3536            .by_id(id)
3537            .map(|imp| imp.func.clone())
3538            .ok_or_else(|| EngineError::Internal(format!("unknown native id: {id}")))
3539    }
3540}
3541
3542fn first_hole_span(expr: &Expr) -> Option<Span> {
3543    match expr {
3544        Expr::Hole(span) => Some(*span),
3545        Expr::App(_, f, x) => first_hole_span(f).or_else(|| first_hole_span(x)),
3546        Expr::Project(_, base, _) => first_hole_span(base),
3547        Expr::Lam(_, _scope, _param, _ann, _constraints, body) => first_hole_span(body),
3548        Expr::Let(_, _var, _ann, def, body) => {
3549            first_hole_span(def).or_else(|| first_hole_span(body))
3550        }
3551        Expr::LetRec(_, bindings, body) => {
3552            for (_var, _ann, def) in bindings {
3553                if let Some(span) = first_hole_span(def) {
3554                    return Some(span);
3555                }
3556            }
3557            first_hole_span(body)
3558        }
3559        Expr::Ite(_, cond, then_expr, else_expr) => first_hole_span(cond)
3560            .or_else(|| first_hole_span(then_expr))
3561            .or_else(|| first_hole_span(else_expr)),
3562        Expr::Match(_, scrutinee, arms) => {
3563            if let Some(span) = first_hole_span(scrutinee) {
3564                return Some(span);
3565            }
3566            for (_pat, arm) in arms {
3567                if let Some(span) = first_hole_span(arm) {
3568                    return Some(span);
3569                }
3570            }
3571            None
3572        }
3573        Expr::Ann(_, inner, _) => first_hole_span(inner),
3574        Expr::Tuple(_, elems) | Expr::List(_, elems) => {
3575            for elem in elems {
3576                if let Some(span) = first_hole_span(elem) {
3577                    return Some(span);
3578                }
3579            }
3580            None
3581        }
3582        Expr::Dict(_, kvs) => {
3583            for value in kvs.values() {
3584                if let Some(span) = first_hole_span(value) {
3585                    return Some(span);
3586                }
3587            }
3588            None
3589        }
3590        Expr::RecordUpdate(_, base, kvs) => {
3591            if let Some(span) = first_hole_span(base) {
3592                return Some(span);
3593            }
3594            for value in kvs.values() {
3595                if let Some(span) = first_hole_span(value) {
3596                    return Some(span);
3597                }
3598            }
3599            None
3600        }
3601        Expr::Bool(..)
3602        | Expr::Uint(..)
3603        | Expr::Int(..)
3604        | Expr::Float(..)
3605        | Expr::String(..)
3606        | Expr::Uuid(..)
3607        | Expr::DateTime(..)
3608        | Expr::Var(..) => None,
3609    }
3610}
3611
3612fn normalize_name(name: &str) -> Symbol {
3613    if let Some(stripped) = name.strip_prefix('(').and_then(|s| s.strip_suffix(')')) {
3614        let ok = stripped
3615            .chars()
3616            .all(|c| !c.is_alphanumeric() && c != '_' && !c.is_whitespace());
3617        if ok {
3618            return sym(stripped);
3619        }
3620    }
3621    sym(name)
3622}
3623
3624fn default_ambiguous_types<State: Clone + Send + Sync + 'static>(
3625    engine: &Engine<State>,
3626    typed: TypedExpr,
3627    mut preds: Vec<Predicate>,
3628) -> Result<(TypedExpr, Vec<Predicate>), EngineError> {
3629    let mut candidates = Vec::new();
3630    collect_default_candidates(&typed, &mut candidates);
3631    for ty in [
3632        Type::builtin(BuiltinTypeId::F32),
3633        Type::builtin(BuiltinTypeId::I32),
3634        Type::builtin(BuiltinTypeId::String),
3635    ] {
3636        push_unique_type(&mut candidates, ty);
3637    }
3638
3639    let mut subst = Subst::new_sync();
3640    loop {
3641        let vars: Vec<_> = preds.ftv().into_iter().collect();
3642        let mut progress = false;
3643        for tv in vars {
3644            if subst.get(&tv).is_some() {
3645                continue;
3646            }
3647            let mut relevant = Vec::new();
3648            let mut simple = true;
3649            for pred in &preds {
3650                if pred.typ.ftv().contains(&tv) {
3651                    if !defaultable_class(&pred.class) {
3652                        simple = false;
3653                        break;
3654                    }
3655                    match pred.typ.as_ref() {
3656                        TypeKind::Var(v) if v.id == tv => relevant.push(pred.clone()),
3657                        _ => {
3658                            simple = false;
3659                            break;
3660                        }
3661                    }
3662                }
3663            }
3664            if !simple || relevant.is_empty() {
3665                continue;
3666            }
3667            if let Some(choice) = choose_default_type(engine, &relevant, &candidates)? {
3668                let mut next = Subst::new_sync();
3669                next = next.insert(tv, choice.clone());
3670                preds = preds.apply(&next);
3671                subst = compose_subst(next, subst);
3672                progress = true;
3673            }
3674        }
3675        if !progress {
3676            break;
3677        }
3678    }
3679    Ok((typed.apply(&subst), preds))
3680}
3681
3682fn defaultable_class(class: &Symbol) -> bool {
3683    matches!(
3684        class.as_ref(),
3685        "AdditiveMonoid" | "MultiplicativeMonoid" | "AdditiveGroup" | "Ring" | "Field" | "Integral"
3686    )
3687}
3688
3689fn collect_default_candidates(expr: &TypedExpr, out: &mut Vec<Type>) {
3690    let mut stack: Vec<&TypedExpr> = vec![expr];
3691    while let Some(expr) = stack.pop() {
3692        if expr.typ.ftv().is_empty()
3693            && let TypeKind::Con(tc) = expr.typ.as_ref()
3694            && tc.arity == 0
3695        {
3696            push_unique_type(out, expr.typ.clone());
3697        }
3698
3699        match &expr.kind {
3700            TypedExprKind::Tuple(elems) | TypedExprKind::List(elems) => {
3701                for elem in elems.iter().rev() {
3702                    stack.push(elem);
3703                }
3704            }
3705            TypedExprKind::Dict(kvs) => {
3706                for value in kvs.values().rev() {
3707                    stack.push(value);
3708                }
3709            }
3710            TypedExprKind::RecordUpdate { base, updates } => {
3711                for value in updates.values().rev() {
3712                    stack.push(value);
3713                }
3714                stack.push(base);
3715            }
3716            TypedExprKind::App(f, x) => {
3717                stack.push(x);
3718                stack.push(f);
3719            }
3720            TypedExprKind::Project { expr, .. } => stack.push(expr),
3721            TypedExprKind::Lam { body, .. } => stack.push(body),
3722            TypedExprKind::Let { def, body, .. } => {
3723                stack.push(body);
3724                stack.push(def);
3725            }
3726            TypedExprKind::LetRec { bindings, body } => {
3727                stack.push(body);
3728                for (_, def) in bindings.iter().rev() {
3729                    stack.push(def);
3730                }
3731            }
3732            TypedExprKind::Ite {
3733                cond,
3734                then_expr,
3735                else_expr,
3736            } => {
3737                stack.push(else_expr);
3738                stack.push(then_expr);
3739                stack.push(cond);
3740            }
3741            TypedExprKind::Match { scrutinee, arms } => {
3742                for (_, expr) in arms.iter().rev() {
3743                    stack.push(expr);
3744                }
3745                stack.push(scrutinee);
3746            }
3747            TypedExprKind::Var { .. }
3748            | TypedExprKind::Bool(..)
3749            | TypedExprKind::Uint(..)
3750            | TypedExprKind::Int(..)
3751            | TypedExprKind::Float(..)
3752            | TypedExprKind::String(..)
3753            | TypedExprKind::Uuid(..)
3754            | TypedExprKind::DateTime(..)
3755            | TypedExprKind::Hole => {}
3756        }
3757    }
3758}
3759
3760fn push_unique_type(out: &mut Vec<Type>, typ: Type) {
3761    if !out.iter().any(|t| t == &typ) {
3762        out.push(typ);
3763    }
3764}
3765
3766fn choose_default_type<State: Clone + Send + Sync + 'static>(
3767    engine: &Engine<State>,
3768    preds: &[Predicate],
3769    candidates: &[Type],
3770) -> Result<Option<Type>, EngineError> {
3771    for candidate in candidates {
3772        let mut ok = true;
3773        for pred in preds {
3774            let test = Predicate::new(pred.class.clone(), candidate.clone());
3775            if !entails(&engine.type_system.classes, &[], &test)? {
3776                ok = false;
3777                break;
3778            }
3779        }
3780        if ok {
3781            return Ok(Some(candidate.clone()));
3782        }
3783    }
3784    Ok(None)
3785}
3786
3787fn scheme_accepts(ts: &TypeSystem, scheme: &Scheme, typ: &Type) -> Result<bool, EngineError> {
3788    let mut supply = TypeVarSupply::new();
3789    let (preds, scheme_ty) = instantiate(scheme, &mut supply);
3790    let subst = match unify(&scheme_ty, typ) {
3791        Ok(s) => s,
3792        Err(_) => return Ok(false),
3793    };
3794    let preds = preds.apply(&subst);
3795    for pred in preds {
3796        if pred.typ.ftv().is_empty() {
3797            let ok = entails(&ts.classes, &[], &pred)?;
3798            if !ok {
3799                return Ok(false);
3800            }
3801        }
3802    }
3803    Ok(true)
3804}
3805
3806pub(crate) fn is_function_type(typ: &Type) -> bool {
3807    matches!(typ.as_ref(), TypeKind::Fun(..))
3808}
3809
3810pub(crate) fn collect_pattern_bindings(pat: &Pattern, out: &mut Vec<Symbol>) {
3811    match pat {
3812        Pattern::Wildcard(..) => {}
3813        Pattern::Var(var) => out.push(var.name.clone()),
3814        Pattern::Named(_, _, ps) => {
3815            for p in ps {
3816                collect_pattern_bindings(p, out);
3817            }
3818        }
3819        Pattern::Tuple(_, ps) => {
3820            for p in ps {
3821                collect_pattern_bindings(p, out);
3822            }
3823        }
3824        Pattern::List(_, ps) => {
3825            for p in ps {
3826                collect_pattern_bindings(p, out);
3827            }
3828        }
3829        Pattern::Cons(_, head, tail) => {
3830            collect_pattern_bindings(head, out);
3831            collect_pattern_bindings(tail, out);
3832        }
3833        Pattern::Dict(_, fields) => {
3834            for (_key, pat) in fields {
3835                collect_pattern_bindings(pat, out);
3836            }
3837        }
3838    }
3839}
3840
3841fn type_head_and_args(typ: &Type) -> Result<(Symbol, usize, Vec<Type>), EngineError> {
3842    let mut args = Vec::new();
3843    let mut head = typ;
3844    while let TypeKind::App(f, arg) = head.as_ref() {
3845        args.push(arg.clone());
3846        head = f;
3847    }
3848    args.reverse();
3849
3850    let TypeKind::Con(con) = head.as_ref() else {
3851        return Err(EngineError::Custom(format!(
3852            "cannot build ADT declaration from non-constructor type `{typ}`"
3853        )));
3854    };
3855    if !args.is_empty() && args.len() != con.arity {
3856        return Err(EngineError::Custom(format!(
3857            "constructor `{}` expected {} type arguments but got {} in `{typ}`",
3858            con.name,
3859            con.arity,
3860            args.len()
3861        )));
3862    }
3863    Ok((con.name.clone(), con.arity, args))
3864}
3865
3866fn type_head(typ: &Type) -> Result<Type, EngineError> {
3867    let (name, arity, _args) = type_head_and_args(typ)?;
3868    Ok(Type::con(name.as_ref(), arity))
3869}
3870
3871pub(crate) fn adt_shape(adt: &AdtDecl) -> String {
3872    let param_names: HashMap<_, _> = adt
3873        .params
3874        .iter()
3875        .enumerate()
3876        .map(|(idx, param)| (param.var.id, format!("t{idx}")))
3877        .collect();
3878    let mut variants = adt
3879        .variants
3880        .iter()
3881        .map(|variant| {
3882            let args = variant
3883                .args
3884                .iter()
3885                .map(|arg| normalize_type_for_shape(arg, &param_names))
3886                .collect::<Vec<_>>()
3887                .join(", ");
3888            format!("{}({args})", variant.name)
3889        })
3890        .collect::<Vec<_>>();
3891    variants.sort();
3892    format!("{}[{}]", adt.name, variants.join(" | "))
3893}
3894
3895fn normalize_type_for_shape(typ: &Type, param_names: &HashMap<usize, String>) -> String {
3896    match typ.as_ref() {
3897        TypeKind::Var(tv) => param_names
3898            .get(&tv.id)
3899            .cloned()
3900            .unwrap_or_else(|| format!("v{}", tv.id)),
3901        TypeKind::Con(con) => con.name.to_string(),
3902        TypeKind::App(fun, arg) => format!(
3903            "({} {})",
3904            normalize_type_for_shape(fun, param_names),
3905            normalize_type_for_shape(arg, param_names)
3906        ),
3907        TypeKind::Fun(arg, ret) => format!(
3908            "({} -> {})",
3909            normalize_type_for_shape(arg, param_names),
3910            normalize_type_for_shape(ret, param_names)
3911        ),
3912        TypeKind::Tuple(elems) => format!(
3913            "({})",
3914            elems
3915                .iter()
3916                .map(|elem| normalize_type_for_shape(elem, param_names))
3917                .collect::<Vec<_>>()
3918                .join(", ")
3919        ),
3920        TypeKind::Record(fields) => format!(
3921            "{{{}}}",
3922            fields
3923                .iter()
3924                .map(|(name, typ)| format!(
3925                    "{name}: {}",
3926                    normalize_type_for_shape(typ, param_names)
3927                ))
3928                .collect::<Vec<_>>()
3929                .join(", ")
3930        ),
3931    }
3932}
3933
3934pub(crate) fn adt_shape_eq(left: &AdtDecl, right: &AdtDecl) -> bool {
3935    adt_shape(left) == adt_shape(right)
3936}
3937
3938fn adt_direct_dependencies(adt: &AdtDecl) -> Result<Vec<Type>, EngineError> {
3939    let types = adt
3940        .variants
3941        .iter()
3942        .flat_map(|variant| variant.args.iter().cloned())
3943        .collect::<Vec<_>>();
3944    let deps =
3945        rexlang_typesystem::collect_adts_in_types(types).map_err(collect_adts_error_to_engine)?;
3946    deps.into_iter().map(|typ| type_head(&typ)).collect()
3947}
3948
3949pub(crate) fn order_adt_family(adts: Vec<AdtDecl>) -> Result<Vec<AdtDecl>, EngineError> {
3950    let mut unique = HashMap::new();
3951    for adt in adts {
3952        match unique.get(&adt.name) {
3953            Some(existing) if adt_shape_eq(existing, &adt) => {}
3954            Some(existing) => {
3955                return Err(EngineError::Custom(format!(
3956                    "conflicting ADT family definitions for `{}`: {} vs {}",
3957                    adt.name,
3958                    adt_shape(existing),
3959                    adt_shape(&adt)
3960                )));
3961            }
3962            None => {
3963                unique.insert(adt.name.clone(), adt);
3964            }
3965        }
3966    }
3967
3968    let mut visiting = Vec::<Symbol>::new();
3969    let mut visited = HashSet::<Symbol>::new();
3970    let mut ordered = Vec::<AdtDecl>::new();
3971
3972    fn visit(
3973        name: &Symbol,
3974        unique: &HashMap<Symbol, AdtDecl>,
3975        visiting: &mut Vec<Symbol>,
3976        visited: &mut HashSet<Symbol>,
3977        ordered: &mut Vec<AdtDecl>,
3978    ) -> Result<(), EngineError> {
3979        if visited.contains(name) {
3980            return Ok(());
3981        }
3982        if let Some(idx) = visiting.iter().position(|current| current == name) {
3983            let mut cycle = visiting[idx..]
3984                .iter()
3985                .map(ToString::to_string)
3986                .collect::<Vec<_>>();
3987            cycle.push(name.to_string());
3988            return Err(EngineError::Custom(format!(
3989                "cyclic ADT auto-registration is not supported yet: {}",
3990                cycle.join(" -> ")
3991            )));
3992        }
3993
3994        let adt = unique.get(name).ok_or_else(|| {
3995            EngineError::Internal(format!("missing ADT `{name}` during ordering"))
3996        })?;
3997        visiting.push(name.clone());
3998        for dep in adt_direct_dependencies(adt)? {
3999            let dep_head = type_head(&dep)?;
4000            let TypeKind::Con(dep_con) = dep_head.as_ref() else {
4001                return Err(EngineError::Internal(format!(
4002                    "dependency head for `{name}` was not a constructor"
4003                )));
4004            };
4005            if unique.contains_key(&dep_con.name) {
4006                visit(&dep_con.name, unique, visiting, visited, ordered)?;
4007            }
4008        }
4009        visiting.pop();
4010        visited.insert(name.clone());
4011        ordered.push(adt.clone());
4012        Ok(())
4013    }
4014
4015    let mut names = unique.keys().cloned().collect::<Vec<_>>();
4016    names.sort();
4017    for name in names {
4018        visit(&name, &unique, &mut visiting, &mut visited, &mut ordered)?;
4019    }
4020    Ok(ordered)
4021}
4022
4023fn type_arity(typ: &Type) -> usize {
4024    let mut count = 0;
4025    let mut cur = typ;
4026    while let TypeKind::Fun(_, next) = cur.as_ref() {
4027        count += 1;
4028        cur = next;
4029    }
4030    count
4031}
4032
4033fn split_fun(typ: &Type) -> Option<(Type, Type)> {
4034    match typ.as_ref() {
4035        TypeKind::Fun(a, b) => Some((a.clone(), b.clone())),
4036        _ => None,
4037    }
4038}
4039
4040pub(crate) fn impl_matches_type<State: Clone + Send + Sync + 'static>(
4041    imp: &NativeImpl<State>,
4042    typ: &Type,
4043) -> bool {
4044    let mut supply = TypeVarSupply::new();
4045    let (_preds, scheme_ty) = instantiate(&imp.scheme, &mut supply);
4046    unify(&scheme_ty, typ).is_ok()
4047}
4048
4049pub(crate) fn native_capability_matches_requirement(
4050    capability: &NativeCapability,
4051    requirement: &NativeRequirement,
4052) -> bool {
4053    let mut supply = TypeVarSupply::new();
4054    let (_preds, scheme_ty) = instantiate(&capability.scheme, &mut supply);
4055    capability.name == requirement.name
4056        && capability.arity == type_arity(&requirement.typ)
4057        && unify(&scheme_ty, &requirement.typ).is_ok()
4058}
4059
4060pub(crate) fn class_method_capability_matches_requirement(
4061    capability: &ClassMethodCapability,
4062    requirement: &ClassMethodRequirement,
4063) -> bool {
4064    let mut supply = TypeVarSupply::new();
4065    let (_preds, scheme_ty) = instantiate(&capability.scheme, &mut supply);
4066    capability.name == requirement.name && unify(&scheme_ty, &requirement.typ).is_ok()
4067}
4068
4069fn value_type(heap: &Heap, value: &Value) -> Result<Type, EngineError> {
4070    let pointer_type = |pointer: &Pointer| -> Result<Type, EngineError> {
4071        let value = heap.get(pointer)?;
4072        value_type(heap, value.as_ref())
4073    };
4074
4075    match value {
4076        Value::Bool(..) => Ok(Type::builtin(BuiltinTypeId::Bool)),
4077        Value::U8(..) => Ok(Type::builtin(BuiltinTypeId::U8)),
4078        Value::U16(..) => Ok(Type::builtin(BuiltinTypeId::U16)),
4079        Value::U32(..) => Ok(Type::builtin(BuiltinTypeId::U32)),
4080        Value::U64(..) => Ok(Type::builtin(BuiltinTypeId::U64)),
4081        Value::I8(..) => Ok(Type::builtin(BuiltinTypeId::I8)),
4082        Value::I16(..) => Ok(Type::builtin(BuiltinTypeId::I16)),
4083        Value::I32(..) => Ok(Type::builtin(BuiltinTypeId::I32)),
4084        Value::I64(..) => Ok(Type::builtin(BuiltinTypeId::I64)),
4085        Value::F32(..) => Ok(Type::builtin(BuiltinTypeId::F32)),
4086        Value::F64(..) => Ok(Type::builtin(BuiltinTypeId::F64)),
4087        Value::String(..) => Ok(Type::builtin(BuiltinTypeId::String)),
4088        Value::Uuid(..) => Ok(Type::builtin(BuiltinTypeId::Uuid)),
4089        Value::DateTime(..) => Ok(Type::builtin(BuiltinTypeId::DateTime)),
4090        Value::Tuple(elems) => {
4091            let mut tys = Vec::with_capacity(elems.len());
4092            for elem in elems {
4093                tys.push(pointer_type(elem)?);
4094            }
4095            Ok(Type::tuple(tys))
4096        }
4097        Value::Array(elems) => {
4098            let first = elems
4099                .first()
4100                .ok_or_else(|| EngineError::UnknownType(sym("array")))?;
4101            let elem_ty = pointer_type(first)?;
4102            for elem in elems.iter().skip(1) {
4103                let ty = pointer_type(elem)?;
4104                if ty != elem_ty {
4105                    return Err(EngineError::NativeType {
4106                        expected: elem_ty.to_string(),
4107                        got: ty.to_string(),
4108                    });
4109                }
4110            }
4111            Ok(Type::app(Type::builtin(BuiltinTypeId::Array), elem_ty))
4112        }
4113        Value::Dict(map) => {
4114            let first = map
4115                .values()
4116                .next()
4117                .ok_or_else(|| EngineError::UnknownType(sym("dict")))?;
4118            let elem_ty = pointer_type(first)?;
4119            for val in map.values().skip(1) {
4120                let ty = pointer_type(val)?;
4121                if ty != elem_ty {
4122                    return Err(EngineError::NativeType {
4123                        expected: elem_ty.to_string(),
4124                        got: ty.to_string(),
4125                    });
4126                }
4127            }
4128            Ok(Type::app(Type::builtin(BuiltinTypeId::Dict), elem_ty))
4129        }
4130        Value::Adt(tag, args) if sym_eq(tag, "Some") && args.len() == 1 => {
4131            let inner = pointer_type(&args[0])?;
4132            Ok(Type::app(Type::builtin(BuiltinTypeId::Option), inner))
4133        }
4134        Value::Adt(tag, args) if sym_eq(tag, "None") && args.is_empty() => {
4135            Err(EngineError::UnknownType(sym("option")))
4136        }
4137        Value::Adt(tag, args) if (sym_eq(tag, "Ok") || sym_eq(tag, "Err")) && args.len() == 1 => {
4138            Err(EngineError::UnknownType(sym("result")))
4139        }
4140        Value::Adt(tag, args)
4141            if (sym_eq(tag, "Empty") || sym_eq(tag, "Cons")) && args.len() <= 2 =>
4142        {
4143            let elems = list_to_vec(heap, value)?;
4144            let first = elems
4145                .first()
4146                .ok_or_else(|| EngineError::UnknownType(sym("list")))?;
4147            let elem_ty = pointer_type(first)?;
4148            for elem in elems.iter().skip(1) {
4149                let ty = pointer_type(elem)?;
4150                if ty != elem_ty {
4151                    return Err(EngineError::NativeType {
4152                        expected: elem_ty.to_string(),
4153                        got: ty.to_string(),
4154                    });
4155                }
4156            }
4157            Ok(Type::app(Type::builtin(BuiltinTypeId::List), elem_ty))
4158        }
4159        Value::Adt(tag, _args) => Err(EngineError::UnknownType(tag.clone())),
4160        Value::Uninitialized(..) => Err(EngineError::UnknownType(sym("uninitialized"))),
4161        Value::Closure(..) => Err(EngineError::UnknownType(sym("closure"))),
4162        Value::Native(..) => Err(EngineError::UnknownType(sym("native"))),
4163        Value::Overloaded(..) => Err(EngineError::UnknownType(sym("overloaded"))),
4164    }
4165}
4166
4167fn resolve_arg_type(
4168    heap: &Heap,
4169    arg_type: Option<&Type>,
4170    arg: &Pointer,
4171) -> Result<Type, EngineError> {
4172    let infer_from_value = |ty_hint: Option<&Type>| -> Result<Type, EngineError> {
4173        let value = heap.get(arg)?;
4174        match ty_hint {
4175            Some(ty) => match value_type(heap, value.as_ref()) {
4176                Ok(val_ty) if val_ty.ftv().is_empty() => Ok(val_ty),
4177                _ => Ok(ty.clone()),
4178            },
4179            None => value_type(heap, value.as_ref()),
4180        }
4181    };
4182    match arg_type {
4183        Some(ty) if ty.ftv().is_empty() => Ok(ty.clone()),
4184        Some(ty) => infer_from_value(Some(ty)),
4185        None => infer_from_value(None),
4186    }
4187}
4188
4189pub(crate) fn binary_arg_types(typ: &Type) -> Result<(Type, Type), EngineError> {
4190    let (lhs, rest) = split_fun(typ).ok_or_else(|| EngineError::NativeType {
4191        expected: "binary function".into(),
4192        got: typ.to_string(),
4193    })?;
4194    let (rhs, _res) = split_fun(&rest).ok_or_else(|| EngineError::NativeType {
4195        expected: "binary function".into(),
4196        got: typ.to_string(),
4197    })?;
4198    Ok((lhs, rhs))
4199}
4200
4201fn project_pointer(heap: &Heap, field: &Symbol, pointer: &Pointer) -> Result<Pointer, EngineError> {
4202    let value = heap.get(pointer)?;
4203    if let Ok(index) = field.as_ref().parse::<usize>() {
4204        return match value.as_ref() {
4205            Value::Tuple(items) => {
4206                items
4207                    .get(index)
4208                    .cloned()
4209                    .ok_or_else(|| EngineError::UnknownField {
4210                        field: field.clone(),
4211                        value: "tuple".into(),
4212                    })
4213            }
4214            _ => Err(EngineError::UnknownField {
4215                field: field.clone(),
4216                value: heap.type_name(pointer)?.into(),
4217            }),
4218        };
4219    }
4220    match value.as_ref() {
4221        Value::Adt(_, args) if args.len() == 1 => {
4222            let inner = heap.get(&args[0])?;
4223            match inner.as_ref() {
4224                Value::Dict(map) => {
4225                    map.get(field)
4226                        .cloned()
4227                        .ok_or_else(|| EngineError::UnknownField {
4228                            field: field.clone(),
4229                            value: "record".into(),
4230                        })
4231                }
4232                _ => Err(EngineError::UnknownField {
4233                    field: field.clone(),
4234                    value: heap.type_name(&args[0])?.into(),
4235                }),
4236            }
4237        }
4238        _ => Err(EngineError::UnknownField {
4239            field: field.clone(),
4240            value: heap.type_name(pointer)?.into(),
4241        }),
4242    }
4243}
4244
4245#[async_recursion]
4246pub(crate) async fn eval_typed_expr<State>(
4247    runtime: &RuntimeSnapshot<State>,
4248    env: &Env,
4249    expr: &TypedExpr,
4250    gas: &mut GasMeter,
4251) -> Result<Pointer, EngineError>
4252where
4253    State: Clone + Send + Sync + 'static,
4254{
4255    check_runtime_cancelled(runtime)?;
4256    let mut env = env.clone();
4257    let mut cur = expr;
4258    loop {
4259        check_runtime_cancelled(runtime)?;
4260        match &cur.kind {
4261            TypedExprKind::Let { name, def, body } => {
4262                gas.charge(gas.costs.eval_node)?;
4263                let ptr = eval_typed_expr(runtime, &env, def, gas).await?;
4264                env = env.extend(name.clone(), ptr);
4265                cur = body;
4266            }
4267            _ => break,
4268        }
4269    }
4270
4271    gas.charge(gas.costs.eval_node)?;
4272    match &cur.kind {
4273        TypedExprKind::Bool(v) => runtime.heap.alloc_bool(*v),
4274        TypedExprKind::Uint(v) => alloc_uint_literal_as(runtime, *v, &cur.typ),
4275        TypedExprKind::Int(v) => alloc_int_literal_as(runtime, *v, &cur.typ),
4276        TypedExprKind::Float(v) => runtime.heap.alloc_f32(*v as f32),
4277        TypedExprKind::String(v) => runtime.heap.alloc_string(v.clone()),
4278        TypedExprKind::Uuid(v) => runtime.heap.alloc_uuid(*v),
4279        TypedExprKind::DateTime(v) => runtime.heap.alloc_datetime(*v),
4280        TypedExprKind::Hole => Err(EngineError::UnsupportedExpr),
4281        TypedExprKind::Tuple(elems) => {
4282            let mut values = Vec::with_capacity(elems.len());
4283            for elem in elems {
4284                check_runtime_cancelled(runtime)?;
4285                values.push(eval_typed_expr(runtime, &env, elem, gas).await?);
4286            }
4287            runtime.heap.alloc_tuple(values)
4288        }
4289        TypedExprKind::List(elems) => {
4290            let mut values = Vec::with_capacity(elems.len());
4291            for elem in elems {
4292                check_runtime_cancelled(runtime)?;
4293                values.push(eval_typed_expr(runtime, &env, elem, gas).await?);
4294            }
4295            let mut list = runtime.heap.alloc_adt(sym("Empty"), vec![])?;
4296            for value in values.into_iter().rev() {
4297                list = runtime.heap.alloc_adt(sym("Cons"), vec![value, list])?;
4298            }
4299            Ok(list)
4300        }
4301        TypedExprKind::Dict(kvs) => {
4302            let mut out = BTreeMap::new();
4303            for (k, v) in kvs {
4304                check_runtime_cancelled(runtime)?;
4305                out.insert(k.clone(), eval_typed_expr(runtime, &env, v, gas).await?);
4306            }
4307            runtime.heap.alloc_dict(out)
4308        }
4309        TypedExprKind::RecordUpdate { base, updates } => {
4310            let base_ptr = eval_typed_expr(runtime, &env, base, gas).await?;
4311            let mut update_vals = BTreeMap::new();
4312            for (k, v) in updates {
4313                check_runtime_cancelled(runtime)?;
4314                update_vals.insert(k.clone(), eval_typed_expr(runtime, &env, v, gas).await?);
4315            }
4316
4317            let base_val = runtime.heap.get(&base_ptr)?;
4318            match base_val.as_ref() {
4319                Value::Dict(map) => {
4320                    let mut map = map.clone();
4321                    for (k, v) in update_vals {
4322                        gas.charge(gas.costs.eval_record_update_field)?;
4323                        map.insert(k, v);
4324                    }
4325                    runtime.heap.alloc_dict(map)
4326                }
4327                Value::Adt(tag, args) if args.len() == 1 => {
4328                    let inner = runtime.heap.get(&args[0])?;
4329                    match inner.as_ref() {
4330                        Value::Dict(map) => {
4331                            let mut out = map.clone();
4332                            for (k, v) in update_vals {
4333                                gas.charge(gas.costs.eval_record_update_field)?;
4334                                out.insert(k, v);
4335                            }
4336                            let dict = runtime.heap.alloc_dict(out)?;
4337                            runtime.heap.alloc_adt(tag.clone(), vec![dict])
4338                        }
4339                        _ => Err(EngineError::UnsupportedExpr),
4340                    }
4341                }
4342                _ => Err(EngineError::UnsupportedExpr),
4343            }
4344        }
4345        TypedExprKind::Var { name, .. } => {
4346            if let Some(ptr) = env.get(name) {
4347                let value = runtime.heap.get(&ptr)?;
4348                match value.as_ref() {
4349                    Value::Native(native) if native.arity == 0 && native.applied.is_empty() => {
4350                        native.call_zero(runtime, gas).await
4351                    }
4352                    _ => Ok(ptr),
4353                }
4354            } else if runtime.type_system.class_methods.contains_key(name) {
4355                EvaluatorRef::new(runtime)
4356                    .resolve_class_method(name, &cur.typ, gas)
4357                    .await
4358            } else {
4359                let value =
4360                    EvaluatorRef::new(runtime).resolve_native(name.as_ref(), &cur.typ, gas)?;
4361                match runtime.heap.get(&value)?.as_ref() {
4362                    Value::Native(native) if native.arity == 0 && native.applied.is_empty() => {
4363                        native.call_zero(runtime, gas).await
4364                    }
4365                    _ => Ok(value),
4366                }
4367            }
4368        }
4369        TypedExprKind::App(..) => {
4370            let mut spine: Vec<(Type, &TypedExpr)> = Vec::new();
4371            let mut head = cur;
4372            while let TypedExprKind::App(f, x) = &head.kind {
4373                check_runtime_cancelled(runtime)?;
4374                spine.push((f.typ.clone(), x.as_ref()));
4375                head = f.as_ref();
4376            }
4377            spine.reverse();
4378
4379            let mut func = eval_typed_expr(runtime, &env, head, gas).await?;
4380            for (func_type, arg_expr) in spine {
4381                check_runtime_cancelled(runtime)?;
4382                gas.charge(gas.costs.eval_app_step)?;
4383                let arg = eval_typed_expr(runtime, &env, arg_expr, gas).await?;
4384                func = apply(
4385                    runtime,
4386                    func,
4387                    arg,
4388                    Some(&func_type),
4389                    Some(&arg_expr.typ),
4390                    gas,
4391                )
4392                .await?;
4393            }
4394            Ok(func)
4395        }
4396        TypedExprKind::Project { expr, field } => {
4397            let value = eval_typed_expr(runtime, &env, expr, gas).await?;
4398            project_pointer(&runtime.heap, field, &value)
4399        }
4400        TypedExprKind::Lam { param, body } => {
4401            let param_ty = split_fun(&expr.typ)
4402                .map(|(arg, _)| arg)
4403                .ok_or_else(|| EngineError::NotCallable(expr.typ.to_string()))?;
4404            runtime.heap.alloc_closure(
4405                env.clone(),
4406                param.clone(),
4407                param_ty,
4408                expr.typ.clone(),
4409                Arc::new(body.as_ref().clone()),
4410            )
4411        }
4412        TypedExprKind::LetRec { bindings, body } => {
4413            let mut env_rec = env.clone();
4414            let mut slots = Vec::with_capacity(bindings.len());
4415            for (name, _) in bindings {
4416                let placeholder = runtime.heap.alloc_uninitialized(name.clone())?;
4417                env_rec = env_rec.extend(name.clone(), placeholder);
4418                slots.push(placeholder);
4419            }
4420
4421            for ((_, def), slot) in bindings.iter().zip(slots.iter()) {
4422                check_runtime_cancelled(runtime)?;
4423                gas.charge(gas.costs.eval_node)?;
4424                let def_ptr = eval_typed_expr(runtime, &env_rec, def, gas).await?;
4425                let def_value = runtime.heap.get(&def_ptr)?;
4426                runtime.heap.overwrite(slot, def_value.as_ref().clone())?;
4427            }
4428
4429            eval_typed_expr(runtime, &env_rec, body, gas).await
4430        }
4431        TypedExprKind::Ite {
4432            cond,
4433            then_expr,
4434            else_expr,
4435        } => {
4436            let cond_ptr = eval_typed_expr(runtime, &env, cond, gas).await?;
4437            match runtime.heap.pointer_as_bool(&cond_ptr) {
4438                Ok(true) => eval_typed_expr(runtime, &env, then_expr, gas).await,
4439                Ok(false) => eval_typed_expr(runtime, &env, else_expr, gas).await,
4440                Err(EngineError::NativeType { got, .. }) => Err(EngineError::ExpectedBool(got)),
4441                Err(err) => Err(err),
4442            }
4443        }
4444        TypedExprKind::Match { scrutinee, arms } => {
4445            let value = eval_typed_expr(runtime, &env, scrutinee, gas).await?;
4446            for (pat, expr) in arms {
4447                check_runtime_cancelled(runtime)?;
4448                gas.charge(gas.costs.eval_match_arm)?;
4449                if let Some(bindings) = match_pattern_ptr(&runtime.heap, pat, &value) {
4450                    let env = env.extend_many(bindings);
4451                    return eval_typed_expr(runtime, &env, expr, gas).await;
4452                }
4453            }
4454            Err(EngineError::MatchFailure)
4455        }
4456        TypedExprKind::Let { .. } => {
4457            unreachable!("let chain handled in eval_typed_expr loop")
4458        }
4459    }
4460}
4461
4462#[async_recursion]
4463pub(crate) async fn apply<State>(
4464    runtime: &RuntimeSnapshot<State>,
4465    func: Pointer,
4466    arg: Pointer,
4467    func_type: Option<&Type>,
4468    arg_type: Option<&Type>,
4469    gas: &mut GasMeter,
4470) -> Result<Pointer, EngineError>
4471where
4472    State: Clone + Send + Sync + 'static,
4473{
4474    let func_value = runtime.heap.get(&func)?.as_ref().clone();
4475    match func_value {
4476        Value::Closure(Closure {
4477            env,
4478            param,
4479            param_ty,
4480            typ,
4481            body,
4482        }) => {
4483            let mut subst = Subst::new_sync();
4484            if let Some(expected) = func_type {
4485                let s_fun = unify(&typ, expected).map_err(|_| EngineError::NativeType {
4486                    expected: typ.to_string(),
4487                    got: expected.to_string(),
4488                })?;
4489                subst = compose_subst(s_fun, subst);
4490            }
4491            let actual_ty = resolve_arg_type(&runtime.heap, arg_type, &arg)?;
4492            let param_ty = param_ty.apply(&subst);
4493            let s_arg = unify(&param_ty, &actual_ty).map_err(|_| EngineError::NativeType {
4494                expected: param_ty.to_string(),
4495                got: actual_ty.to_string(),
4496            })?;
4497            subst = compose_subst(s_arg, subst);
4498            let env = env.extend(param, arg);
4499            let body = body.apply(&subst);
4500            eval_typed_expr(runtime, &env, &body, gas).await
4501        }
4502        Value::Native(native) => native.apply(runtime, arg, arg_type, gas).await,
4503        Value::Overloaded(over) => over.apply(runtime, arg, func_type, arg_type, gas).await,
4504        _ => Err(EngineError::NotCallable(
4505            runtime.heap.type_name(&func)?.into(),
4506        )),
4507    }
4508}
4509
4510fn match_pattern_ptr(
4511    heap: &Heap,
4512    pat: &Pattern,
4513    value: &Pointer,
4514) -> Option<HashMap<Symbol, Pointer>> {
4515    match pat {
4516        Pattern::Wildcard(..) => Some(HashMap::new()),
4517        Pattern::Var(var) => {
4518            let mut bindings = HashMap::new();
4519            bindings.insert(var.name.clone(), *value);
4520            Some(bindings)
4521        }
4522        Pattern::Named(_, name, ps) => {
4523            let v = heap.get(value).ok()?;
4524            match v.as_ref() {
4525                Value::Adt(vname, args)
4526                    if vname == &name.to_dotted_symbol() && args.len() == ps.len() =>
4527                {
4528                    match_patterns(heap, ps, args)
4529                }
4530                _ => None,
4531            }
4532        }
4533        Pattern::Tuple(_, ps) => {
4534            let v = heap.get(value).ok()?;
4535            match v.as_ref() {
4536                Value::Tuple(xs) if xs.len() == ps.len() => match_patterns(heap, ps, xs),
4537                _ => None,
4538            }
4539        }
4540        Pattern::List(_, ps) => {
4541            let v = heap.get(value).ok()?;
4542            let values = list_to_vec(heap, v.as_ref()).ok()?;
4543            if values.len() == ps.len() {
4544                match_patterns(heap, ps, &values)
4545            } else {
4546                None
4547            }
4548        }
4549        Pattern::Cons(_, head, tail) => {
4550            let v = heap.get(value).ok()?;
4551            match v.as_ref() {
4552                Value::Adt(tag, args) if sym_eq(tag, "Cons") && args.len() == 2 => {
4553                    let mut left = match_pattern_ptr(heap, head, &args[0])?;
4554                    let right = match_pattern_ptr(heap, tail, &args[1])?;
4555                    left.extend(right);
4556                    Some(left)
4557                }
4558                _ => None,
4559            }
4560        }
4561        Pattern::Dict(_, fields) => {
4562            let v = heap.get(value).ok()?;
4563            match v.as_ref() {
4564                Value::Dict(map) => {
4565                    let mut bindings = HashMap::new();
4566                    for (key, pat) in fields {
4567                        let v = map.get(key)?;
4568                        let sub = match_pattern_ptr(heap, pat, v)?;
4569                        bindings.extend(sub);
4570                    }
4571                    Some(bindings)
4572                }
4573                _ => None,
4574            }
4575        }
4576    }
4577}
4578
4579fn match_patterns(
4580    heap: &Heap,
4581    patterns: &[Pattern],
4582    values: &[Pointer],
4583) -> Option<HashMap<Symbol, Pointer>> {
4584    let mut bindings = HashMap::new();
4585    for (p, v) in patterns.iter().zip(values.iter()) {
4586        let sub = match_pattern_ptr(heap, p, v)?;
4587        bindings.extend(sub);
4588    }
4589    Some(bindings)
4590}