| //+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 |
| } |