// +build ignore package main type I interface { f() } type C int func (*C) f() {} type D struct{ ptr *int } func (D) f() {} type E struct{} func (*E) f() {} var a, b int var unknown bool // defeat dead-code elimination func interface1() { var i interface{} = &a var j interface{} = D{&b} k := j if unknown { k = i } print(i) // @types *int print(j) // @types D print(k) // @types *int | D print(i.(*int)) // @pointsto main.a print(j.(*int)) // @pointsto print(k.(*int)) // @pointsto main.a print(i.(D).ptr) // @pointsto print(j.(D).ptr) // @pointsto main.b print(k.(D).ptr) // @pointsto main.b } func interface2() { var i I = (*C)(&a) var j I = D{&a} k := j if unknown { k = i } print(i) // @types *C print(j) // @types D print(k) // @types *C | D print(k) // @pointsto makeinterface:main.D | makeinterface:*main.C k.f() // @calls main.interface2 -> (*main.C).f // @calls main.interface2 -> (main.D).f print(i.(*C)) // @pointsto main.a print(j.(D).ptr) // @pointsto main.a print(k.(*C)) // @pointsto main.a switch x := k.(type) { case *C: print(x) // @pointsto main.a case D: print(x.ptr) // @pointsto main.a case *E: print(x) // @pointsto } } func interface3() { // There should be no backflow of concrete types from the type-switch to x. var x interface{} = 0 print(x) // @types int switch x.(type) { case int: case string: } } func interface4() { var i interface{} = D{&a} if unknown { i = 123 } print(i) // @types int | D j := i.(I) // interface narrowing type-assertion print(j) // @types D print(j.(D).ptr) // @pointsto main.a var l interface{} = j // interface widening assignment. print(l) // @types D print(l.(D).ptr) // @pointsto main.a m := j.(interface{}) // interface widening type-assertion. print(m) // @types D print(m.(D).ptr) // @pointsto main.a } // Interface method calls and value flow: type J interface { f(*int) *int } type P struct { x int } func (p *P) f(pi *int) *int { print(p) // @pointsto p@i5p:6 print(pi) // @pointsto i@i5i:6 return &p.x } func interface5() { var p P // @line i5p var j J = &p var i int // @line i5i print(j.f(&i)) // @pointsto p.x@i5p:6 print(&i) // @pointsto i@i5i:6 print(j) // @pointsto makeinterface:*main.P } // @calls main.interface5 -> (*main.P).f func interface6() { f := I.f print(f) // @pointsto (main.I).f$thunk f(new(struct{ D })) } // @calls main.interface6 -> (main.I).f$thunk // @calls (main.I).f$thunk -> (*struct{main.D}).f func main() { interface1() interface2() interface3() interface4() interface5() interface6() }