docs: 문서 하나가 질문 하나에 답하게
GOAL.md 는 계획일 때 값어치가 있었는데 완료 보고로 바꾸는 순간 git log 의
중복이 됐다. 끝난 계획은 문서가 아니라 히스토리다. 내용은 이미 TODO 와 SPEC
에 들어갔으니 지운다.
fixture-report.md 도 지운다. 기준선이 150/188 인 일회성 조사 스냅샷이고
지금은 245/245 다. 필요하면 2f140e1 에 있다.
TODO 의 '정해진 것' 이 두 종류를 섞고 있었다. 언어 규칙은 SPEC 문장을 옮겨
적은 것이라 한쪽만 고치면 갈라지고, 구현 결정은 SPEC 에 없어서 여기가 유일한
출처다. 둘로 쪼갰다 -- 앞의 표는 §번호만 담고, 뒤의 표는 내용과 그것이 사는
파일을 담는다.
SPEC 의 §7.9 를 §7.7 로 옮겼다. 7.7 과 7.8 없이 7.9 가 떠 있었다.
1847 → 1173 줄. 245/245, 38/38.
This commit is contained in:
@@ -9,8 +9,7 @@ DOS/Windows용 시스템 프로그래밍 언어 Ferro와 그 컴파일러 `fec`.
|
||||
|---|---|
|
||||
| `SPEC.md` | 언어 명세. 유일한 규범 문서 |
|
||||
| `IR.md` | 중간 표현. 프론트엔드와 기계 사이 |
|
||||
| `TODO.md` | 남은 작업, 미결 결정, 정해진 것 |
|
||||
| `GOAL.md` | 부트스트랩까지의 실행 계획. P0~P4 와 안 하기로 한 것 |
|
||||
| `TODO.md` | 남은 작업과 정해진 것. 언어 규칙은 `SPEC.md` 를 가리키기만 한다 |
|
||||
| `fec/tests/*/README.md` | 각 fixture 디렉터리가 무엇을 검사하는지 |
|
||||
|
||||
## 파이프라인
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
# GOAL — 부트스트랩까지 남은 작업
|
||||
|
||||
외부 스펙 감사(v0.1.8)와, 그 항목들을 실제로 빌드해서 확인한 결과를 합친 실행
|
||||
계획이었다. **P0~P4 는 전부 끝났다.** 감사는 문서를 읽었고 여기 적힌 것은
|
||||
컴파일러에 물어본 답이다.
|
||||
|
||||
```
|
||||
uv run python tests/run.py 245/245 + std 밖 unsafe/*T 예산 검사
|
||||
uv run python tests/exec.py 38/38
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 끝난 것
|
||||
|
||||
### P0 — 조용히 틀린 것
|
||||
|
||||
| # | 무엇이었나 | |
|
||||
|---|---|---|
|
||||
| 0-1 | 니치 옵셔널(`?^T`, `?&T`)이 포인터가 아니라 포인터가 든 자리를 넘겼다. `if let` 이 컴파일되고 쓰레기를 반환했다 | `exec/optref.fe` |
|
||||
| 0-2 | `Handle(Node){ raw: 7 }` 이 파싱되지 않았다. 제네릭 인스턴스는 `Self{...}` 나 생성자로만 지을 수 있었다 | `exec/geninst/` |
|
||||
|
||||
### P1 — 스펙의 빈칸
|
||||
|
||||
| # | 결정 | |
|
||||
|---|---|---|
|
||||
| 1-1 | 정수 리터럴은 문맥이 요구하는 타입, 없으면 `i32`. 범위를 벗어나면 거부 | `types/badlit.fe`, `types/oklit.fe` |
|
||||
| — | 그 자리에서 나온 것: **store 폭이 목적지가 아니라 값에서 왔다.** `let b: u8 = 200;` 이 4바이트를 1바이트 자리에 써서 옆 지역을 지웠다 | `exec/narrow.fe` |
|
||||
| 1-2 | 미사용 타입 파라미터는 정상. typed handle 이 그 모양이다 | `generic/okphant.fe`, `badphant.fe` |
|
||||
| 1-3 | `--no-checks` 에서 오버플로는 랩어라운드로 정의된다 | SPEC §7.4 |
|
||||
| 1-4 | 작은 규칙 일곱 (SPEC §7.9). 다섯은 이미 옳았고, `defer` 안의 `return` 과 순회 중 원본 변경 둘은 그냥 통과하고 있었다 | `own/bdefret.fe`, `own/badforwr.fe`, `own/okforrd.fe` |
|
||||
|
||||
### P2 — SPEC 에서 죽은 C 백엔드 제거
|
||||
|
||||
`.fei`, `--emit-c`, `fe_errors.h`, "호스트 C 방출", "C 방출 시 static inline"
|
||||
열 군데. 감사가 그 문서를 충실히 읽고 존재하지 않는 문제(C 의 부호 있는
|
||||
오버플로 UB)를 보고했다 — 명세가 거짓말을 하면 그것을 읽는 사람이 틀린 답을
|
||||
낸다. 오류 코드 절은 실제대로 다시 썼고, `--target=`/`--model=` 은 드라이버에서
|
||||
없앴다.
|
||||
|
||||
### P3 — stdlib
|
||||
|
||||
| # | | |
|
||||
|---|---|---|
|
||||
| 3-1 | `arena.Handle(T)` — 8바이트 고정. 세대·epoch·arena id 를 담아 놓아준 뒤, reset 뒤, 다른 아레나에 물으면 `null` | `exec/arenat.fe` |
|
||||
| 3-2 | `arena.Arena(T)` — 짧은 대여만. `get` 은 사본을 준다. `get_mut` 은 두지 않았다 | |
|
||||
| 3-3 | `list.List(T)` 에 `pop`/`take`/`swap`/`slice`/`slice_mut`/`clear` | `exec/listmor.fe` |
|
||||
| 3-4 | `intern.Interner` — `str` 을 꺼내는 API 없음. `eq`/`len_of`/`hash_of`/`find`/`copy_into` | `exec/interns.fe` |
|
||||
| 3-5 | `std.map` 이 `StrId` 를 바이트 키로 받는다. 별도 `IntMap` 불필요 | |
|
||||
|
||||
길에서 고친 것 둘:
|
||||
- 메서드 호출이 시그니처를 **호출자 유닛**에서 풀었다.
|
||||
- 제네릭 인스턴스를 필드로 담은 구조체가 **크기 0 으로 굳었다** — 짓는 중인
|
||||
인스턴스가 배치되어 버려서. `Holder` 가 36 바이트 대신 12 였다.
|
||||
|
||||
### P4 — 측정
|
||||
|
||||
`--report-unsafe`, `--report-instances`. 그리고 그 숫자를 `run.py` 가 검사한다:
|
||||
`std.mem`/`std.sys` 밖의 `unsafe` 와 `*T` 는 0 이어야 하고, 늘어나면 빌드가
|
||||
실패한다.
|
||||
|
||||
```
|
||||
unit unsafe *T unchecked
|
||||
std.io 6 1 0
|
||||
std.sys 10 12 0
|
||||
total 16 13 0
|
||||
outside std 0 0 0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 채택하지 않은 것
|
||||
|
||||
| 감사 항목 | 판정 | 근거 |
|
||||
|---|---|---|
|
||||
| 참조 튜플 `-> (&mut T, &mut T)` | 보류 | struct 는 필드 단위 대여로 풀렸다. 컨테이너의 두 원소만 남는데 렉서·파서에서 필요했던 자리가 0 번 |
|
||||
| `Arena.get_mut -> ?&mut T` | 거부 | 아레나 하나를 통째로 잠그는 참조를 오래 들고 있게 하는 API |
|
||||
| `fmt.fmt_strid` | 거부 | `@print` 가 interner 인스턴스에 닿을 수 없다 (R10) |
|
||||
| 별도 `IntMap(V)` | 불필요 | `std.map` 이 이미 포괄 |
|
||||
| C 오버플로 방출 규칙 | 대체 | C 백엔드가 없다. 결론만 1-3 으로 흡수 |
|
||||
| R4 완화 | 영구 제외 | |
|
||||
|
||||
---
|
||||
|
||||
## 다음
|
||||
|
||||
부트스트랩까지 남은 것은 `TODO.md` 에 있다. 도구는 다 갖췄다 — 아레나, 핸들,
|
||||
맵, interner, 그리고 리졸버가 쓸 `Node.bind` 와 `Map.clear`.
|
||||
@@ -581,7 +581,7 @@ pub fn main() -> !void {
|
||||
|
||||
---
|
||||
|
||||
### 7.9 작은 규칙들
|
||||
### 7.7 작은 규칙들
|
||||
|
||||
구현자가 임의로 정하면 갈라지는 것들. 각각 한 줄이면 끝나므로 여기 모아 둔다.
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ uv run python tests/exec.py 38/38 컴파일된 프로그램이 실제로
|
||||
| `std.map` | 키를 맵이 소유한 버퍼에 복사하고 슬롯은 위치만 든다 |
|
||||
| **Ferro 파서를 Ferro 로** | 노드 배열 하나 + 인덱스. `1 + 2 * 3` 이 `(+ 1 (* 2 3))` 로 묶인다 |
|
||||
| 필드 단위 대여 | `p.a` 와 `p.b` 는 다른 place 다. `std.map` 의 `keep` 이 다시 함수 하나가 됐다 |
|
||||
| **GOAL.md P0~P4** | 외부 감사에서 나온 것 전부. stdlib 다섯, 스펙 빈칸, 죽은 C 백엔드, 측정 |
|
||||
| 외부 스펙 감사 대응 | 니치 옵셔널·store 폭·배치 세 버그, 스펙 빈칸, 죽은 C 백엔드, stdlib 다섯, 측정 |
|
||||
|
||||
파서가 알려준 것: **자기 참조 자료구조는 인덱스로 짓는다.** 노드는 `^Node` 를
|
||||
들 수 없고(자식이 여럿이며 한 번씩 소유하지 않는다) `&Node` 도 들 수 없다(R4).
|
||||
@@ -35,8 +35,6 @@ uv run python tests/exec.py 38/38 컴파일된 프로그램이 실제로
|
||||
|
||||
## 셀프호스팅으로 가는 길
|
||||
|
||||
순서와 근거는 `GOAL.md` 에 있다 (P0~P4). 여기는 무엇이 남았는지만 적는다.
|
||||
|
||||
| # | 일 | 규모 | 비고 |
|
||||
|---|---|---|---|
|
||||
| 1 | 리졸버를 Ferro 로 | 중 | 도구는 다 있다: `intern`, `map`, `Node.bind`, `Map.clear` |
|
||||
@@ -62,29 +60,43 @@ uv run python tests/exec.py 38/38 컴파일된 프로그램이 실제로
|
||||
|
||||
---
|
||||
|
||||
## 정해진 것
|
||||
## 정해진 것 — 언어
|
||||
|
||||
`SPEC.md` 가 유일한 출처다. 여기는 **어디를 보는지만** 적는다. 문장을 옮겨
|
||||
적으면 한쪽만 고쳐져서 갈라진다.
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 타깃 | **i386 하나.** 세그먼트 없음, `far` 영구 제외 (SPEC §2) |
|
||||
| `usize`/`isize` | **타깃의 포인터 폭.** 비트 수를 약속하지 않아 64비트 문이 닫히지 않음 |
|
||||
| 제네릭 | 모노모피제이션. 순수 프론트엔드 기능이라 IR 에 제네릭 개념이 없음 |
|
||||
| 덩어리 전달 | 전부 주소로. ISA 마다 다른 구조체 전달 ABI 를 피해감 |
|
||||
| 트랩 | `trap <reason> <line>` → `fe_trap(reason, FE_FILE_n, line)`. 파일은 검사가 쓰인 유닛 |
|
||||
| 슬라이스 배치 | 포인터 다음 길이. 오프셋은 `lowerpri.h` 한 군데에만 |
|
||||
| 오류 코드 | `error.Name` 을 빌드 전체에서 모아 철자 순으로 1부터 |
|
||||
| 레지스터 | ebx·esi·edi 를 블록 안에 머무는 임시값에 준다. eax/ecx/edx 는 스크래치 |
|
||||
| 정수 리터럴 | 문맥이 요구하는 타입, 없으면 `i32`. 범위를 벗어나면 거부 (SPEC §3) |
|
||||
| store 폭 | 값이 아니라 **자리**가 정한다 |
|
||||
| unsafe 예산 | `std.mem`/`std.sys` 밖은 0. `run.py` 가 검사하고 늘어나면 실패한다 |
|
||||
| 해제 | 소유자를 놓으면 그것이 가진 것도 놓는다 (R1). `drop` 을 부른 뒤 필드로 내려간다 — 그래서 `List`/`Arena`/`Map` 은 `drop` 이 없다 |
|
||||
| 배타 대여를 호출에 넘기기 | **이동이 아니라 호출 동안의 재대여** (SPEC §4.2, §5 R6). 없으면 배타 파라미터를 함수당 한 번만 넘길 수 있어 재귀 하강 파서를 못 쓴다 |
|
||||
| 자기 `drop` 안의 부분 이동 | **허용** (SPEC §5 R7 예외). 객체가 사라지는 중이라 뒤에 남아 읽힐 것이 없다 |
|
||||
| 대여 단위 | **place 단위** (SPEC §5 R6). 루트 변수의 직속 필드 한 겹까지 갈라지고, 그 아래와 인덱스·역참조는 전체 대여다. 한 값당 4 필드까지, 넘으면 전체로 되돌아간다 |
|
||||
| 타깃, `usize`/`isize` | §2 |
|
||||
| 정수 리터럴의 타입과 범위 | §3 |
|
||||
| 호출 인자·반환 위치의 대여 약화 | §4.2 |
|
||||
| 해제는 소유자를 따라 내려간다 | §5 R1 |
|
||||
| 대여는 place 단위 | §5 R6 |
|
||||
| 배타 대여를 호출에 넘기는 것은 재대여 | §4.2, §5 R6 |
|
||||
| 자기 `drop` 안의 부분 이동 | §5 R7 |
|
||||
| `--no-checks` 의 오버플로는 랩어라운드 | §7.4 |
|
||||
| `match`·`defer`·순회·`undefined` 등 작은 규칙 일곱 | §7.7 |
|
||||
| 제네릭은 모노모피제이션 | §9 |
|
||||
|
||||
## 정해진 것 — 구현
|
||||
|
||||
`SPEC.md` 에 없는 것들. **여기가 출처다.**
|
||||
|
||||
| | | 사는 곳 |
|
||||
|---|---|---|
|
||||
| 덩어리 전달 | 전부 주소로. ISA 마다 다른 구조체 전달 ABI 를 피해감 | `lower.c` |
|
||||
| 슬라이스 배치 | 포인터 다음 길이 | `lowerpri.h` 한 군데에만 |
|
||||
| store 폭 | 값이 아니라 **자리**가 정한다 | `lowerstm.c` `store_into` |
|
||||
| 트랩 | `fe_trap(reason, FE_FILE_n, line)`. 파일은 검사가 쓰인 유닛 | `x86.c`, `rt/start.asm` |
|
||||
| 오류 코드 | 빌드 전체에서 모아 철자 순으로 1부터 | `lowerstm.c` |
|
||||
| 레지스터 | ebx·esi·edi 를 블록 안에 머무는 임시값에. eax/ecx/edx 는 스크래치 | `x86.c` |
|
||||
| 제네릭 인스턴스 | 짓는 중에는 배치하지 않는다. 멤버가 안 정해진 집합 타입은 굳지 않고 물러난다 | `types.c` `layout_type` |
|
||||
| unsafe 예산 | `std.mem`/`std.sys` 밖은 0. 늘어나면 빌드가 실패한다 | `tests/run.py` |
|
||||
|
||||
---
|
||||
|
||||
## 파일 크기 규칙
|
||||
|
||||
**2,000 줄을 넘기지 않는다. 웬만하면 1,000 줄.** 넘으면 나눈다 -- `check.c` 는
|
||||
3,937 줄이었고 `lower.c` 는 1,913 줄이었다. 지금 가장 큰 것은 1,000 줄이다.
|
||||
3,937 줄이었고 `lower.c` 는 1,913 줄이었다. 지금 가장 큰 것은 `checkcal.c`
|
||||
1,044 줄이다.
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# SPEC–fec parser audit
|
||||
|
||||
- 날짜: 2026-08-17
|
||||
- 기준 커밋: `52aaff62e490e37a0995aaaf7cbda47cf98e54a7`
|
||||
- 범위: `SPEC.md` §6과 `fec/src/lexer.c`, `fec/src/parser.c`
|
||||
|
||||
## 현재 문제
|
||||
|
||||
| ID | SPEC | 현재 구현 | 재현 결과 |
|
||||
|---|---|---|---|
|
||||
| PARSE-01 | 최상위 `comptime if` 선언 허용 | `comptime if`는 문장에서만 처리 | 최상위 사용을 `expected declaration`으로 거부 |
|
||||
| PARSE-02 | 타입 이름은 `ident ('.' ident)*` | 타입에서 점 하나만 처리 | `alpha.beta.Gamma`를 파싱하지 못함 |
|
||||
| PARSE-03 | `catch` EBNF가 binding 없는 block과 binding 뒤 expression도 허용 | 짧은 `catch expr`과 `catch \|e\| block`만 처리 | 구현은 §4.6 설명과 맞고 §6.1 EBNF가 지나치게 넓음 |
|
||||
| PARSE-04 | `\|`와 `^`는 같은 우선순위, 단항 비트 NOT은 `~` | 각각 우선순위 5와 6, `~` 토큰 없음, 단항 `^` 허용 | `~x`를 거부하고 `a \| b ^ c`를 `a \| (b ^ c)`로 파싱 |
|
||||
| PARSE-05 | 전역 `static`과 `var`의 타입 필수 | 타입 표기를 선택적으로 처리하고 초기값에서 추론 | `static A = 1;`, `var B = 2;` 모두 검사 통과 |
|
||||
| PARSE-06 | error code는 정수 literal | 일반 expression을 파싱하며 literal이 아니면 code 검증을 건너뜀 | `error E { Bad = 1 + 2, }`가 검사 통과 |
|
||||
| PARSE-07 | struct field와 enum vfield의 쉼표 필수 | 닫는 `}` 바로 앞에서는 쉼표 생략 허용 | `struct S { x: i32 }`가 검사 통과 |
|
||||
|
||||
## 검증
|
||||
|
||||
- `uv run python tests/run.py`: `240/240` 통과
|
||||
- 위 항목의 최소 입력을 현재 `fec`에 직접 넣어 파싱 및 `--check` 결과를 확인함
|
||||
- 기존 fixture에는 위 괴리를 직접 고정하는 사례가 없음
|
||||
|
||||
이 문서는 조사 시점의 구현 상태를 기록한다. 언어 규칙의 기준은 `SPEC.md`다.
|
||||
@@ -1,597 +0,0 @@
|
||||
# 마커 없는 fixture 진단 증거 보고서
|
||||
|
||||
기준선: `uv run python tests/run.py` → `150/188 passed (58 pin a line and message)`
|
||||
|
||||
이 보고서는 마커가 없는 37개 fixture를 직접 읽고, 기준선에서 새로 빌드된
|
||||
`.build/fec.exe --check`의 실제 진단을 확인한 결과다. 진단 전문의 색상 제어 문자는
|
||||
가독성을 위해 제거했으며, 텍스트·줄·열·진단 순서는 그대로 기록했다.
|
||||
|
||||
## types
|
||||
|
||||
### `fec/tests/types/bad_ari.fe`
|
||||
|
||||
- 검사 대상: 함수 호출 인자 개수 불일치.
|
||||
- 근거: `add`는 두 인자를 받지만 8행에서 `add(1)`로 한 인자만 전달한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/bad_ari.fe:8:15: error: wrong number of arguments
|
||||
8 | return add(1);
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 호출의 인자 개수 위반을 직접 진단한다.
|
||||
|
||||
### `fec/tests/types/bad_asgn.fe`
|
||||
|
||||
- 검사 대상: 불변 `let` 변수에 대입.
|
||||
- 근거: 4행에서 `let value`로 선언한 뒤 5행에서 `value = 2`로 대입한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/bad_asgn.fe:5:5: error: cannot assign to immutable let
|
||||
5 | value = 2;
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — `let`의 불변성 위반을 직접 진단한다.
|
||||
|
||||
### `fec/tests/types/bad_cast.fe`
|
||||
|
||||
- 검사 대상: 허용되지 않는 타입의 `as` 변환.
|
||||
- 근거: 4행에서 `bool` 값 `true`를 `i32`로 변환한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/bad_cast.fe:4:23: error: 'as' requires integer or char types
|
||||
4 | let x: i32 = true as i32;
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 정수/문자가 아닌 피연산자의 캐스트를 직접 진단한다.
|
||||
|
||||
### `fec/tests/types/bad_cond.fe`
|
||||
|
||||
- 검사 대상: 조건식의 비-`bool` 값 사용.
|
||||
- 근거: 4행의 `if 1`에서 정수 리터럴을 조건으로 사용한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/bad_cond.fe:4:5: error: if condition must be bool
|
||||
4 | if 1 { return 0; }
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 조건식이 `bool`이어야 한다는 규칙을 직접 진단한다.
|
||||
|
||||
### `fec/tests/types/bad_mlet.fe`
|
||||
|
||||
- 검사 대상: `let`으로 mutable slice를 바인딩.
|
||||
- 근거: 4행에서 mutable 배열 slice를 만든 뒤 5행의 `let s: []mut u8`에 바인딩한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/bad_mlet.fe:5:5: error: let cannot bind a mutable slice
|
||||
5 | let s: []mut u8 = raw[..];
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — mutable slice의 `let` 바인딩 금지를 직접 진단한다.
|
||||
|
||||
### `fec/tests/types/bad_ret.fe`
|
||||
|
||||
- 검사 대상: 반환식과 함수 반환 타입의 불일치.
|
||||
- 근거: `main`은 `i32`를 반환한다고 선언했지만 4행에서 `true`를 반환한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/bad_ret.fe:4:5: error: return type mismatch
|
||||
4 | return true;
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 반환 타입 불일치를 직접 진단한다.
|
||||
|
||||
### `fec/tests/types/bad_shwr.fe`
|
||||
|
||||
- 검사 대상: shared slice를 통한 쓰기.
|
||||
- 근거: `s`는 `[]u8` shared slice인데 4행에서 `s[0] = 1`로 쓴다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/bad_shwr.fe:4:6: error: cannot write through shared slice
|
||||
4 | s[0] = 1;
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — shared slice 쓰기 위반을 직접 진단한다.
|
||||
|
||||
### `fec/tests/types/bad_type.fe`
|
||||
|
||||
- 검사 대상: 함수 인자 타입 불일치.
|
||||
- 근거: `add`의 첫 인자는 `i32`인데 8행에서 `true`를 전달한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/bad_type.fe:8:16: error: argument type mismatch
|
||||
8 | return add(true, 1);
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 함수 인자의 타입 불일치를 직접 진단한다.
|
||||
|
||||
### `fec/tests/types/bad_unit.fe`
|
||||
|
||||
- 검사 대상: 초기화되지 않은 지역 변수 사용.
|
||||
- 근거: 4행에서 `var value: i32`만 선언하고 값을 넣지 않은 채 5행에서 반환한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/bad_unit.fe:5:12: error: use of uninitialized variable
|
||||
5 | return value;
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 초기화되지 않은 변수 사용을 직접 진단한다.
|
||||
|
||||
### `fec/tests/types/bad_unk.fe`
|
||||
|
||||
- 검사 대상: 정의되지 않은 이름 사용.
|
||||
- 근거: 4행에서 선언되지 않은 `missing_name`을 반환한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/bad_unk.fe:4:12: error: unknown name
|
||||
4 | return missing_name;
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 미정의 이름 사용을 직접 진단한다.
|
||||
|
||||
### `fec/tests/types/bad_void.fe`
|
||||
|
||||
- 검사 대상: `void` 표현식을 값 변수의 초기화식으로 사용.
|
||||
- 근거: 반환값이 없는 `noop()`의 결과를 8행에서 `i32` 변수에 넣는다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/bad_void.fe:8:5: error: initializer type mismatch
|
||||
8 | let value: i32 = noop();
|
||||
| ^
|
||||
fec/tests/types/bad_void.fe:8:5: error: void expression cannot initialize a variable
|
||||
8 | let value: i32 = noop();
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — void 표현식의 값 초기화 사용을 직접 진단한다.
|
||||
|
||||
### `fec/tests/types/badarr.fe`
|
||||
|
||||
- 검사 대상: 배열 리터럴의 원소 타입 및 선언된 배열 타입 불일치.
|
||||
- 근거: `[2]i32`에 세 원소를 쓰고, 둘째 원소로 `bool`인 `true`를 넣는다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/badarr.fe:3:25: error: array element type mismatch
|
||||
3 | let a: [2]i32 = [1, true, 3];
|
||||
| ^
|
||||
fec/tests/types/badarr.fe:3:5: error: initializer type mismatch
|
||||
3 | let a: [2]i32 = [1, true, 3];
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 배열 원소 타입 위반을 직접 진단하고, 선언 타입 불일치도 함께 진단한다.
|
||||
|
||||
### `fec/tests/types/badchar.fe`
|
||||
|
||||
- 검사 대상: 명시적 캐스트 없는 `char`와 `u8`의 대입.
|
||||
- 근거: 4행에서 `char` 리터럴을 `u8` 변수에 직접 넣는다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/badchar.fe:4:5: error: initializer type mismatch
|
||||
4 | let u: u8 = 'A';
|
||||
| ^
|
||||
fec/tests/types/badchar.fe:5:5: error: return type mismatch
|
||||
5 | return u;
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 첫 진단이 char/u8 직접 대입의 타입 불일치를 짚는다. 5행 진단은 연쇄 오류다.
|
||||
|
||||
### `fec/tests/types/badcycle.fe`
|
||||
|
||||
- 검사 대상: 값으로 연결된 재귀 구조체 타입.
|
||||
- 근거: `A`가 `B`를 값으로 포함하고 `B`가 다시 `A`를 값으로 포함한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/badcycle.fe:1:1: error: by-value recursive type
|
||||
1 | unit badcycle;
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 값 기반 재귀 타입을 직접 진단한다. 위치가 선언부 첫 줄로 올라가지만 진단 종류는 정확하다.
|
||||
|
||||
### `fec/tests/types/badfield.fe`
|
||||
|
||||
- 검사 대상: 불변 구조체 값의 필드에 대입.
|
||||
- 근거: `p`는 `let`으로 선언됐고 6행에서 `p.x = 3`을 수행한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/badfield.fe:6:6: error: cannot assign through immutable value
|
||||
6 | p.x = 3;
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 불변 값의 projection을 통한 쓰기를 직접 진단한다.
|
||||
|
||||
### `fec/tests/types/badfld.fe`
|
||||
|
||||
- 검사 대상: 구조체 초기화 필드 누락과 존재하지 않는 필드 접근.
|
||||
- 근거: `Point`는 `x`, `y`를 요구하지만 4행 초기화에는 `x`만 있고, 5행에서 없는 `z`에 접근한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/badfld.fe:4:20: error: missing struct field
|
||||
4 | let p: Point = Point{ x: 1 };
|
||||
| ^
|
||||
fec/tests/types/badfld.fe:5:13: error: unknown struct field
|
||||
5 | return p.z;
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 두 필드 규칙 위반을 모두 직접 진단한다.
|
||||
|
||||
### `fec/tests/types/badindex.fe`
|
||||
|
||||
- 검사 대상: 불변 배열을 통한 요소 쓰기.
|
||||
- 근거: `a`는 `let` 배열인데 5행에서 `a[0] = 3`을 수행한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/badindex.fe:5:6: error: cannot assign through immutable value
|
||||
5 | a[0] = 3;
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 불변 배열 index projection을 통한 쓰기를 직접 진단한다.
|
||||
|
||||
### `fec/tests/types/badmat.fe`
|
||||
|
||||
- 검사 대상: 비-완전 `match`.
|
||||
- 근거: `Shape`에는 `Empty`, `Circle` 두 variant가 있는데 4행 match에는 `Empty`만 있다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/badmat.fe:4:5: error: non-exhaustive match
|
||||
4 | match Shape.Empty { Empty => 0; }
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — match의 비-완전성을 직접 진단한다.
|
||||
|
||||
### `fec/tests/types/badstr.fe`
|
||||
|
||||
- 검사 대상: shared string/slice를 통한 쓰기.
|
||||
- 근거: `str`인 `text`의 4행에서 인덱스 요소에 대입한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/types/badstr.fe:4:9: error: cannot write through shared slice
|
||||
4 | text[0] = 'z';
|
||||
| ^
|
||||
fec/tests/types/badstr.fe:4:13: error: assignment type mismatch
|
||||
4 | text[0] = 'z';
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 첫 진단이 shared string 쓰기를 직접 짚고, 두 번째는 요소 타입의 연쇄 진단이다.
|
||||
|
||||
## format
|
||||
|
||||
### `fec/tests/format/bad_ari.fe`
|
||||
|
||||
- 검사 대상: format placeholder와 인자 개수 불일치.
|
||||
- 근거: 4행의 format 문자열에는 `{}`가 두 개지만 인자는 `1` 하나다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/format/bad_ari.fe:4:6: error: format argument count mismatch
|
||||
4 | @print("{} {}", 1);
|
||||
| ^
|
||||
fec/tests/format/bad_ari.fe:4:6: error: format argument count mismatch
|
||||
4 | @print("{} {}", 1);
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 인자 개수 불일치를 직접 진단한다. 동일 진단이 중복 출력된다.
|
||||
|
||||
### `fec/tests/format/bad_bufw.fe`
|
||||
|
||||
- 검사 대상: `io.buf_writer(buf)`를 통한 buffer writer 구성.
|
||||
- 근거: `[]mut u8` 버퍼를 `io.buf_writer`에 전달하지만, 이 호출이 정확히 어떤 금지 규칙을 의도하는지는 파일만으로 확정하기 어렵다. 명세의 `io.Writer`는 enum handle이며 `io.buf_writer` API는 정의되어 있지 않다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/format/bad_bufw.fe:6:13: error: unknown name
|
||||
6 | let w = io.buf_writer(buf);
|
||||
| ^
|
||||
fec/tests/format/bad_bufw.fe:6:26: error: invalid enum variant constructor
|
||||
6 | let w = io.buf_writer(buf);
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 애매 — 존재하지 않는 `io.buf_writer`를 거부한다는 점은 맞지만, fixture가 검사하려는 구체적인 buffer-writer 규칙을 진단한 것인지 코드만으로 판정할 수 없다.
|
||||
|
||||
### `fec/tests/format/bad_cls.fe`
|
||||
|
||||
- 검사 대상: 닫히지 않은 placeholder가 아니라 unmatched `}` 형식 오류.
|
||||
- 근거: 4행의 format 문자열이 단독 `}`를 포함한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/format/bad_cls.fe:4:6: error: unmatched '}' in format
|
||||
4 | @print("}", 1);
|
||||
| ^
|
||||
fec/tests/format/bad_cls.fe:4:6: error: format argument count mismatch
|
||||
4 | @print("}", 1);
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 첫 진단이 unmatched `}`를 직접 짚는다. 두 번째는 파생된 개수 진단이다.
|
||||
|
||||
### `fec/tests/format/bad_many.fe`
|
||||
|
||||
- 검사 대상: placeholder보다 많은 format 인자.
|
||||
- 근거: 문자열에는 `{}` 하나뿐인데 4행에서 `1, 2` 두 인자를 전달한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/format/bad_many.fe:4:6: error: format argument count mismatch
|
||||
4 | @print("{}", 1, 2);
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — format 인자 개수 불일치를 직접 진단한다.
|
||||
|
||||
### `fec/tests/format/bad_open.fe`
|
||||
|
||||
- 검사 대상: 닫히지 않은 format placeholder.
|
||||
- 근거: 4행의 문자열에 여는 `{`만 있고 닫는 `}`가 없다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/format/bad_open.fe:4:6: error: unterminated format placeholder
|
||||
4 | @print("{", 1);
|
||||
| ^
|
||||
fec/tests/format/bad_open.fe:4:6: error: format argument count mismatch
|
||||
4 | @print("{", 1);
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 첫 진단이 종료되지 않은 placeholder를 직접 짚는다. 두 번째는 파생된 개수 진단이다.
|
||||
|
||||
### `fec/tests/format/bad_run.fe`
|
||||
|
||||
- 검사 대상: 런타임 문자열을 format 문자열로 사용.
|
||||
- 근거: 4행에서 `fmt`를 `var str`로 선언하고 5행에서 `@print(fmt, 1)`에 전달한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/format/bad_run.fe:5:6: error: format must be a comptime string
|
||||
5 | @print(fmt, 1);
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — format 문자열의 comptime 제약을 직접 진단한다.
|
||||
|
||||
### `fec/tests/format/bad_try.fe`
|
||||
|
||||
- 검사 대상: 오류 결과가 아닌 `@print`에 `try` 사용.
|
||||
- 근거: 명세상 `@print`은 `void`를 반환하는데 4행에서 `try @print(...)`을 쓴다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/format/bad_try.fe:4:5: error: try requires an error result
|
||||
4 | try @print("nope");
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — `try`의 오류 결과 요구를 직접 진단한다.
|
||||
|
||||
### `fec/tests/format/bad_type.fe`
|
||||
|
||||
- 검사 대상: format writer가 없는 타입을 format 인자로 사용.
|
||||
- 근거: `Point` 구조체 값을 7행에서 `{}` placeholder의 인자로 전달한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/format/bad_type.fe:7:18: error: no fmt writer for argument type
|
||||
7 | @print("{}", p);
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 해당 타입을 포맷할 writer가 없음을 직접 진단한다.
|
||||
|
||||
### `fec/tests/format/bad_verb.fe`
|
||||
|
||||
- 검사 대상: 지원되지 않는 format verb.
|
||||
- 근거: 4행의 `{q}`에서 `q`는 명세에 없는 verb다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/format/bad_verb.fe:4:6: error: unsupported format verb
|
||||
4 | @print("{q}", 1);
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 지원되지 않는 verb를 직접 진단한다.
|
||||
|
||||
### `fec/tests/format/bad_writ.fe`
|
||||
|
||||
- 검사 대상: `@fprint` 첫 인자의 `io.Writer` 타입 위반.
|
||||
- 근거: 5행에서 writer 대신 `i32` 변수 `x`를 첫 인자로 전달한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/format/bad_writ.fe:5:13: error: @fprint requires io.Writer
|
||||
5 | @fprint(x, "bad");
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — `@fprint`의 writer 요구를 직접 진단한다.
|
||||
|
||||
## own
|
||||
|
||||
### `fec/tests/own/bad_clos.fe`
|
||||
|
||||
- 검사 대상: 소유 값을 close 후 다시 사용.
|
||||
- 근거: 11행의 `try file.close()`가 `file`을 이동시키고 12행에서 다시 `file.close()`를 호출한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/own/bad_clos.fe:12:5: error: use of moved value
|
||||
12 | file.close();
|
||||
| ^
|
||||
fec/tests/own/bad_clos.fe:11:9: note: value was moved here
|
||||
11 | try file.close();
|
||||
| ^
|
||||
fec/tests/own/bad_clos.fe:12:5: error: use of moved value
|
||||
12 | file.close();
|
||||
| ^
|
||||
fec/tests/own/bad_clos.fe:11:9: note: value was moved here
|
||||
11 | try file.close();
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 이동된 값을 재사용한 위치와 이동 위치를 직접 진단한다. 동일 진단이 중복 출력된다.
|
||||
|
||||
### `fec/tests/own/bad_cond.fe`
|
||||
|
||||
- 검사 대상: 조건부 이동 후 값의 무조건 사용.
|
||||
- 근거: 6행의 조건 분기 안에서 `take(p)`가 `p`를 이동할 수 있고 7행에서 무조건 `p`를 쓴다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/own/bad_cond.fe:7:5: error: use of possibly moved value
|
||||
7 | p.^ = 3;
|
||||
| ^
|
||||
fec/tests/own/bad_cond.fe:7:5: error: use of possibly moved value
|
||||
7 | p.^ = 3;
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 조건부 이동 가능성을 직접 진단한다. 동일 진단이 중복 출력된다.
|
||||
|
||||
### `fec/tests/own/bad_dbl.fe`
|
||||
|
||||
- 검사 대상: 소유 포인터의 이중 destroy.
|
||||
- 근거: 4행에서 `p`를 destroy한 뒤 5행에서 같은 `p`를 다시 destroy한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/own/bad_dbl.fe:5:17: error: use of moved value
|
||||
5 | mem.destroy(p);
|
||||
| ^
|
||||
fec/tests/own/bad_dbl.fe:4:17: note: value was moved here
|
||||
4 | mem.destroy(p);
|
||||
| ^
|
||||
fec/tests/own/bad_dbl.fe:5:17: error: use of moved value
|
||||
5 | mem.destroy(p);
|
||||
| ^
|
||||
fec/tests/own/bad_dbl.fe:4:17: note: value was moved here
|
||||
4 | mem.destroy(p);
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 두 번째 destroy의 이동 후 사용을 직접 진단한다. 동일 진단이 중복 출력된다.
|
||||
|
||||
### `fec/tests/own/bad_dest.fe`
|
||||
|
||||
- 검사 대상: owned pointer가 아닌 값을 `mem.destroy`에 전달.
|
||||
- 근거: 4행에서 일반 `i32` 값 `x`를 `mem.destroy(x)`에 전달한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/own/bad_dest.fe:4:16: error: mem.destroy requires exactly one owned pointer
|
||||
4 | mem.destroy(x);
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — `mem.destroy`의 owned pointer 요구를 직접 진단한다.
|
||||
|
||||
### `fec/tests/own/bad_drop.fe`
|
||||
|
||||
- 검사 대상: 사용자 `drop` 메서드의 직접 호출.
|
||||
- 근거: `Box`에 `drop`을 정의했지만 10행에서 `b.drop()`으로 직접 호출한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/own/bad_drop.fe:10:11: error: drop may only be invoked by scope cleanup
|
||||
10 | b.drop();
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — drop은 scope cleanup에서만 호출된다는 규칙을 직접 진단한다.
|
||||
|
||||
### `fec/tests/own/bad_loop.fe`
|
||||
|
||||
- 검사 대상: 반복문 안의 이동으로 인한 possibly-moved 값 사용.
|
||||
- 근거: 6행의 `while` 본문에서 매 반복 `take(p)`가 `p`를 이동할 수 있다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/own/bad_loop.fe:6:24: error: use of possibly moved value
|
||||
6 | while again { take(p); }
|
||||
| ^
|
||||
fec/tests/own/bad_loop.fe:6:24: error: use of possibly moved value
|
||||
6 | while again { take(p); }
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 반복에 따른 possibly-moved 상태를 직접 진단한다. 동일 진단이 중복 출력된다.
|
||||
|
||||
### `fec/tests/own/bad_move.fe`
|
||||
|
||||
- 검사 대상: 함수 인자의 이중 이동.
|
||||
- 근거: 6행의 첫 `take(p)`가 `p`를 이동한 뒤 7행에서 다시 `take(p)`를 호출한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/own/bad_move.fe:7:10: error: use of moved value
|
||||
7 | take(p);
|
||||
| ^
|
||||
fec/tests/own/bad_move.fe:6:10: note: value was moved here
|
||||
6 | take(p);
|
||||
| ^
|
||||
fec/tests/own/bad_move.fe:7:10: error: use of moved value
|
||||
7 | take(p);
|
||||
| ^
|
||||
fec/tests/own/bad_move.fe:6:10: note: value was moved here
|
||||
6 | take(p);
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — 이동된 인자의 재사용과 최초 이동 위치를 직접 진단한다. 동일 진단이 중복 출력된다.
|
||||
|
||||
### `fec/tests/own/bad_proj.fe`
|
||||
|
||||
- 검사 대상: 구조체 projection에서 non-Copy 소유 필드 이동.
|
||||
- 근거: `Holder.p`는 owned pointer이고 7행에서 `take(h.p)`로 필드 밖으로 직접 이동하려 한다.
|
||||
- 실제 진단:
|
||||
|
||||
```text
|
||||
fec/tests/own/bad_proj.fe:7:11: error: cannot move a non-Copy value out of a projection; use mem.replace
|
||||
7 | take(h.p);
|
||||
| ^
|
||||
```
|
||||
|
||||
- 일치 여부: 예 — projection에서 non-Copy 값을 이동할 수 없다는 규칙과 대안을 직접 진단한다.
|
||||
|
||||
## 판정 요약
|
||||
|
||||
- `아니오`: 없음.
|
||||
- `애매`: `fec/tests/format/bad_bufw.fe` — `io.buf_writer` 자체가 명세에 없으므로 fixture의 구체적 의도를 확정할 수 없음.
|
||||
- 나머지 36개: 실제 진단이 코드가 검사하려는 규칙과 일치.
|
||||
Reference in New Issue
Block a user