대여는 변수가 아니라 place 단위다

p.a 와 p.b 는 서로 다른 자리인데 한쪽을 대여하면 다른 쪽까지 잠겼다. 메서드가
하는 일의 대부분이 한 필드에 쓰면서 다른 필드를 읽는 것이라, std.map 의 keep 은
그것 때문에 함수 둘로 갈라져 있었고 파서도 같은 자리에서 걸렸다.

FeOwnState 가 필드별 칸을 넷 갖는다. 값으로 복사되는 구조체라 흐름 병합과
스냅샷은 손댈 것이 없었다. 전체를 대여하면 모든 필드와 충돌하고, 필드를
대여하면 전체 및 같은 필드와 충돌한다. 칸이 모자라면 전체 대여로 되돌아가
더 많이 보고할 뿐 놓치지 않는다.

읽기는 식별자에서 일어나는데 그 자리에서는 자기가 무엇의 밑동인지 알 수 없다.
그래서 투영이 내려가는 길에 어느 필드인지 적어두고 식별자가 그것을 집는다.
인덱스는 갈라지지 않는다 -- xs[i] 의 i 는 상수가 아닐 수 있고, 필드 이름은
상수다.

길에서 나온 것: mem.replace 가 목적지 대여를 가져가고 돌려주지 않았다. 일반
호출 인자는 문장 끝에 돌려주는데 intrinsic 경로에만 그것이 없었다. 전에는
그 자리가 어차피 거부돼서 드러나지 않았다.

  var p = Pair{ a: 1, b: 2 };
  let r = &mut p.a;
  p.b = 3;      // ok -- 전에는 에러
  p.a = 3;      // 에러
  take(p);      // 에러

SPEC §5 R6 을 고쳤고, 옛 규칙을 그대로 적어둔 문단과 예제를 갈아치웠다.
own/badrfld 는 이제 허용되는 코드였으므로 같은 필드를 건드리도록 다시 겨눴고
okrfld·badrall·badrsame·exec/fieldbrw 를 더했다.

228/228, 32/32.
This commit is contained in:
2026-08-17 15:29:12 +09:00
parent 120a36eef5
commit f7e667652e
15 changed files with 510 additions and 40 deletions
+9
View File
@@ -30,6 +30,8 @@ struct FeSym {
release the root borrow without a separate alias engine. */
FeOwnState own;
FeSym *borrow_root;
/* Which field of the root this binding borrowed, or null for all of it. */
const char *borrow_field;
int borrow_mut;
int borrow_defer;
FeScope *owner;
@@ -52,6 +54,11 @@ typedef struct FeCheckerState {
unsigned defer_depth;
FeOwnLiveness liveness;
FeNode *fn_node;
/* While a projection is being checked, which field of which base it
reaches. The read happens down at the identifier, which cannot see the
chain above it, so the chain leaves word here on the way down. */
const char *proj_field;
FeNode *proj_base;
} FeCheckerState;
/* The type bindings in force, saved across a nested instantiation. */
@@ -70,6 +77,7 @@ typedef struct FeFlowSlot {
typedef struct FeFlowBorrow {
FeSym *root;
const char *field;
int mutable;
} FeFlowBorrow;
@@ -114,6 +122,7 @@ void flow_restore(FeFlowSlot *slots, unsigned count);
void flow_merge(FeFlowSlot *base, FeFlowSlot *left, FeFlowSlot *right,
unsigned count);
FeSym *own_root_symbol(FeCheckerState *s, FeNode *expr);
const char *own_projected_field(FeNode *expr, FeNode **root_out);
int own_is_global(FeCheckerState *s, FeSym *sym);
void own_borrow_expr(FeCheckerState *s, FeNode *expr, int mutable);
void own_release_temporary_borrow(FeCheckerState *s, FeNode *expr);