//+build ignore package main // This file is the input to TestObjValueLookup in source_test.go, // which ensures that each occurrence of an ident defining or // referring to a func, var or const object can be mapped to its // corresponding SSA Value. // // For every reference to a var object, we use annotations in comments // to denote both the expected SSA Value kind, and whether to expect // its value (x) or its address (&x). // // For const and func objects, the results don't vary by reference and // are always values not addresses, so no annotations are needed. The // declaration is enough. import "fmt" import "os" type J int func (*J) method() {} const globalConst = 0 var globalVar int // &globalVar::Global func globalFunc() {} type I interface { interfaceMethod() } type S struct { x int // x::nil } func main() { print(globalVar) // globalVar::UnOp globalVar = 1 // globalVar::Const var v0 int = 1 // v0::Const (simple local value spec) if v0 > 0 { // v0::Const v0 = 2 // v0::Const } print(v0) // v0::Phi // v1 is captured and thus implicitly address-taken. var v1 int = 1 // v1::Const v1 = 2 // v1::Const fmt.Println(v1) // v1::UnOp (load) f := func(param int) { // f::MakeClosure param::Parameter if y := 1; y > 0 { // y::Const print(v1, param) // v1::UnOp (load) param::Parameter } param = 2 // param::Const println(param) // param::Const } f(0) // f::MakeClosure var v2 int // v2::Const (implicitly zero-initialized local value spec) print(v2) // v2::Const m := make(map[string]int) // m::MakeMap // Local value spec with multi-valued RHS: var v3, v4 = m[""] // v3::Extract v4::Extract m::MakeMap print(v3) // v3::Extract print(v4) // v4::Extract v3++ // v3::BinOp (assign with op) v3 += 2 // v3::BinOp (assign with op) v5, v6 := false, "" // v5::Const v6::Const (defining assignment) print(v5) // v5::Const print(v6) // v6::Const var v7 S // &v7::Alloc v7.x = 1 // &v7::Alloc &x::FieldAddr print(v7.x) // &v7::Alloc &x::FieldAddr var v8 [1]int // &v8::Alloc v8[0] = 0 // &v8::Alloc print(v8[:]) // &v8::Alloc _ = v8[0] // &v8::Alloc _ = v8[:][0] // &v8::Alloc v8ptr := &v8 // v8ptr::Alloc &v8::Alloc _ = v8ptr[0] // v8ptr::Alloc _ = *v8ptr // v8ptr::Alloc v8a := make([]int, 1) // v8a::Slice v8a[0] = 0 // v8a::Slice print(v8a[:]) // v8a::Slice v9 := S{} // &v9::Alloc v10 := &v9 // v10::Alloc &v9::Alloc _ = v10 // v10::Alloc var v11 *J = nil // v11::Const v11.method() // v11::Const var v12 J // &v12::Alloc v12.method() // &v12::Alloc (implicitly address-taken) // NB, in the following, 'method' resolves to the *types.Func // of (*J).method, so it doesn't help us locate the specific // ssa.Values here: a bound-method closure and a promotion // wrapper. _ = v11.method // v11::Const _ = (*struct{ J }).method // J::nil // These vars are not optimised away. if false { v13 := 0 // v13::Const println(v13) // v13::Const } switch x := 1; x { // x::Const case v0: // v0::Phi } for k, v := range m { // k::Extract v::Extract m::MakeMap _ = k // k::Extract v++ // v::BinOp } if y := 0; y > 1 { // y::Const y::Const } var i interface{} // i::Const (nil interface) i = 1 // i::MakeInterface switch i := i.(type) { // i::MakeInterface i::MakeInterface case int: println(i) // i::Extract } ch := make(chan int) // ch::MakeChan select { case x := <-ch: // x::UnOp (receive) ch::MakeChan _ = x // x::UnOp } // .Op is an inter-package FieldVal-selection. var err os.PathError // &err::Alloc _ = err.Op // &err::Alloc &Op::FieldAddr _ = &err.Op // &err::Alloc &Op::FieldAddr // Exercise corner-cases of lvalues vs rvalues. // (Guessing IsAddr from the 'pointerness' won't cut it here.) type N *N var n N // n::Const n1 := n // n1::Const n::Const n2 := &n1 // n2::Alloc &n1::Alloc n3 := *n2 // n3::UnOp n2::Alloc n4 := **n3 // n4::UnOp n3::UnOp _ = n4 // n4::UnOp }