Skip to content

Draft: Understanding the Go Compiler ‐ Part 1: From AST to IR

xhd2015 edited this page Apr 7, 2024 · 2 revisions

Introduction

Here is an illegal program that normal go compiler will fail to compile:

package debug

import (
	"testing"
)

const N = 50

func TestPatchConstInAssignmentShouldWork(t *testing.T) {
	n := N
	getN(n)
}

func printN(n int64) {
    fmt.Printf("n=%d\n", n)
}

Run:

go test ./

Output:

demo_test.go:20:7: cannot use n (variable of type int) as int64 value in argument to printN
FAIL    github.com/xhd2015/xgo/runtime/test/debug [build failed]

As the message says, n has type int, while printN accepts int64, without a conversion, go refused to compile the program.

Goal

Our goal is to make the above program compile, without modifying the source code.

We will dig in depth the go compiler, and some of its code.

In this process, we will understand how go process the source code internally, and what stages are invovled.

The AST

Draft:

N type

__trap_x() N

CallExpr{
    TypeCast {
    fn: Type,
    Args: [CallExpr{
        fn: __trap_const,
        args: (pkg,name,value)
    }]
}
}

int64(__trap().(int))


X.(int) assert expr Type=int,value=nil


helper:
    a typeof helper

    Typeof(x*y) --> does nothing, instead it extracts

    // best compatibility
    SimpleConvert(__trap().(int)) 
    
    // not always working
    var x Typeof(expr) = d

Implicit Type Conversions

Three kinds:

  1. assignment
  2. binary operation
  3. switch case comparision