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.
263 lines
12 KiB
C
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
|