fix: 같은 위반을 두 번 보고하던 두 경로를 정리한다

이동한 값을 쓰면 진단이 두 번 나왔다. 원인이 둘이다. 식별자를 읽으면
FE_OWN_READ 가 이미 보고하는데 mark_moved 가 FE_OWN_MOVE 로 같은 자리를 다시
보고했고, member lvalue 는 check_lvalue 가 base 를 검사한 뒤 check_lvalue_core
가 또 검사했다. M6/M7 두 검사기를 합칠 때 남은 자국이다.

러너는 진단의 첫 줄만 마커와 대조하므로 fixture 188개가 이것을 잡지 못했다.
This commit is contained in:
2026-08-17 04:49:05 +09:00
parent c900e0f61c
commit f5bffec7dd
+15 -5
View File
@@ -84,6 +84,11 @@ static void mark_moved(FeCheckerState *s, FeNode *n, FeType *t)
"cannot move a non-Copy value out of a projection; use mem.replace");
return;
}
/* Reaching an identifier already ran FE_OWN_READ over it, and that
read reported the value as gone if it was. Running the move as well
reports the same sentence at the same column a second time, so stop
at the state the read left behind. */
if (sym->own.move != FE_OWN_AVAILABLE) return;
if (fe_own_access(s->c->diags,&sym->own,FE_OWN_MOVE,n->loc)) {
sym->moved=sym->own.move;
/* Keep the existing emitter contract: ownership-consuming AST
@@ -304,7 +309,8 @@ static void check_match(FeCheckerState *s, FeNode *n);
static void check_stmt(FeCheckerState *s, FeNode *n);
static FeType *check_expr_core(FeCheckerState *s, FeNode *n);
static void check_stmt_core(FeCheckerState *s, FeNode *n);
static FeType *check_lvalue_core(FeCheckerState *s, FeNode *n, int read);
static FeType *check_lvalue_core(FeCheckerState *s, FeNode *n, int read,
FeType *base_in);
static FeType *check_lvalue(FeCheckerState *s, FeNode *n, int read);
static FeType *check_call(FeCheckerState *s, FeNode *n);
@@ -1163,7 +1169,11 @@ static FeType *check_expr_core(FeCheckerState *s, FeNode *n)
return unknown(c);
}
static FeType *check_lvalue_core(FeCheckerState *s, FeNode *n, int read)
/* `base_in` is the already-checked type of a member expression's base. The M7
lvalue path looks at that base before delegating here, and checking it a
second time reports any ownership violation on it a second time too. */
static FeType *check_lvalue_core(FeCheckerState *s, FeNode *n, int read,
FeType *base_in)
{
FeSym *sym;
FeType *base;
@@ -1189,7 +1199,7 @@ static FeType *check_lvalue_core(FeCheckerState *s, FeNode *n, int read)
return sym->type;
}
if (n && n->kind == FE_N_MEMBER) {
base=check_expr(s,n->a);
base=base_in ? base_in : check_expr(s,n->a);
if (base && base->kind == FE_TYPE_REF && n->b && n->b->text &&
strcmp(n->b->text,"^")==0) {
if (!base->ref_mut)
@@ -2223,7 +2233,7 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
static FeType *check_lvalue(FeCheckerState *s, FeNode *n, int read)
{
FeType *base;
FeType *base=0;
FeFieldType *field;
FeType *owner;
if (!n) return unknown(s->c);
@@ -2262,7 +2272,7 @@ static FeType *check_lvalue(FeCheckerState *s, FeNode *n, int read)
return field->type;
}
}
return check_lvalue_core(s,n,read);
return check_lvalue_core(s,n,read,n->kind==FE_N_MEMBER ? base : 0);
}
static FeType *m7_pattern_binding_type(FeCheckerState *s, FeType *payload,