REPL throws an error when attempting to show a term on LLVM
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
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?
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.
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.
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. :)
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.