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