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