move: move/affinity 검사 — v0 fast path 완성

보안 정리 (ii) — safe code에서 capability는 복제·위조되지 않는다 — 를 코드로
닫는다. 검사는 전부 함수 로컬 데이터플로우이고 전역 분석이 없다.

affinity의 뿌리는 capability다. 필드로 가진 타입은 전이적으로 affine이며
고정점까지 돌려 상호 재귀 타입도 유도한다. 이 전이가 없으면 wrapper 하나를
복사해 capability가 사실상 복제되므로 정리가 깨진다. copyable 선언과 affine
필드의 공존은 오류다.

구현한 규칙:
- affine 값은 소유 자리로 갈 때 move된다(own 파라미터, 반환, struct 저장,
  컨테이너 삽입, let 바인딩, by-move capture). moved 이후 사용은 오류이고
  진단이 어디서 소비됐는지를 말한다
- 분기 병합은 보수적 합집합. 한 분기에서라도 moved면 병합 이후 moved
- 빌린 값은 탈출하지 못한다: 반환, struct 저장, 소유 자리로 넘기기 전부 거부
- use의 전염: 빌린 값을 capture한 클로저는 그 자체가 빌린 값이라 소유 자리로
  갈 수 없다. 별도의 nonescaping 개념 없이 use 규칙 하나로 닫힌다
- callable affinity: affine 값을 capture한 클로저는 affine fn이며 fn 자리에
  갈 수 없다

자율 결정 둘:
- 클로저는 mut 바인딩을 capture할 수 없다. spawn만 막는 특수 규칙 대신
  일반 규칙으로 뒀다 — v0에 참조가 없으므로 별칭도 조용한 복사도 만들 수
  없고, spawn 제한은 이 규칙의 특수 사례가 된다
- v0에 부분 move는 없다. 필드 접근은 빌림이고 결과도 빌린 값이다.
  affine 필드만 꺼내려면 부분 move 상태 추적이 필요한데 v0가 살 복잡도가 아니다

05를 자족적으로 다시 썼다. affinity의 뿌리가 capability라 자원 타입을 모듈
안에서 정의해야 검사기가 affine임을 유도할 수 있다. 외부 타입은 affine임을
증명할 수 없으므로 copyable로 본다.

이로써 fast path(L0 parse / L1 type·effect·capability·ownership)가 완성됐다.
cool check가 처음으로 성공을 선언한다 — 01~04, 06, 07이 exit 0으로 통과한다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ZVDeU6KLuUVL3gs18Hm3E
This commit is contained in:
2026-08-30 03:01:05 +09:00
co-authored by Claude Opus 5
parent 79e4ed4190
commit 2e67b74376
6 changed files with 722 additions and 79 deletions
+9 -2
View File
@@ -45,6 +45,13 @@ Alias/Move 모델 (철학 1,3에서 파생 — 언어 전체의 토대):
미해제는 검사하지 않는다 (오용 금지, 누수 허용).
linear 검사와 해제 보장은 v1 과제
- v0에 first-class reference는 없다. mutable 데이터는 소유 변수를 통해서만 변경
- 클로저는 mut 바인딩을 capture할 수 없다. 참조가 없으므로 별칭을 만들 수도,
조용히 복사할 수도 없기 때문이다. spawn 클로저 제한은 이 일반 규칙의 특수 사례다
- v0에 부분 move는 없다. 필드 접근은 빌림이고 결과도 빌린 값이다
※ struct에서 affine 필드만 꺼내 가려면 부분 move 상태 추적이 필요한데,
그 복잡도는 v0가 사려는 것이 아니다. 필요하면 통째로 own으로 받는다
- 외부 타입은 affine임을 증명할 수 없으므로 copyable로 본다.
모르는 것을 위반이라고 말하지 않는다 — 모듈 로딩이 생기면 판정된다
- 공유는 deep immutable 값만 가능 (내부 가변성 타입은 v0에 없음)
근거: "safe code에 data race 없음"은 spawn만 막아서 성립하지 않는다. closure,
channel, container, 인자/반환 전 경로에서 mutable alias가 없어야 하며, 값 의미론
@@ -107,8 +114,8 @@ Affinity 전이 (보안 주장의 필수 전제):
- structured concurrency만 허용: 태스크 수명 = 블록 구조 (locality)
- 데이터 경쟁은 격리로: mutable은 단일 소유, channel로 소유권 이동,
공유는 deep immutable만 (borrow checker는 complexity budget 초과)
- spawn closure는 by-move capture 또는 immutable capture만 허용.
mutable 참조 capture는 문법적으로 금지
- spawn closure는 by-move capture 또는 immutable capture만 허용
(Alias/Move 모델의 mut capture 금지가 그대로 적용된다)
- spawn은 primitive가 아니라 TaskScope capability의 메서드다.
effect spawn은 아래 "정적/동적 층 분리"대로 그 타입에 묶인다
(PaymentGateway.refund와 동형)