lower: 제네릭 인스턴스와 메서드

모노모피제이션이 실제로 코드를 만드는 자리가 여기다. 프론트엔드는 어떤
인스턴스가 존재하는지만 정했다. 검사기가 인스턴스마다 선언·바인딩·유닛·링크
이름을 기록하고, lowering 이 그 바인딩을 다시 걸고 같은 본문을 자기 이름으로
내린다. 제네릭 선언 자체는 코드가 없다.

comptime 인자는 값이 아니므로 호출에서 넘기지 않고 파라미터 자리도 잡지
않는다. 메서드 호출은 도달한 대상을 첫 인자로 넘긴다 -- self: Self 든
self: &Self 든 수신자의 주소로 같다. 구조체 메서드가 아예 lowering 되지
않고 있었다.

exec.py 13/13.
This commit is contained in:
2026-08-17 06:26:20 +09:00
parent eba6f63530
commit 231c7d564b
4 changed files with 157 additions and 19 deletions
+46 -10
View File
@@ -464,12 +464,14 @@ static void pop_bindings(FeCheck *c, const FeBindSave *save);
static void bind_self(FeCheck *c, FeType *owner);
static void instance_key(char *out, const char *unit, const char *name,
FeType **args, unsigned count);
static int instance_record(FeCheck *c, const char *key, FeLoc loc);
static int instance_record(FeCheck *c, const char *key, FeLoc loc,
FeNode *decl, FeUnit *home, FeType *owner);
static const char *instance_cname(FeCheck *c, const char *key);
static int instance_descend(FeCheck *c, FeLoc loc);
static void instantiate_body(FeCheck *c, FeUnit *home, FeNode *decl,
FeType *owner, FeBindSave *bindings, FeLoc site);
static void check_instance_method(FeCheckerState *s, FeType *owner,
FeNode *method, FeLoc site);
FeNode *method, FeLoc site, FeNode *call);
typedef struct FeFlowSlot {
FeSym *sym;
@@ -1318,7 +1320,7 @@ static FeType *check_expr_core(FeCheckerState *s, FeNode *n)
fe_type_intern(&c->types,"void");
if (bound) {
pop_bindings(c,&msave);
check_instance_method(s,et,method,n->loc);
check_instance_method(s,et,method,n->loc,n);
}
return n->sem_type;
}
@@ -2249,6 +2251,14 @@ static void instance_key(char *out, const char *unit, const char *name,
/* Already built, or being built right now. Re-asking for a pending instance is
how a recursive generic terminates, so it must not look like a new one. */
static const char *instance_cname(FeCheck *c, const char *key)
{
unsigned i;
for (i=0;i<c->instance_count;++i)
if (!strcmp(c->instances[i].key,key)) return c->instances[i].cname;
return 0;
}
static int instance_known(FeCheck *c, const char *key)
{
unsigned i;
@@ -2257,14 +2267,27 @@ static int instance_known(FeCheck *c, const char *key)
return 0;
}
static int instance_record(FeCheck *c, const char *key, FeLoc loc)
static int instance_record(FeCheck *c, const char *key, FeLoc loc,
FeNode *decl, FeUnit *home, FeType *owner)
{
FeInstance *inst;
unsigned i;
if (instance_known(c,key)) return 0;
if (c->instance_count>=FE_GENERIC_INSTANCE_MAX) {
err(c,loc,"too many generic instances");
return -1;
}
strcpy(c->instances[c->instance_count].key,key);
inst=&c->instances[c->instance_count];
strcpy(inst->key,key);
inst->decl=decl;
inst->home=home ? home->name : 0;
inst->owner=owner;
inst->cname=unit_cname(c,key);
/* The bindings in force right now are the ones this instance was built
with, and lowering has to see exactly those again. */
inst->bind_count=c->types.param_count;
for (i=0;i<c->types.param_count && i<FE_TYPE_PARAM_MAX;++i)
inst->binds[i]=c->types.params[i];
++c->instance_count;
return 1;
}
@@ -2357,7 +2380,7 @@ static FeType *instantiate_struct(FeCheck *c, FeUnit *home, const char *name,
return unknown(c);
}
instance_key(key,home->name,name,args,count);
if (instance_record(c,key,loc)<0) return unknown(c);
if (instance_record(c,key,loc,decl,home,0)<0) return unknown(c);
return build_struct_instance(c,home,decl,key,args,count);
}
@@ -2537,8 +2560,10 @@ static FeType *check_generic_call(FeCheckerState *s, FeNode *n, FeSym *sym,
instance_key(key,home->name,decl->text,args,want);
push_bindings(c,&save,decl,args,want);
result=check_call_args(s,n,sym,home->name,want);
fresh=instance_record(c,key,n->loc,decl,home,0);
pop_bindings(c,&save);
fresh=instance_record(c,key,n->loc);
/* The call goes to this instance, not to the declaration it came from. */
if (n->a) n->a->cname=(char *)instance_cname(c,key);
if (fresh>0) {
if (!instance_descend(c,n->loc)) return result;
push_bindings(c,&save,decl,args,want);
@@ -2572,8 +2597,9 @@ static FeType *check_static_method_call(FeCheckerState *s, FeNode *n,
push_instance_bindings(c,&save,owner);
bind_self(c,owner);
result=check_call_args(s,n,&fake,home->name,0);
fresh=instance_record(c,key,n->loc,method,home,owner);
pop_bindings(c,&save);
fresh=instance_record(c,key,n->loc);
if (n->a) n->a->cname=(char *)instance_cname(c,key);
if (fresh>0) {
if (!instance_descend(c,n->loc)) return result;
push_instance_bindings(c,&save,owner);
@@ -2587,7 +2613,7 @@ static FeType *check_static_method_call(FeCheckerState *s, FeNode *n,
/* The body of a method on a generic instance, checked once per instance. */
static void check_instance_method(FeCheckerState *s, FeType *owner,
FeNode *method, FeLoc site)
FeNode *method, FeLoc site, FeNode *call)
{
FeCheck *c=s->c;
FeUnit *home=current_unit(c);
@@ -2596,7 +2622,17 @@ static void check_instance_method(FeCheckerState *s, FeType *owner,
FeType *self_args[1];
self_args[0]=owner;
instance_key(key,home->name,method->text,self_args,1);
if (instance_record(c,key,site)<=0) return;
{
FeBindSave probe;
int fresh;
push_instance_bindings(c,&probe,owner);
bind_self(c,owner);
fresh=instance_record(c,key,site,method,home,owner);
pop_bindings(c,&probe);
/* The call names this instance's copy of the method. */
if (call && call->a) call->a->cname=(char *)instance_cname(c,key);
if (fresh<=0) return;
}
if (!instance_descend(c,site)) return;
push_instance_bindings(c,&save,owner);
bind_self(c,owner);