I am trying to create a “visitor” with a context using capabilities:
package io.github.iltotore.cylang.util
trait Visitor[In, Out, Ctx, Err] {
type Result = Either[Err, (Ctx, Out)]
def visitInput(input: In)(using Ctx): Result
class VisitDSL(var context: Ctx)
def visiting(visit: VisitDSL ?=> Out)(using context: Ctx): Result = {
val dsl = VisitDSL(context)
try {
val out = visit(using dsl)
Right((dsl.context, out))
} catch case err => ???
}
def reify(result: Result)(using dsl: VisitDSL): Out = result match {
case Right((ctx, value)) =>
update(ctx)
value
case Left(err) => throw err
}
def visitReify(input: In)(using VisitDSL): Out = reify(visitInput(input))
}
Here is a working minimal implementation :
class ExpressionEvaluator extends Visitor[Expression, Value, Context, EvaluationError] {
override def visitInput(input: Expression)(using context: Context): Result = input match {
case Negation(expression) => visiting {
summon[VisitDSL]
???
}
}
}
But if I use the visitReify
method, I get an error:
class ExpressionEvaluator extends Visitor[Expression, Value, Context, EvaluationError] {
override def visitInput(input: Expression)(using context: Context): Result = input match {
case Negation(expression) => visiting {
visitReify(expression) match { // no implicit argument of type ExpressionEvaluator.this.VisitDSL was found for parameter x$2 of method visitReify in trait Visitor
case Value.Integer(x) => Value.Integer(-x)
case Value.Real(x) => Value.Real(-x)
case _ => ??
}
}
}
}
The weirdest thing being this example which is actually working:
class ExpressionEvaluator extends Visitor[Expression, Value, Context, EvaluationError] {
override def visitInput(input: Expression)(using context: Context): Result = input match {
case Negation(expression) => visiting {
summon[VisitDSL]
visitReify(expression)
}
}
}
Is this behaviour intented ? It seems like a bug between type inference and implicit resolution but the error message doesn’t look accurate.