Написал макрос, который типизирует тело вызываемого метода, сравнивает полученный тип с формально описанным и если они не совпадают, то делает даункаст.
public macro Deanon(funCall : PExpr)
syntax ("deanon", funCall) {
ExtendedAnonTypesImpl.Deanon(Macros.ImplicitCTX(), funCall)
}
[ManagerAccess(ManagerClass.Instance)]
module ExtendedAnonTypesImpl{
withType(typer: Typer, expr: PExpr, transform : TExpr -> PExpr, errMsg : string="") : PExpr{
def errText = if(!string.IsNullOrEmpty(errMsg)) errMsg
else $"Can not infer the type of $expr";
def type = typer.TypeExpr(expr);
typer.DelayMacro(lt => match(type.Type.Hint) {
| None when lt => Message.FatalError(expr.Location, errText)
| None => None();
| Some => type |> transform |> Some
});
}
public Deanon(typer : Typer, funCall : PExpr) : PExpr {
Macros.DefineCTX(typer);
def wt = withType(typer, _, _);
def (fname, _) = match(funCall) {
| <[ $f(..$args) ]> => (f, args)
| _ => Message.FatalError(funCall.Location, "Function call expected");
}
def makeCast(callType, t) {
def method = match(t) {
| TExpr.StaticRef(_, method, _) => method;
| TExpr.MethodRef(_, method, _ , _) => method;
| _ => Message.FatalError(t.Location, "Only method call supperted");
}
def methodBuilder = method :> MethodBuilder;
methodBuilder.RunBodyTyper();
def bodyType = methodBuilder.BodyTyped.Type;
if(callType.Type.TryProvide <| bodyType) <[ $funCall ]>
else <[ $funCall :> $(bodyType: typed) ]>
}
wt(funCall, ct => wt(fname, makeCast(ct,_)));
}
}
На словах, то есть с точки зрения интеграции, все отрабатывает
Но при сборке проекта валится с ошибкой
Main.n(26,18): error : AssertionException has occurred when expanding macro 'deanon' confused by earlier errors bailing out
Хотя отладкой студии в студии смотрел — никаких ошибок там не сыпалось. И что делать с подобным ассертом не имею ни малейшего представления. Куда посоветуете копать?
Переписал реализацию макроса
public Deanon(typer : Typer, funCall : PExpr) : PExpr {
Macros.DefineCTX(typer);
def wt = withType(typer, _, _);
def (fname, _) = match(funCall) {
| <[ $f(..$args) ]> => (f, args)
| _ => Message.FatalError(funCall.Location, "Function call expected");
}
def makeCast(callType, t) {
def method = match(t) {
| TExpr.StaticRef(_, method, _) => method;
| TExpr.MethodRef(_, method, _ , _) => method;
| _ => Message.FatalError(t.Location, "Only method call supported");
}
def methodBuilder = method :> MethodBuilder;
def methodTyper = Typer(methodBuilder);
withType(methodTyper, methodBuilder.Body, bt => {
def bodyType = bt.Type;
if(callType.Type.TryRequire <| bodyType) <[ $funCall ]>
else <[ $funCall :> $(bodyType: typed) ]>
});
}
wt(funCall, ct => wt(fname, makeCast(ct,_)));
}
сыпется с ошибкой
{"assertion ``!solver.InUse'' failed in file ncc\\typing\\Typer.n, line 145"}
Подскажите, что же я неправильно делаю? В первом варианте даже корректно раскрывалось все.