std: map 을 쓴다 -- 바이트 열에서 값으로

컴파일러는 이름을 끊임없이 찾는데 리스트 선형 탐색은 그 모양이 아니다. 키는
맵이 소유하는 한 버퍼에 복사되고 슬롯은 그 안의 어디인지만 적는다 -- R11 이
말하는 아레나와 핸들 모양이고, 그래서 맵을 놓는 것이 엔트리마다 하나가 아니라
두 번의 해제다.

개방 주소법에 선형 탐사. 표는 2의 거듭제곱이라 나눗셈이 아니라 마스크이고,
탐사가 길어지는 것이 표가 차는 것보다 먼저라 3/4 에서 자란다.

길에서 고친 것 넷:

- 인스턴스를 만들 때 선언 유닛으로 전환하지 않아서, 필드 타입 Slot(V) 를
  호출자 유닛에서 찾고 있었다.
- mem.alloc_slice 가 원소 타입으로 단순한 이름만 받았다. Slot(V) 같은
  인스턴스도 받는다.
- 쓸 수 있는지를 바인딩이 아니라 소유된 것이 정한다. let p: ^[]mut T 는 p 를
  고정하고 그것이 소유한 것은 쓸 수 있게 둔다. 슬라이스 인덱스도 마찬가지다.
- 메서드 인자에 자유 함수와 같은 호출 한정 약화가 없었다.

알게 된 것: 대여는 루트 단위라 self 의 한 필드에 쓰는 동안 다른 필드를 읽을 수
없다. 지역으로 빼거나 메서드를 나누면 되지만, 필드 단위 대여가 있으면 훨씬
편할 자리다.

  count 5 / fn 2 let 3 missing 0 / grown 64 / after 40 / balanced

218/218, 28/28.
This commit is contained in:
2026-08-17 12:23:52 +09:00
parent c7cba061b3
commit 8c4e80e246
4 changed files with 265 additions and 9 deletions
+38 -7
View File
@@ -142,9 +142,20 @@ int lvalue_writable(FeCheckerState *s, FeNode *n)
t=n->a ? n->a->sem_type : 0;
if (t && t->kind==FE_TYPE_REF && n->b && n->b->text &&
strcmp(n->b->text,"^")==0) return t->ref_mut;
/* Through an owner, what may be written is decided by what is owned,
not by whether the binding may be pointed somewhere else. `let p:
^[]mut T` fixes p and leaves what it owns writable. */
if (t && t->kind==FE_TYPE_OWNED && n->b && n->b->text &&
strcmp(n->b->text,"^")==0)
return !t->elem || t->elem->kind!=FE_TYPE_SLICE || t->elem->ref_mut;
return lvalue_writable(s,n->a);
}
if (n->kind == FE_N_INDEX) {
/* An index into a slice asks the slice, not the binding. */
t=n->a ? n->a->sem_type : 0;
if (t && t->kind==FE_TYPE_SLICE) return t->ref_mut;
return lvalue_writable(s,n->a);
}
if (n->kind == FE_N_INDEX) return lvalue_writable(s,n->a);
return 0;
}
@@ -440,10 +451,16 @@ FeType *check_expr_core(FeCheckerState *s, FeNode *n)
if (strcmp(n->a->b->text,"alloc_slice")==0) {
FeNode *count=arg ? arg->next : 0;
FeType *item;
if(!arg || arg->kind!=FE_N_IDENT || !count || count->next)
err(c,n->loc,"mem.alloc_slice requires a type and length");
item=arg && arg->kind==FE_N_IDENT ?
fe_type_intern(&c->types,arg->text) : unknown(c);
{
/* The element type may be an instance -- `Slot(V)` -- and
not just a name. */
int named=0;
item=arg ? type_from_expr(s,arg,&named) : unknown(c);
if(!arg || !named || !count || count->next) {
err(c,n->loc,"mem.alloc_slice requires a type and length");
item=unknown(c);
}
}
b=count ? check_expr(s,count) : unknown(c);
if(known(b) && !fe_type_is_integer(b))
err(c,count->loc,"slice length must be an integer");
@@ -578,9 +595,23 @@ FeType *check_expr_core(FeCheckerState *s, FeNode *n)
while(param && arg) {
a=check_expr(s,arg);
b=method_type(c,param->a,et);
if(!compatible(b,a,arg) && a->kind!=FE_TYPE_UNKNOWN)
/* A method argument gets the same call-only weakening a
free function's does: an exclusive view may be handed
over as a shared one for the length of the call, and an
exclusive borrow is lent rather than given. */
if(!compatible(b,a,arg) &&
!(b && a && b->kind==FE_TYPE_SLICE &&
a->kind==FE_TYPE_SLICE && !b->ref_mut && a->ref_mut &&
fe_type_equal(b->elem,a->elem)) &&
!(b && a && b->kind==FE_TYPE_REF && a->kind==FE_TYPE_REF &&
!b->ref_mut && a->ref_mut &&
fe_type_equal(b->elem,a->elem)) &&
a->kind!=FE_TYPE_UNKNOWN)
err(c,arg->loc,"method argument type mismatch");
mark_moved(s,arg,a);
if(!call_reborrows(b,a) &&
!(b && a && b->kind==FE_TYPE_SLICE &&
a->kind==FE_TYPE_SLICE && !b->ref_mut && a->ref_mut))
mark_moved(s,arg,a);
param=param->next;
arg=arg->next;
}
+5
View File
@@ -226,9 +226,13 @@ FeType *build_struct_instance(FeCheck *c, FeUnit *home, FeNode *decl,
for (f=decl->children;f;f=f->next) if (f->kind==FE_N_FIELD) ++fields;
t->field_count=fields;
if (fields) {
const char *save_unit=c->types.unit_name;
t->fields=(FeFieldType *)fe_arena_alloc(&c->arena,
fields*sizeof(FeFieldType));
if (!t->fields) { t->field_count=0; return t; }
/* Field types are written in the unit that declared the struct, not in
whichever unit asked for this instance. */
c->types.unit_name=home->name;
push_instance_bindings(c,&save,t);
bind_self(c,t);
i=0;
@@ -240,6 +244,7 @@ FeType *build_struct_instance(FeCheck *c, FeUnit *home, FeNode *decl,
++i;
}
pop_bindings(c,&save);
c->types.unit_name=save_unit;
}
fe_type_layout_all(&c->types);
/* A type that says how to let go of itself needs that method to exist for