본문으로 건너뛰기
피드

Go 1.26의 타입 생성(Type Construction)과 순환 감지(Cycle Detection) 개선

backend 약 5분

Go 1.26에서 타입 체커의 타입 생성 알고리즘을 개선해 재귀 타입과 배열 크기 계산 시 발생하던 순환 감지 문제를 체계적으로 해결했다. 불완전한 값이 다운스트림으로 퍼지기 전에 업스트림에서 차단하는 새로운 접근법으로 여러 컴파일러 패닉을 수정.

  • 1

    타입 완전성(completeness)이 타입 분해(deconstruction)의 전제 조건

  • 2

    재귀 타입에서는 루프 내 타입이 동시에 완성되는 트릭으로 해결

  • 3

    배열 크기에 unsafe.Sizeof(T{}) 같은 순환 정의는 교착 상태 유발

  • 4

    불완전한 값의 업스트림(변환, 함수 호출 등)에서 완전성 즉시 체크

  • 5

    컴파일러 패닉 #75918, #76383 등 다수 해결

  • Go 컴파일러에서 타입 체커가 AST를 순회하면서 각 타입의 내부 표현을 구성하는 과정을 타입 생성(type construction)이라고 함. Go 1.26에서 이 부분을 상당히 개선했는데, 사용자 관점에서는 변화가 거의 없지만 미래 개선을 위한 기반 작업임

기본 타입 생성 과정

  • type T []Utype U *int 같은 단순 선언의 경우: T를 만나면 Defined 구조체를 생성하고, 아직 평가 안 된 []U의 underlying은 nil. U를 찾아가서 *int를 평가하고, int는 미리 선언된(predeclared) 타입이라 이미 완성 상태. 그러면 역순으로 *intU[]UT가 차례로 완성됨

  • 타입 완전성(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가 단순한 타입 시스템으로 유명하지만, 재귀 타입 + 크기가 있는 배열 타입이 만나면 생각보다 복잡한 문제가 숨어 있다는 거임. 프로그래머로서 당연하게 쓰는 기능 뒤에 있는 미묘한 복잡성을 들여다보는 재미있는 글

Go의 단순한 타입 시스템 이면에 숨은 미묘한 복잡성을 보여주는 흥미로운 글. 재귀 타입 + 크기 있는 배열의 조합이 만드는 문제가 생각보다 깊음.

댓글

댓글

댓글을 불러오는 중...

backend

Cloudflare가 잡아낸 QUIC CUBIC 버그, ‘idle’ 한 줄 오판이 다운로드를 죽였다

Cloudflare의 QUIC 구현체 quiche에서 CUBIC 혼잡 제어가 최소 윈도우에 갇혀 회복하지 못하는 버그가 발견됐다. Linux 커널의 idle 최적화를 QUIC에 옮기는 과정에서 TCP와 QUIC의 이벤트 타이밍 차이를 놓쳤고, 결국 ACK 시점을 기준으로 idle 시간을 재도록 고쳐 100% 테스트 통과를 회복했다.

backend

삼성전자가 반도체 개발 조직에 오라클 자바를 공식 채택한 이유

삼성전자 DS 부문이 글로벌 반도체 개발 환경에 오라클 자바 SE 유니버설 서브스크립션을 공식 채택했다. 서로 다른 자바 배포판과 버전이 섞이면서 생길 수 있는 보안, 컴플라이언스, 라이선스 리스크를 줄이고 개발 환경을 표준화하려는 결정이다.

backend

네이버클라우드, 트래픽 따라 알아서 줄고 느는 서버리스 데이터베이스 출시

네이버클라우드가 사용량에 따라 CPU, 메모리, 스토리지를 자동 조절하는 완전관리형 서버리스 데이터베이스 서비스를 내놨다. 기존 가상머신 기반 관리형 데이터베이스처럼 피크 트래픽에 맞춰 서버를 과하게 잡아두는 방식에서 벗어나, 사용량 기반 과금과 오토스케일링으로 비용 낭비를 줄이겠다는 방향이다.

backend

네이버클라우드, 사용량 따라 늘고 줄어드는 서버리스 데이터베이스 출시

네이버클라우드가 완전관리형 서버리스 데이터베이스 서비스인 Cloud DB Serverless를 출시했다. VM 기반 관리형 데이터베이스의 고정 비용과 과잉 프로비저닝 문제를 줄이고, 트래픽에 따라 CPU·메모리·스토리지를 자동 조절하는 구조를 내세운다.

backend

네이버클라우드, 사용량 따라 자동 확장되는 서버리스 데이터베이스 출시

네이버클라우드가 사용량에 따라 컴퓨팅 자원을 자동 조절하는 서버리스 기반 클라우드 데이터베이스를 출시했음. 기존 가상머신 기반 관리형 데이터베이스의 고정 비용과 운영 부담을 줄이고, 국내 데이터 규제 요구까지 맞추겠다는 전략임.