diff --git a/.claude/base/modifier-plan.md b/.claude/base/modifier-plan.md index 0e5894e..ae9eb76 100644 --- a/.claude/base/modifier-plan.md +++ b/.claude/base/modifier-plan.md @@ -389,6 +389,36 @@ Modifier 값을 변수/모듈 상수로 만들어 재사용하는, 기존에도 근거 없는 선제 최적화라 설계하지 않음 — CLAUDE.md의 "드문 오용/가상 미래 요구까지 방어/최적화하려고 구조를 복잡하게 만들지 않는다" 원칙과 동일. +### 9-2. `Override`가 서로 다른(그러나 상하위 관계인) Modifier 타입을 섞는 경우 — +타입 시그니처 미확정, 실 Luau 테스트 필요 (2026-08-07 다섯 번째 세션 후속) + +**문제**: Modifier 타입은 위 4번 절 "FrameModifier 타입" 언급대로 Roblox +클래스별로 생성기가 뽑아내는 flat 타입인데, 그 밑의 Roblox 클래스 자체엔 +서브타입 관계가 있음(`Frame`이 `GuiObject`의 서브클래스) — 그럼 생성된 +`FrameModifier`도 `GuiObjectModifier`의 서브타입이어야 자연스럽고, 실제로 +`Modifier.Override(guiObjectMod, frameMod)`처럼 공통 상위 클래스 스타일 +프리셋과 하위 클래스 전용 보정을 섞어 합치는 패턴이 필요해 보임(사용자 +지적, 2026-08-07). + +**막히는 지점**: 필드 setter 메소드(`:FontSize` 류)는 각 타입마다 반환 +타입이 자기 자신(`self`, 즉 `FrameModifier`는 `FrameModifier`를, +`GuiObjectModifier`는 `GuiObjectModifier`를 리턴)이라, 같은 이름의 메소드 +필드끼리 리턴 타입이 갈려서 단순 구조적 서브타이핑만으로는 안 풀릴 가능성이 +있음. + +**후보안(미검증)**: 같은 이름의 메소드 필드는 리턴 타입이 다르니 그냥 +`any`로 뭉개고, 나머지(메소드가 아닌 순수 데이터 필드) 쪽만 `[string]: nil`류 +인덱스 시그니처 조건이 성립하면 통과시키는 식으로 서브타입 호환을 흉내낼 수 +있는지 — 이게 실제로 Luau 솔버에서 받아들여지는 타입 구성인지는 추론만으로 +결론 낼 수 없고 실제 코드로 테스트해봐야 함(M0가 이미 검증 대상으로 삼은 +"추론만으로 확정하고 실제 Luau로 부딪혀본 적 없는 것"과 같은 성격의 모호함). + +**당장의 fallback**: 위 후보안이 Luau에서 실제로 안 먹히는 걸로 확인되면, +`Modifier.Override`의 타입 시그니처를 일단 `Override(...: any): any`류로 +느슨하게 열어 정적 체크를 포기 — 이건 임시 처치로 명시하고, M7 실제 구현 +시점에 실 테스트 결과에 따라 다시 좁히는 걸 목표로 로드맵에 남김 +(`ROADMAP.md` M7). + **`:Peek<>(key): T | State | nil`** — Modifier 필드를 확정하지 않고 그대로 읽는 접근자. 이름을 `Get`이 아니라 `Peek`로 정한 이유: 이 프로젝트 전역에서 `State:Get()`은 "확정한다"(pull + recompute + 최종값 diff --git a/ROADMAP.md b/ROADMAP.md index dfedd72..b267f66 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -94,6 +94,10 @@ Luau 코드로 부딪혀본 적 없는 세 가지**를 던지는 코드로 검 - [ ] flatten-before-dispatch, immutable `table.clone` 체이닝 - [ ] `Modifier.Override(mod1, mod2, ...)`(가칭, 구 `Merge`) — 필드별 raw 덮어쓰기, 특별한 State/함수 분기 불필요(`modifier-plan.md` 9번) +- [ ] `Override`가 서브타입 관계인 서로 다른 Modifier 타입(예: `FrameModifier`/ + `GuiObjectModifier`)을 섞을 때의 타입 시그니처 실 Luau 테스트 + (`modifier-plan.md` 9-2번, 미검증 — 안 되면 일단 `Override(...: any): + any`로 느슨하게 열어두고 이 항목으로 되돌아올 것) - [ ] `State` 조합 타입 차단 확인(`modifier-plan.md` 7번, UB 확정) - [ ] `:Apply(factory)` 팩토리 함수 체이닝(`modifier-plan.md` 8번, 예약 키 `Apply`가 제네릭 `__index` 필드 setter와 안 겹치는지 확인)