// #target: macos-x64 module test; import std::io; def FooFn = fn void(Foo* f, int x); struct Foo { FooFn x; } struct FooTest { inline Foo a; } struct FooTest2 { inline Foo a; int z; } fn void Foo.test(Foo* f, int x) { f.x(f, x); } fn void FooTest.init(FooTest* this) { static FooFn foo = foo_fn(FooTest); this.x = foo; } fn void FooTest.high(FooTest* t, int x) { io::printfn("High: %d", x); } fn void FooTest.low(FooTest* t, int x) { io::printfn("Low: %d", x); } fn void FooTest2.init(FooTest2* this, int z) { static FooFn foo = foo_fn(FooTest2); this.x = foo; this.z = z; } fn void FooTest2.high(FooTest2* t, int x) { io::printfn("High2: %d", x * t.z); } fn void FooTest2.low(FooTest2* t, int x) { io::printfn("Low2: %d", x * t.z); } macro FooFn foo_fn($FooType) { return fn void(Foo* f, int x) { $FooType* z = ($FooType*)f; if (x > 0) return z.high(x); return z.low(x); }; } fn int main() { FooTest a; a.init(); a.test(10); a.test(0); a.test(-1); FooTest2 b; b.init(100); b.test(10); b.test(0); b.test(-1); return 0; } /* #expect: test.ll @init.foo = internal unnamed_addr global ptr @"test.$global$lambda1", align 8 @init.foo.2 = internal unnamed_addr global ptr @"test.$global$lambda2", align 8 define void @test.Foo.test(ptr %0, i32 %1) #0 { entry: %2 = getelementptr inbounds %Foo, ptr %0, i32 0, i32 0 %3 = load ptr, ptr %2, align 8 call void %3(ptr %0, i32 %1) ret void } define void @test.FooTest.init(ptr %0) #0 { entry: %1 = getelementptr inbounds %FooTest, ptr %0, i32 0, i32 0 %2 = getelementptr inbounds %Foo, ptr %1, i32 0, i32 0 %3 = load ptr, ptr @init.foo, align 8 store ptr %3, ptr %2, align 8 ret void } define internal void @"test.$global$lambda1"(ptr %0, i32 %1) #0 { entry: %z = alloca ptr, align 8 store ptr %0, ptr %z, align 8 %gt = icmp sgt i32 %1, 0 br i1 %gt, label %if.then, label %if.exit if.then: ; preds = %entry %2 = load ptr, ptr %z, align 8 call void @test.FooTest.high(ptr %2, i32 %1) ret void if.exit: ; preds = %entry %3 = load ptr, ptr %z, align 8 call void @test.FooTest.low(ptr %3, i32 %1) ret void } define internal void @"test.$global$lambda2"(ptr %0, i32 %1) #0 { entry: %z = alloca ptr, align 8 store ptr %0, ptr %z, align 8 %gt = icmp sgt i32 %1, 0 br i1 %gt, label %if.then, label %if.exit if.then: ; preds = %entry %2 = load ptr, ptr %z, align 8 call void @test.FooTest2.high(ptr %2, i32 %1) ret void if.exit: ; preds = %entry %3 = load ptr, ptr %z, align 8 call void @test.FooTest2.low(ptr %3, i32 %1) ret void }