Open dvdvgt opened 1 week ago
Given that in Phase
, we have
def apply(input: In)(using C: Context): Option[Out] = try {
run(input)
} catch {
case FatalPhaseError(msg) =>
C.report(msg)
None
}
what about we change
-def run(input: In)(using C: Context): Option[Out]
+def run(input: In)(using C: Context): Out // can throw FatalPhaseError using `abort`.
?
The convention then would be to always use abort
to immediately abort execution of a phase without returning a value.
error
is typically used if we eventually abort a phase, but want to collect multiple errors. This mode of usage could also be "formalized" somewhere. In Typer for instance we are using the idiom
if (Context.messaging.hasErrors) {
None
} else {
Some(Typechecked(source, tree, mod))
}
that could be used elsewhere as well.
Namer always seems to use abort
and return Some(NameResolved(source, tree, mod))
, which doesn't give multiple resolved errors. Many of these abort
s could become error
s.
It would be nice to have some agreed upon convention on when to use which kind of error reporting: https://github.com/effekt-lang/effekt/blob/430369f402d78abdc70486ad8d38d54a8cb24060/effekt/shared/src/main/scala/effekt/util/Messages.scala#L115-L134 When should something
abort
? When should somethingpanic
? When to justreport
an error?Related to this, what is the contract of calling a
run
function of phase? Should the caller check whether the previous phase reported an error by check if it returnedNone
and thenabort
/panic
, or rather should each phase (callee) handle their own errors appropriately and in turn do not returnOption[A]
but justA
?