base/ 확정 사항 중 아직 실제 Luau로 부딪혀본 적 없는 것(M0 스파이크 대상)을 사용자가 luau/luau-analyze/luau-lsp/Roblox Studio로 직접 돌려볼 수 있는 독립 실행 스크립트 14개 + README 색인으로 정리. 커밋 f198fd9의 정정사항(Ref 콜백/대기자 배열 소진을 None에서 nil로 되돌린 것 등)을 반영해 02번을 재작성했고, 타입 관련 실측이 필요한 항목 (Attribute 제네릭 DI 키 narrowing, Ref/PreRef 구조적 서브타입, Source/ Ref nilable-default 오버로드)을 새로 찾아 12~14번으로 추가함. 처음엔 git 자동 제외 폴더(luau-ignoreme/)에 만들었으나 커밋해서 레포에 남기기로 해 .claude/luau-test/로 이동, .claude/README.md에 색인 추가. CLAUDE.md에 세션 요약 반영 — 아직 실행 결과는 미확인. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
73 lines
3.5 KiB
Text
73 lines
3.5 KiB
Text
--!strict
|
|
--[[
|
|
검증 대상: Modifier.Overridden(mod1, mod2, ...)가 서브타입 관계인
|
|
서로 다른 Modifier 타입(FrameModifier <: GuiObjectModifier)을 섞을 때
|
|
타입이 통과하는지 — 필드 setter가 전부 self를 반환하는 fluent 타입이라
|
|
구조적 서브타이핑이 실제로 성립하는지가 관건.
|
|
|
|
배경: .claude/base/modifier-plan.md 9-2번 절, ROADMAP.md M7.
|
|
"막히는 지점"으로 문서가 지목한 것: `:BackgroundColor3` 같은 메소드가
|
|
FrameModifier에서는 FrameModifier를, GuiObjectModifier에서는
|
|
GuiObjectModifier를 리턴하므로 같은 이름 필드의 리턴 타입이 갈려서
|
|
단순 구조적 서브타이핑이 깨질 수 있음.
|
|
|
|
이 파일은 두 버전을 나란히 둠:
|
|
A) "정직한" 버전 — 메소드 리턴 타입이 각자 자기 자신
|
|
B) fallback 버전 — 문제가 생기면 쓸 `Overridden(...: any): any` 완화형
|
|
luau-analyze를 돌려서 A가 실제로 어디서 막히는지(또는 안 막히는지)
|
|
확인하는 게 목적.
|
|
|
|
실행: `luau-analyze 09-type-modifier-overridden-subtype.luau`
|
|
]]
|
|
|
|
-- ===== A) 정직한 버전 =====
|
|
|
|
export type GuiObjectModifier = {
|
|
-- Color3 대신 number로 단순화(luau-analyze 단독 실행 환경엔 Roblox 타입이 없을 수 있어서)
|
|
BackgroundColor3: (self: GuiObjectModifier, v: number) -> GuiObjectModifier,
|
|
Apply: (self: GuiObjectModifier, f: (GuiObjectModifier) -> GuiObjectModifier) -> GuiObjectModifier,
|
|
}
|
|
|
|
export type FrameModifier = {
|
|
BackgroundColor3: (self: FrameModifier, v: number) -> FrameModifier,
|
|
Apply: (self: FrameModifier, f: (FrameModifier) -> FrameModifier) -> FrameModifier,
|
|
ClipsDescendants: (self: FrameModifier, v: boolean) -> FrameModifier, -- Frame 전용 필드
|
|
}
|
|
|
|
local function fakeFrameModifier(): FrameModifier
|
|
return (nil :: any) :: FrameModifier
|
|
end
|
|
|
|
-- 시도 1: FrameModifier 값을 GuiObjectModifier 변수에 그대로 대입 — 통과하는가?
|
|
local frameMod: FrameModifier = fakeFrameModifier()
|
|
local asGuiObjectMod: GuiObjectModifier = frameMod -- <- 여기가 luau-analyze 에러 나는지 확인 포인트 1
|
|
|
|
-- 시도 2: Overridden을 GuiObjectModifier 시그니처로 선언하고 FrameModifier를 인자로 넘김
|
|
local function OverriddenHonest(...: GuiObjectModifier): GuiObjectModifier
|
|
return (nil :: any) :: GuiObjectModifier
|
|
end
|
|
local result1 = OverriddenHonest(frameMod) -- <- 확인 포인트 2
|
|
|
|
-- ===== B) fallback(any) 버전 =====
|
|
|
|
local function OverriddenLoose(...: any): any
|
|
return (nil :: any)
|
|
end
|
|
local result2 = OverriddenLoose(frameMod, asGuiObjectMod) -- 이건 항상 통과해야 함(any이므로)
|
|
|
|
print("런타임 실행 자체는 의미 없음 — luau-analyze 출력을 확인할 것")
|
|
print(result1, result2)
|
|
|
|
--[[
|
|
확인 포인트:
|
|
1. "시도 1"(asGuiObjectMod 대입)에서 luau-analyze가 에러를 내는가?
|
|
낸다면 정확한 에러 메시지(타입 불일치 상세)를 기록해둘 것 —
|
|
BackgroundColor3 필드의 리턴 타입 불일치 때문인지, 아니면 다른
|
|
이유인지가 다음 설계 결정에 중요함.
|
|
2. "시도 2"(함수 인자로 넘기기)도 같은 결과가 나오는가, 아니면 대입과
|
|
함수 인자 전달이 Luau에서 다르게 취급되는가(공변성 처리 차이 가능성).
|
|
3. A가 전부 막히면 -> .claude/base/modifier-plan.md 9-2번의 fallback대로
|
|
`Overridden(...: any): any`로 확정하고 이 항목을 M7에서 다시 열 것.
|
|
A가 통과하면 -> 서브타입 체이닝을 정식으로 타입에 반영할 수 있다는
|
|
뜻이니 그 결과를 modifier-plan.md에 반영할 것.
|
|
]]
|