Это старая версия документа!
Эта страница посвящена поиску бага связанного с вызовом функции init в произвольном модуле из другого модуля, в котором используются ссылки на функции.
https://github.com/inferno-os/inferno-os/issues/31
Описание
В коде приведённом ниже есть есть функции empty и init. В init производится попытка вызова функции init из модуля echo (как это происходит в шелле). В случае если раскоментирован блок
#fp:= empty;
или любой из if (0) включен, вызов не срабатывает:
link typecheck Echo->empty() 0/9cd71c5e echo: link typecheck Echo->empty() 0/9cd71c5e
Очевидно, что вместо init вызывается empty, которого в модуле echo нет.
implement Sh93;
include "sys.m";
sys: Sys;
include "draw.m";
Sh93: module
{
init: fn(ctxt: ref Draw->Context, argv: list of string);
};
SomeT: adt {
f: ref fn();
};
empty() {
sys->print("empty\n");
}
init(ctxt: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
#fp:= empty;
if (0)
{
st:= ref SomeT;
st.f = empty;
st.f();
}
file := "echo.dis";
args : list of string;
args = "\"test\"" :: args;
args = "echo" :: args;
c := load Sh93 file;
if(c == nil) {
err := sys->sprint("%r");
if(err != "permission denied" && err != "access permission denied" && file[0]!='/' && file[0:2]!="./"){
c = load Sh93 "/dis/"+file;
if(c == nil) {
err = sys->sprint("%r");
}
}
if(c == nil) {
sys->print("%s: %s\n", "echo", err);
return;
}
}
c->init(ctxt, args);
if (0)
{
st:= ref SomeT;
st.f = empty;
st.f();
}
}
Workaround
Объявление функции в блоке «модуль» помогает решить проблему:
Добавляем empty в декларацию модуля:
Sh93: module
{
init: fn(ctxt: ref Draw->Context, argv: list of string);
empty: fn();
};
Lets check libinterp/link.c. The error manifests itself in linkm proc (thats where «link typecheck» message comes from), for some reason empty is in m→ext array (interp.h / struct Module comment calls m→ext: «External dynamic links») and this loop: [ for(l = m→ext; l→name; l++)](https://github.com/inferno-os/inferno-os/blob/d7b29f497205f48247d2bab33340bd7ace64de4d/libinterp/link.c#L41) iterates over init and empty.
When you add empty to module definition explicitly, then this loop only makes single iteration with init.
Limbo does not have anonymous functions (lambdas) as far as I know, so this issue just leads to inconvenience of declaration of functions you normally would prefer not to declare.
