effekt icon indicating copy to clipboard operation
effekt copied to clipboard

Forward references to effect operations aren't supported

Open kyay10 opened this issue 2 months ago • 4 comments

This happens when using an effect (and has a somewhat confusing error message):

def test() = {
  def f: Foo = <>
  f.foo() // Cannot resolve operation foo, called on a receiver that is a computation.
}

interface Foo {
  def foo(): Unit
}

or implementing one:

def test() = {
  val f = new Foo {
    def foo() = <> // Operation foo is not part of interface Foo.
  }
}

interface Foo {
  def foo(): Unit
}

kyay10 avatar Nov 07 '25 20:11 kyay10

In general, Effekt doesn't support forward referencing of declarations (AFAIK it can do so for functions, though only for those with annotated return types).

(EDIT: Also, the latter declaration should also be def f like the former one, computations are bound with def :))


Though I do agree that the second error message could be improved 👀

jiribenes avatar Nov 07 '25 22:11 jiribenes

Oops didn't even notice the val thing. I sometimes wish the compiler would continue accumulating errors, instead of (seemingly) just stopping on the first one, but ik that's a hard problem in general.

kyay10 avatar Nov 07 '25 22:11 kyay10

though only for those with annotated return types

FWIW, Kotlin resolves this by having 2 phases: one where it checks only declarations with implicit return types, and one where it checks all other declarations. That first one just lazily resolves return types, forming an implicit DAG of sorts, and reports cycle detected errors if you try to use the return type of a function whose return type hasn't been resolved yet (because that means that the return type is necessary for that function's resolution). It works okay-enough, although it throws up false positives every now and then

kyay10 avatar Nov 08 '25 16:11 kyay10

I quickly check Namer because of a different issue. We already have two [somewhat ad-hoc] phases in Namer: preresolve and resolve where the former is only used for declarations. So we do pre resolve the interface, just not its methods so that, according to the comment, they can refer to types that aren't defined yet. https://github.com/effekt-lang/effekt/blob/348e4de805c72ecc8bd92b459677d943d563c66e/effekt/shared/src/main/scala/effekt/Namer.scala#L166-L173

(I'm mostly posting this for context for somebody in the future who might want to improve the error / support forward refs completely)

jiribenes avatar Dec 09 '25 11:12 jiribenes