Skip to main content

monomorphize_generic_method/
monomorphize_generic_method.rs

1//! End-to-end demonstration that monomorphization makes trait method
2//! calls inside generic function bodies resolve.
3//!
4//! Without monomorphization, `x.double()` inside
5//! `fn use_doubler<T: Doubler>(x: T) -> i64` cannot resolve at
6//! compile time because `x`'s type is the abstract type parameter
7//! `T`. The monomorphization pass walks the call graph from `main`,
8//! infers `T = i64` from the call `use_doubler(21)`, and generates
9//! `use_doubler__i64` as a specialization with `T` replaced by `i64`
10//! throughout. Inside the specialization, `x: i64` is concrete and
11//! `x.double()` resolves to `Doubler::i64::double`.
12//!
13//! Run with: `cargo run --example monomorphize_generic_method`
14
15use keleusma::compiler::compile;
16use keleusma::lexer::tokenize;
17use keleusma::parser::parse;
18use keleusma::vm::{DEFAULT_ARENA_CAPACITY, Vm, VmState};
19use keleusma::{Arena, Value};
20
21fn main() {
22    let src = r#"
23        trait Doubler { fn double(x: i64) -> i64; }
24        impl Doubler for i64 { fn double(x: i64) -> i64 { x + x } }
25        fn use_doubler<T: Doubler>(x: T) -> i64 { x.double() }
26        fn main() -> i64 { use_doubler(21) }
27    "#;
28    let tokens = tokenize(src).expect("lex");
29    let program = parse(&tokens).expect("parse");
30    let module = compile(&program).expect("compile");
31    let arena = Arena::with_capacity(DEFAULT_ARENA_CAPACITY);
32    let mut vm = Vm::new(module, &arena).expect("verify");
33    match vm.call(&[]) {
34        Ok(VmState::Finished(Value::Int(n))) => {
35            println!("use_doubler(21) = {}", n);
36            assert_eq!(n, 42);
37            println!("monomorphization-driven method dispatch executed end to end");
38        }
39        other => panic!("unexpected: {:?}", other),
40    }
41}