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