Files
doslang-mirror/fec/src/checkpri.h
T
coolguy f7e667652e 대여는 변수가 아니라 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.
2026-08-17 15:29:12 +09:00

263 lines
12 KiB
C

#ifndef FE_CHECKPRI_H
#define FE_CHECKPRI_H
/* The checker's own vocabulary, shared by the files it is split across.
Nothing outside the checker includes this. */
#include "check.h"
#include "m7.h"
#include <stdlib.h>
#define FE_M7_FLOW_CAP 64U
#include "own.h"
#include <string.h>
#include <stdio.h>
typedef struct FeSym FeSym;
/* FeScope is forward declared in check.h. */
struct FeSym {
const char *name;
char *cname;
FeType *type;
FeNode *fn;
int mutable;
int initialized;
int moved;
FeNode *decl;
/* M6 ownership is tracked at the root local/parameter. A reference
binding remembers that root so releasing the binding's last use can
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;
};
struct FeScope {
FeScope *parent;
FeSym *items;
unsigned count;
unsigned capacity;
};
typedef struct FeCheckerState {
FeCheck *c;
FeScope *scope;
FeScope *globals;
FeType *ret;
unsigned loop_depth;
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. */
typedef struct FeBindSave {
FeTypeBind params[FE_TYPE_PARAM_MAX];
unsigned count;
} FeBindSave;
typedef struct FeFlowSlot {
FeSym *sym;
int moved;
int initialized;
int own_move;
int own_initialized;
} FeFlowSlot;
typedef struct FeFlowBorrow {
FeSym *root;
const char *field;
int mutable;
} FeFlowBorrow;
/* How long a chain of new generic instances may get, and how long an
instance's readable spelling may be before it falls back to serials. */
#define FE_GENERIC_DEPTH_MAX 32
#define FE_GENERIC_NAME_READABLE 200
/* Every definition in the checker, so the split files can see each other. */
FeType *unknown(FeCheck *c);
void err(FeCheck *c, FeLoc loc, const char *msg);
int ordered_type(const FeType *t);
int known(FeType *t);
int in_own_drop(FeCheckerState *s, FeNode *n);
void mark_moved(FeCheckerState *s, FeNode *n, FeType *t);
int compatible(FeType *want, FeType *got, FeNode *value);
int call_reborrows(const FeType *param, const FeType *arg);
int explicit_castable(FeType *a, FeType *b);
FeType *node_type(FeCheck *c, FeNode *n);
char *unit_cname(FeCheck *c, const char *name);
char *local_cname(FeCheck *c, const char *name);
FeScope *scope_new(FeCheckerState *s, FeScope *parent);
FeSym *find_current(FeScope *scope, const char *name);
FeSym *find_symbol(FeScope *scope, const char *name);
FeSym *add_symbol(FeCheckerState *s, FeScope *scope,
const char *name, FeType *type, FeNode *fn,
int mutable, int initialized, char *cname,
FeNode *decl);
void enter_unit(FeCheck *c, unsigned index);
unsigned unit_index(FeCheck *c, const FeUnit *u);
FeUnit *binding_unit(FeCheckerState *s, FeNode *base);
int decl_is_public(const FeNode *decl);
FeSym *unit_member(FeCheck *c, FeUnit *u, const char *name);
FeType *unit_type(FeCheck *c, FeUnit *u, const char *name);
int enter_declaring_unit(FeCheck *c, const char *unit_name);
FeNode *unit_type_decl(FeCheck *c, FeUnit *u, const char *name);
FeType *node_type_in(FeCheck *c, const char *unit, FeNode *node);
FeNode *find_method(FeCheck *c, FeType *owner, const char *name);
FeType *method_type(FeCheck *c, FeNode *node, FeType *owner);
unsigned flow_capture(FeScope *scope, FeFlowSlot *slots, unsigned cap);
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);
FeSym *own_derived_call_root(FeCheckerState *s, FeNode *call);
void own_bind_derived_call(FeCheckerState *s, FeSym *binding,
FeNode *value);
int own_stmt_uses(FeNode *node, const char *name);
int own_defer_uses(FeNode *node, const char *name);
int own_contains_node(FeNode *node, FeNode *needle);
void own_release_after_stmt(FeCheckerState *s, FeScope *scope,
FeNode *stmt, int scope_end);
FeOwnState *flow_own_new(FeCheckerState *s, unsigned count);
void flow_own_capture(FeFlowSlot *slots, FeOwnState *states,
unsigned count);
void flow_own_restore(FeFlowSlot *slots, FeOwnState *states,
unsigned count);
void flow_own_merge(FeFlowSlot *slots, FeOwnState *left,
FeOwnState *right, unsigned count);
FeFlowBorrow *flow_borrow_new(FeCheckerState *s, unsigned count);
void flow_borrow_capture(FeFlowSlot *slots, FeFlowBorrow *states,
unsigned count);
void flow_borrow_restore(FeFlowSlot *slots, FeFlowBorrow *states,
unsigned count);
void flow_borrow_merge(FeFlowSlot *slots, FeFlowBorrow *left,
FeFlowBorrow *right, unsigned count);
FeNode *find_const_node(FeCheck *c, const char *name);
const char *builtin_format(FeCheckerState *s, FeNode *fmt);
int format_is_slice_u8(FeType *t);
int format_is_writer_type(FeType *t);
int format_arg_ok(FeType *t, int verb);
void check_format_call(FeCheckerState *s, FeNode *n);
int is_format_builtin(const char *name);
int lvalue_writable(FeCheckerState *s, FeNode *n);
int has_field(FeNode *list, const char *name);
int field_is_visible(FeCheckerState *s, const FeType *t,
const FeFieldType *field);
FeType *check_struct_fields(FeCheckerState *s, FeNode *n, FeType *t);
FeType *check_struct_init(FeCheckerState *s, FeNode *n);
FeType *check_array_init(FeCheckerState *s, FeNode *n);
int array_slice_lvalue(FeNode *n);
FeType *check_index(FeCheckerState *s, FeNode *n);
FeType *check_identifier(FeCheckerState *s, FeNode *n);
FeType *check_expr_core(FeCheckerState *s, FeNode *n);
FeType *check_lvalue_core(FeCheckerState *s, FeNode *n, int read,
FeType *base_in);
int compound_operator(const char *op);
void check_match(FeCheckerState *s, FeNode *n);
void check_for(FeCheckerState *s, FeNode *n);
void check_type_cycle(FeCheck *c, FeType *t);
void check_type_cycles(FeCheck *c);
int own_ast_reference_type(FeNode *type);
int own_ast_pointer_to_reference(FeNode *type);
void check_reference_storage(FeCheck *c, FeNode *decl);
int own_return_from_allowed_root(FeCheckerState *s, FeNode *expr);
void check_stmt_core(FeCheckerState *s, FeNode *n);
void check_fn(FeCheck *c, FeNode *fn, FeScope *globals);
void check_method(FeCheck *c, FeNode *fn, FeScope *globals,
FeType *owner);
int m7_actual_compatible(FeType *want, FeType *got, FeNode *value);
FeType *m7_check_expected(FeCheckerState *s, FeNode *value,
FeType *expected);
FeType *m7_member_field(FeCheckerState *s, FeNode *n, FeType *base);
int m7_place_is_projection(FeNode *n);
unsigned decl_type_param_count(const FeNode *decl);
FeNode *decl_type_param(const FeNode *decl, unsigned i);
int decl_is_generic(const FeNode *decl);
void check_generic_params(FeCheck *c, FeNode *decl);
void push_bindings(FeCheck *c, FeBindSave *save, FeNode *decl,
FeType **args, unsigned count);
void push_instance_bindings(FeCheck *c, FeBindSave *save, FeType *t);
void bind_self(FeCheck *c, FeType *owner);
void pop_bindings(FeCheck *c, const FeBindSave *save);
void instance_key(char *out, const char *unit, const char *name,
FeType **args, unsigned count);
const char *instance_cname(FeCheck *c, const char *key);
int instance_known(FeCheck *c, const char *key);
int instance_record(FeCheck *c, const char *key, FeLoc loc,
FeNode *decl, FeUnit *home, FeType *owner);
int instance_descend(FeCheck *c, FeLoc loc);
FeUnit *current_unit(FeCheck *c);
FeType *build_struct_instance(FeCheck *c, FeUnit *home, FeNode *decl,
const char *key, FeType **args,
unsigned count);
FeType *instantiate_struct(FeCheck *c, FeUnit *home, const char *name,
FeType **args, unsigned count, FeLoc loc);
FeType *instantiate_type_node(void *owner, const FeNode *node);
FeType *type_from_expr(FeCheckerState *s, FeNode *n, int *ok);
int comptime_condition(FeCheckerState *s, FeNode *n, int *out);
void instantiate_body(FeCheck *c, FeUnit *home, FeNode *decl,
FeType *owner, FeBindSave *bindings, FeLoc site);
FeType *check_generic_call(FeCheckerState *s, FeNode *n, FeSym *sym,
FeUnit *home);
FeUnit *unit_named(FeCheck *c, const char *name);
FeType *check_static_method_call(FeCheckerState *s, FeNode *n,
FeType *owner, FeNode *method);
void check_instance_method(FeCheckerState *s, FeType *owner,
FeNode *method, FeLoc site, FeNode *call);
int const_names_type(FeCheckerState *s, FeNode *n);
FeNode *type_method(FeType *t, const char *name);
int method_is_static(const FeNode *method);
int is_error_set_member(FeCheckerState *s, FeNode *n);
FeType *cross_unit_value(FeCheckerState *s, FeNode *n, int *handled);
FeType *check_call_args(FeCheckerState *s, FeNode *n, FeSym *sym,
const char *home, unsigned skip);
FeType *check_call(FeCheckerState *s, FeNode *n);
void m7_capture_flow(FeCheckerState *s, FeFlowSlot *slots,
FeOwnState **own, FeFlowBorrow **borrow,
unsigned *count);
void m7_restore_flow(FeFlowSlot *slots, FeOwnState *own,
FeFlowBorrow *borrow, unsigned count);
void m7_merge_rhs_flow(FeCheckerState *s, FeFlowSlot *base,
FeOwnState *own_base,
FeFlowBorrow *borrow_base,
unsigned count, FeFlowSlot *rhs,
FeOwnState *own_rhs,
FeFlowBorrow *borrow_rhs);
int m7_stmt_definitely_exits(FeNode *n);
FeType *m7_check_lazy(FeCheckerState *s, FeNode *n,
FeM7LazyKind kind);
FeType *check_expr(FeCheckerState *s, FeNode *n);
FeType *check_lvalue(FeCheckerState *s, FeNode *n, int read);
FeType *m7_pattern_binding_type(FeCheckerState *s, FeType *payload,
FeNode *source, int *borrow_mut);
void m7_check_if_let(FeCheckerState *s, FeNode *n);
void m7_check_optional_match(FeCheckerState *s, FeNode *n,
FeType *opt);
void m7_check_match_stmt(FeCheckerState *s, FeNode *n);
void m7_check_decl_stmt(FeCheckerState *s, FeNode *n, int mutable);
void check_stmt(FeCheckerState *s, FeNode *n);
int m7_ast_reference_storage(FeNode *type);
void m7_check_storage(FeCheck *c, FeNode *decl);
void m7_validate_error_decl(FeCheck *c, FeNode *decl);
void declare_unit(FeCheck *c);
FeScope *declare_unit_scope(FeCheck *c, FeCheckerState *s);
void check_unit_bodies(FeCheck *c, FeCheckerState *s);
#endif