Go

The Unified IR Format

The Unified IR Format

In the previous post, we explored how the Go compiler’s type checker analyzes your code. We saw how it resolves identifiers, checks type compatibility, and ensures your program is semantically correct.

Now that we have a fully type-checked AST, the next logical step would be to generate the compiler’s Intermediate Representation (IR)—the form it uses for optimization and code generation. But here’s something interesting: the Go compiler doesn’t immediately transform the AST into IR. Instead, it takes what might seem like a detour—it serializes the type-checked AST into a binary format, then deserializes it back into IR nodes.

The Type Checker

The Type Checker

In the previous posts, we explored the scanner—which converts source code into tokens—and the parser—which takes those tokens and builds an Abstract Syntax Tree.

In future posts, I’ll cover the Intermediate Representation (IR)—how the compiler transforms the AST into an intermediate lower-level form. But before we can get there, we need to talk about two crucial intermediate steps: type checking (this post) and the Unified IR (which I’ll cover in a separate post soon).

The Parser

The Parser

In the previous blog post, we explored the scanner—the component that converts your source code from a stream of characters into a stream of tokens.

Now we’re ready for the next step: the parser.

Here’s the challenge the parser solves: right now, we have a flat list of tokens with no relationships between them. The scanner gave us package, main, {, fmt, ., Println… but it has no idea that Println belongs to the fmt package, or that the entire fmt.Println("Hello world") statement lives inside the main function.

The Scanner

The Scanner

This is part of a series where I’ll walk you through the entire Go compiler, covering each phase from source code to executable. If you’ve ever wondered what happens when you run go build, you’re in the right place.

Note: This article is based on Go 1.25.3. The compiler internals may change in future versions, but the core concepts will likely remain the same.

I’m going to use the simplest example possible to guide us through the process—a classic “hello world” program: