diff --git a/crates/ail/tests/typeclass_22b3.rs b/crates/ail/tests/typeclass_22b3.rs index b414219..39d3761 100644 --- a/crates/ail/tests/typeclass_22b3.rs +++ b/crates/ail/tests/typeclass_22b3.rs @@ -304,6 +304,65 @@ fn synthesise_mono_fn_falls_back_to_class_default() { let f = synthesise_mono_fn(&target, &class_def, &instance).expect("synth"); assert_eq!(f.name, "hello#Int"); - assert_eq!(f.params, vec!["_x".to_string()]); + assert_eq!( + f.params.len(), + 1, + "default-fallback Lam carries 1 param: {:?}", + f.params + ); assert!(matches!(&f.body, Term::Lit { .. }), "body = {:?}", f.body); } + +/// Zero-arg method (no positional params): body is used verbatim +/// without Lam-unwrapping. Class `Foo a where bar : Int` (note: no +/// arrow — the method is a constant), instance `Foo Int where bar +/// = 7`. synthesise_mono_fn must produce +/// `FnDef { name: "bar#Int", ty: Int, params: [], body: Lit 7 }`. +#[test] +fn synthesise_mono_fn_zero_arg_method_uses_body_verbatim() { + use ailang_check::mono::{synthesise_mono_fn, MonoTarget}; + use ailang_core::ast::{ClassDef, ClassMethod, InstanceDef, InstanceMethod, Literal, Term}; + + let class_def = ClassDef { + name: "Foo".into(), + param: "a".into(), + superclass: None, + methods: vec![ClassMethod { + name: "bar".into(), + // Zero-arg method: ty is the value type directly, not a Type::Fn. + ty: Type::int(), + default: None, + }], + doc: None, + }; + let instance = InstanceDef { + class: "Foo".into(), + type_: Type::int(), + methods: vec![InstanceMethod { + name: "bar".into(), + // Body is a value directly — no Lam wrapper. + body: Term::Lit { + lit: Literal::Int { value: 7 }, + }, + }], + doc: None, + }; + let target = MonoTarget { + class: "Foo".into(), + method: "bar".into(), + type_: Type::int(), + defining_module: "m".into(), + }; + + let f = synthesise_mono_fn(&target, &class_def, &instance).expect("synth"); + assert_eq!(f.name, "bar#Int"); + assert!( + f.params.is_empty(), + "zero-arg method must produce empty params" + ); + assert!( + matches!(&f.body, Term::Lit { lit: Literal::Int { value: 7 } }), + "body must be the verbatim Lit, got {:?}", + f.body + ); +} diff --git a/crates/ailang-check/src/mono.rs b/crates/ailang-check/src/mono.rs index d5d899e..34d593b 100644 --- a/crates/ailang-check/src/mono.rs +++ b/crates/ailang-check/src/mono.rs @@ -359,7 +359,6 @@ pub fn synthesise_mono_fn( Type::Fn { params, .. } if !params.is_empty() ); let (params, body): (Vec, Term) = if method_has_params { - // Method has positional params — body must be a Lam. match body_term { Term::Lam { params, body, .. } => (params, *body), other => { @@ -371,7 +370,6 @@ pub fn synthesise_mono_fn( } } } else { - // Zero-arg method — body is the value directly. (Vec::new(), body_term) };