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