effekt icon indicating copy to clipboard operation
effekt copied to clipboard

REPL throws an error when attempting to show a term on LLVM

Open jiribenes opened this issue 1 year ago • 3 comments

Problem

When I put an expression into the REPL, the REPL tries to call println($EXPR) which fails for all non-trivial types since #449:

> type TrafficLight { Red(); Yellow(); Green() }
> Red()
[error] Cannot typecheck call.
There are multiple overloads, which all fail to check:
[...]
Full error
Possible overload: option::println of type Option[Double] => Unit
  Argument count does not match TrafficLight2360 vs. Option593
  Expected type
    Option[Double]
  but got type
    TrafficLight

Possible overload: effekt::println of type String => Unit
  Expected String but got TrafficLight.

Possible overload: effekt::println of type Int => Unit
  Expected Int but got TrafficLight.

Possible overload: array::println of type Array[String] => Unit
  Argument count does not match TrafficLight2360 vs. Array1667
  Expected type
    Array[String]
  but got type
    TrafficLight

Possible overload: option::println of type Option[Bool] => Unit
  Argument count does not match TrafficLight2360 vs. Option593
  Expected Option[Bool] but got TrafficLight.

Possible overload: list::println of type List[Int] => Unit
  Argument count does not match TrafficLight2360 vs. List767
  Expected List[Int] but got TrafficLight.

Possible overload: option::println of type Option[Int] => Unit
  Argument count does not match TrafficLight2360 vs. Option593
  Expected Option[Int] but got TrafficLight.

Possible overload: list::println of type List[Double] => Unit
  Argument count does not match TrafficLight2360 vs. List767
  Expected List[Double] but got TrafficLight.

Possible overload: effekt::println of type Unit => Unit
  Expected Unit but got TrafficLight.

Possible overload: list::println of type List[String] => Unit
  Argument count does not match TrafficLight2360 vs. List767
  Expected List[String] but got TrafficLight.

Possible overload: array::println of type Array[Bool] => Unit
  Argument count does not match TrafficLight2360 vs. Array1667
  Expected Array[Bool] but got TrafficLight.

Possible overload: effekt::println of type Double => Unit
  Expected Double but got TrafficLight.

Possible overload: array::println of type Array[Double] => Unit
  Argument count does not match TrafficLight2360 vs. Array1667
  Expected type
    Array[Double]
  but got type
    TrafficLight

Possible overload: list::println of type List[Bool] => Unit
  Argument count does not match TrafficLight2360 vs. List767
  Expected List[Bool] but got TrafficLight.

Possible overload: effekt::println of type Ordering => Unit
  Expected Ordering but got TrafficLight.

Possible overload: effekt::println of type Bool => Unit
  Expected Bool but got TrafficLight.

Possible overload: array::println of type Array[Int] => Unit
  Argument count does not match TrafficLight2360 vs. Array1667
  Expected Array[Int] but got TrafficLight.

Source

Here's the code in question which just calls println on terms: https://github.com/effekt-lang/effekt/blob/aa897e4f70407d5086d0da093ce04824bf43acee/effekt/jvm/src/main/scala/effekt/Repl.scala#L318-L319

Potential solution

If we don't want to wait for typeclasses #66, we could instead use inspect introduced in #449 because the REPL ~~always runs with the JavaScript backend~~: EDIT: Not true, the REPL runs with the backend of user's choice, see below. The workaround would only work for the JS and Chez backends https://github.com/effekt-lang/effekt/blob/aa897e4f70407d5086d0da093ce04824bf43acee/libraries/common/effekt.effekt#L102-L104

jiribenes avatar May 28 '24 12:05 jiribenes

the REPL always runs with the JavaScript backend:

For debugging I often use different backends in the REPL, e.g. via effekt.sh --backend llvm Am I misunderstanding this?

marvinborner avatar May 28 '24 12:05 marvinborner

Thanks, I took a closer look and invalidated my assumption. The REPL runs for any backend... I'll fix it in the original issue description.

jiribenes avatar May 28 '24 12:05 jiribenes

I propose monomorphization just for inspect.

Add an llvm variant to inspect that crashes.

extern io def inspect[R](value: R): Unit =
  js { println(genericShow(value)) }
  chez { println(genericShow(value)) }
  llvm { @print("should not happen") ret void }

Create a core to core pass that creates special definitions for all types that inspect is used at. For example when we see inspect[TrafficLight](Red()) we change it to inspect_TrafficLight(Red()) and create a top-level definition:

def inspect_TrafficLight(x: TrafficLight) = x match {
  case Red() => println("Red")
  ...
}

For complex types we have to create more definitions.

This will always work for the REPL because a closed program does not contain free type variables.

phischu avatar Oct 23 '24 09:10 phischu

This will always work for the REPL because a closed program does not contain free type variables.

This is not exactly a free type variable, but is a problem nonetheless:

$ effekt --backend js
Welcome to the Effekt interpreter (v0.6.0). Enter a top-level definition, or an expression to evaluate.

> inspect(box { [A](x: A) => x })
(x_1, ks_3, k_3) =>
    () => k_3(x_1, ks_3)

> :t box { [A](x: A) => x }
[A](A) => A at {}

To be fair, I'd be okay with inspect being more of a builtin that just halts the compilation if it gets a boxed function or something with a forall. :)

jiribenes avatar Oct 23 '24 09:10 jiribenes

There is a counter example but this is not it. For functions we could display the generated core code, but I'd rather show <box> or something. A problem are existentials, i.e. inspect[Dynamic](Hidden[Int](5)), but for this corner case I would just display <any> or something.

phischu avatar Oct 23 '24 12:10 phischu