effekt-lang / effekt

A language with lexical effect handlers and lightweight effect polymorphism
https://effekt-lang.org
MIT License
334 stars 24 forks source link

Fix buggy LLVM tests #568

Closed marvinborner closed 2 months ago

marvinborner commented 2 months ago

This is an ongoing effort to fix some of the broken LLVM tests.

Already fixed:

For better diagnosing and a more reliable RTS overall, I also enabled and fixed GCC warnings.


Also, I believe there's a bug in polymorphism boxing:

interface Eff[A] {
    def eff(a: A): Unit
}

def foo { f: [A](A) => A / Eff[A] }: Unit =
    try {
        f(42)
        ()
    } with Eff[Int] {
        def eff(a) = println(a)
    }

def main() = {
    foo { [T](x: T) =>
        do eff(x)
        x
    }
}

This generates a function invocation

musttail call tailcc void %functionPointer_62(%Object %closure_60, i64 %evidenceZero_3523, %Pos %pureApp_3524, %Stack %stack_14)

where functionPointer_62 is actually a reference to

define tailcc void @Eff$capability4_3495_clause_15(%Object %closure, i64 %ev3506_3506, i64 %a7_3500, %Stack %stack) {

(note the third argument boxed int %Pos vs i64)

Maybe @marzipankaiser can help?

marzipankaiser commented 2 months ago

After PolymorphismBoxing, the above is:

interface Eff2384[A2383] {
  eff2390: (A2383) => Unit374
}

def foo2387(){f2386} =
  try { (){Eff$capability3800} => 
    val v_coe_34833801: BoxedInt283 = f2386[BoxedInt283](boxInt285(42), Eff$capability3800);
    unboxInt287(v_coe_34833801);
    ()
  } with Eff2384[Int378] {
    def eff2390(a2391: Int378){resume2392} = 
      println6(a2391)
  };
def main2388() =
  foo2387({ [T2393](x2394: T2393){Eff$capability3802} => 
    Eff$capability3802.eff(x2394);
    x2394
  })

Where the parameter a is incorrectly annotated / not transformed. This would need to be fixed somewhere here, I think: https://github.com/effekt-lang/effekt/blob/458fc9cb0cfbeed87fd98273cc5e23414ad5f0c7/effekt/shared/src/main/scala/effekt/core/PolymorphismBoxing.scala#L226-L240 by making sure that blockType is the actual (polymorphic) type of the operation in the interface (which we'd probably need to look up at the definition via a DeclarationContext / the PContext)

marvinborner commented 2 months ago

Remaining bugs:

// leaks cons
def main() = { [1,2,3].map { a => println(a) }; () }

// array is never freed
def main() = { allocate(5000); () }
marvinborner commented 2 months ago

I think we can merge this for now and work on the remaining issues later.

b-studios commented 2 months ago

I guess a few splices are missing, hence the errors (the LLVM backend now also properly splices parameters).

marvinborner commented 2 months ago

Only one, I just chose the wrong version during merging.