Это старая версия документа!
Эта страница посвящена поиску бага связанного с вызовом функции 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.
