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