Files
coollang/samples/13_lints.cool
T
coolguyandClaude Opus 5 91f3840d19 lint: 파서 오류 복구와 두 lint — 남은 부채를 턴다
파서 오류 복구:
항목 단위로만 회복한다. 문 단위로 더 잘게 회복하려 하면 파서가 추측을
하게 되고, 틀린 추측은 없는 오류를 지어낸다. 한 항목에 오류 하나가
상한이라는 것은 정직한 한계다. 동기화 지점은 중괄호 깊이 0 + 줄 첫머리
+ 선언 시작 토큰 — 셋 다 필요하다. 본문 안의 fn을 새 항목으로 오인하면
그 뒤가 전부 어긋난다. 샘플 08이 이제 오류 넷을 한 번에 보고한다.

두 lint (취향이 아니라 비용이다):
- 미사용 import는 재검사 범위를 넓힌다. 쓰지 않는 모듈의 시그니처가
  바뀌면 이 모듈이 재검사된다.
- effect 과잉 선언은 호출자에게 없는 의무를 지운다. 시그니처는 실제보다
  좁아도 안 되고 넓어도 안 된다.

과잉 선언은 effect 변수가 있거나 본문에 모르는 이름이 있으면 판정하지
않는다. 첫 구현이 샘플 03/06을 오탐으로 잡았는데, 원인이 외부 타입이었다
— 외부 capability의 메서드는 effect를 모르므로 "수행하지 않았다"고 말할
근거가 없다. saw_unknown으로 판정을 보류한다.

Resolve.error에 blocking을 나눴다. 이름 해소 실패는 뒤 단계를 막지만
lint는 막지 않는다 — lint 하나가 진짜 타입 오류를 가리면 루프가 느려진다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ZVDeU6KLuUVL3gs18Hm3E
2026-08-30 15:53:35 +09:00

36 lines
1.4 KiB
Plaintext

// 13. 두 lint — 미사용 import와 effect 과잉 선언
//
// 둘 다 취향 문제가 아니라 비용 문제다.
//
// 미사용 import: 쓰지도 않는 모듈의 시그니처가 바뀌면 이 모듈이 재검사된다.
// 증분 루프의 비용을 아무 이유 없이 넓히는 선언이다.
//
// effect 과잉 선언: 선언한 effect를 수행하지 않으면 호출자는 하지도 않는
// 일에 대한 의무를 진다 — 자기 effects 절을 넓히거나 capability를 받아온다.
// 시그니처는 실제보다 좁아도 안 되고 넓어도 안 된다.
import "cool.dev/std/list" as List
// ERROR: List을(를) 가져왔지만 쓰지 않습니다
pub capability Db {
fn read(id: Int) effects {Db.read} -> Int
fn write(id: Int) effects {Db.write}
}
// Db.write는 선언만 하고 수행하지 않는다.
pub fn only_reads(db: Db, id: Int) effects {Db.read, Db.write} -> Int {
db.read(id)
}
// ERROR: only_reads은(는) Db.write을(를) 선언했지만 수행하지 않습니다
// 정확히 선언하면 통과한다.
pub fn honest(db: Db, id: Int) effects {Db.read} -> Int {
db.read(id)
}
// effect 변수가 있으면 판정하지 않는다. e에 무엇이 묶일지는 호출 지점이
// 정하고, 본문만 보고는 알 수 없다 — 모르는 것을 틀렸다고 말하지 않는다.
pub fn polymorphic[e: effects](f: fn() effects e) effects e {
f()
}