153 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			153 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
| // +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()
 | |
| }
 |