Go 1.26의 타입 생성(Type Construction)과 순환 감지(Cycle Detection) 개선
요약
기사 전체 정리
Go 1.26의 타입 생성(Type Construction)과 순환 감지(Cycle Detection) 개선
- Go 컴파일러에서 타입 체커가 AST를 순회하면서 각 타입의 내부 표현을 구성하는 과정을 **타입 생성(type construction)**이라고 함. Go 1.26에서 이 부분을 상당히 개선했는데, 사용자 관점에서는 변화가 거의 없지만 미래 개선을 위한 기반 작업임
기본 타입 생성 과정
type T []U와type U *int같은 단순 선언의 경우: T를 만나면 Defined 구조체를 생성하고, 아직 평가 안 된[]U의 underlying은 nil.U를 찾아가서*int를 평가하고,int는 미리 선언된(predeclared) 타입이라 이미 완성 상태. 그러면 역순으로*int→U→[]U→T가 차례로 완성됨타입 **완전성(completeness)**이 핵심 속성: 모든 내부 필드가 채워지고, 참조하는 타입들도 모두 완성된 상태를 의미함. 완전해야 타입을 분해(deconstruct)해서 내부를 들여다보는 게 안전함
재귀 타입에서 복잡해지는 부분
type T []U; type U *T같은 재귀 타입에서는*T의 base 타입이 아직 완성 안 된T를 가리키게 됨. 이때는 "나중에 T가 완성되면 괜찮아질 것"이라 가정하고 일단 포인터만 연결해둠. 루프 안의 타입들이 동시에 완성되면서 해결됨재귀 타입이 등장하면 "평가 결과가 항상 완전한 타입"이라는 편리한 속성이 깨짐. 그래서 map 키의 comparable 체크 같은 분해가 필요한 검사는 타입 체킹 마지막에 모든 타입이 완성된 후로 지연시킴
진짜 문제: 배열 크기와 불완전한 값
type T [unsafe.Sizeof(T{})]int같은 경우가 진짜 골치아픔. 배열의 크기를 계산하려면 T의 크기를 알아야 하는데, T의 크기는 배열이 완성돼야 알 수 있음. T는 배열 완성을 기다리고, 배열은 T 완성을 기다리는 교착 상태이건 순환 정의(cyclic definition) 에러.
type T T도 같은 류의 문제임Go 1.26의 해법: 불완전한 값(incomplete value)이 생성되는 업스트림 지점(변환, 함수 호출, 타입 단언, 채널 수신, 맵 접근, 역참조 등)에서 결과 타입의 완전성을 즉시 체크. 불완전하면 순환 에러를 보고하고 invalid operand를 반환해서 불완전한 값이 다운스트림으로 퍼지는 걸 차단함
예외적으로
type T [unsafe.Sizeof(new(T))]int는 유효함.*T타입인 값의 크기는 T의 내부를 몰라도 알 수 있기 때문 (모든 포인터 크기는 동일)
중요
> 이 개선으로 기존에 발생하던 여러 컴파일러 패닉(#75918, #76383, #76384, #76478 등)이 해결됨. 기존의 복잡한 bespoke 순환 감지를 더 단순하고 체계적인 접근으로 교체한 것.
- 저자의 결론: Go가 단순한 타입 시스템으로 유명하지만, 재귀 타입 + 크기가 있는 배열 타입이 만나면 생각보다 복잡한 문제가 숨어 있다는 거임. 프로그래머로서 당연하게 쓰는 기능 뒤에 있는 미묘한 복잡성을 들여다보는 재미있는 글
댓글
댓글
댓글을 불러오는 중...