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