mirror of
https://github.com/golang/go
synced 2024-11-18 19:44:46 -07:00
3b5de067a1
Core: reflect.TypeOf reflect.ValueOf reflect.Zero reflect.Value.Interface Maps: (reflect.Value).MapIndex (reflect.Value).MapKeys (reflect.Value).SetMapIndex (*reflect.rtype).Elem (*reflect.rtype).Key + tests: pointer/testdata/mapreflect.go. oracle/testdata/src/main/reflection.go. Interface objects (T, V...) have been renamed "tagged objects". Abstraction: we model reflect.Value similar to interface{}---as a pointer that points only to tagged objects---but a reflect.Value may also point to an "indirect tagged object", one in which the payload V is of type *T not T. These are required because reflect.Values can hold lvalues, e.g. when derived via Field() or Elem(), though we won't use them till we get to structs and pointers. Solving: each reflection intrinsic defines a new constraint and resolution rule. Because of the nature of reflection, generalizing across types, the resolution rules dynamically create additional complex constraints during solving, where previously only simple (copy) constraints were created. This requires some solver changes: The work done before the main solver loop (to attach new constraints to the graph) is now done before each iteration, in processNewConstraints. Its loop over constraints is broken into two passes: the first handles base (addr-of) constraints, the second handles simple and complex constraints. constraint.init() has been inlined. The only behaviour that varies across constraints is ptr() Sadly this will pessimize presolver optimisations, when we get there; such is the price of reflection. Objects: reflection intrinsics create objects (i.e. cause memory allocations) with no SSA operation. We will represent them as the cgnode of the instrinsic (e.g. reflect.New), so we extend Labels and node.data to represent objects as a product (not sum) of ssa.Value and cgnode and pull this out into its own type, struct object. This simplifies a number of invariants and saves space. The ntObject flag is now represented by obj!=nil; the other flags are moved into object. cgnodes are now always recorded in objects/Labels for which it is appropriate (all but those for globals, constants and the shared contours for functions). Also: - Prepopulate the flattenMemo cache to consider reflect.Value a fake pointer, not a struct. - Improve accessors and documentation on type Label. - @conctypes assertions renamed @types (since dyn. types needn't be concrete). - add oracle 'describe' test on an interface (missing, an oversight). R=crawshaw CC=golang-dev https://golang.org/cl/13418048
98 lines
2.4 KiB
Go
98 lines
2.4 KiB
Go
// +build ignore
|
|
|
|
package main
|
|
|
|
var unknown bool // defeat dead-code elimination
|
|
|
|
var a, b int
|
|
|
|
func array1() {
|
|
sliceA := make([]*int, 10) // @line a1make
|
|
sliceA[0] = &a
|
|
|
|
var sliceB []*int
|
|
sliceB = append(sliceB, &b) // @line a1append
|
|
|
|
print(sliceA) // @pointsto makeslice@a1make:16
|
|
print(sliceA[0]) // @pointsto main.a
|
|
|
|
print(sliceB) // @pointsto append@a1append:17
|
|
print(sliceB[100]) // @pointsto main.b
|
|
}
|
|
|
|
func array2() {
|
|
sliceA := make([]*int, 10) // @line a2make
|
|
sliceA[0] = &a
|
|
|
|
sliceB := sliceA[:]
|
|
|
|
print(sliceA) // @pointsto makeslice@a2make:16
|
|
print(sliceA[0]) // @pointsto main.a
|
|
|
|
print(sliceB) // @pointsto makeslice@a2make:16
|
|
print(sliceB[0]) // @pointsto main.a
|
|
}
|
|
|
|
func array3() {
|
|
a := []interface{}{"", 1}
|
|
b := []interface{}{true, func() {}}
|
|
print(a[0]) // @types string | int
|
|
print(b[0]) // @types bool | func()
|
|
}
|
|
|
|
// Test of append, copy, slice.
|
|
func array4() {
|
|
var s2 struct { // @line a4L0
|
|
a [3]int
|
|
b struct{ c, d int }
|
|
}
|
|
var sl1 = make([]*int, 10) // @line a4make
|
|
var someint int // @line a4L1
|
|
sl1[1] = &someint
|
|
sl2 := append(sl1, &s2.a[1]) // @line a4append1
|
|
print(sl1) // @pointsto makeslice@a4make:16
|
|
print(sl2) // @pointsto append@a4append1:15 | makeslice@a4make:16
|
|
print(sl1[0]) // @pointsto someint@a4L1:6 | s2.a[*]@a4L0:6
|
|
print(sl2[0]) // @pointsto someint@a4L1:6 | s2.a[*]@a4L0:6
|
|
|
|
// In z=append(x,y) we should observe flow from y[*] to x[*].
|
|
var sl3 = make([]*int, 10) // @line a4L2
|
|
_ = append(sl3, &s2.a[1])
|
|
print(sl3) // @pointsto makeslice@a4L2:16
|
|
print(sl3[0]) // @pointsto s2.a[*]@a4L0:6
|
|
|
|
var sl4 = []*int{&a} // @line a4L3
|
|
sl4a := append(sl4) // @line a4L4
|
|
print(sl4a) // @pointsto slicelit@a4L3:18 | append@a4L4:16
|
|
print(&sl4a[0]) // @pointsto slicelit[*]@a4L3:18 | append[*]@a4L4:16
|
|
print(sl4a[0]) // @pointsto main.a
|
|
|
|
var sl5 = []*int{&b} // @line a4L5
|
|
copy(sl5, sl4)
|
|
print(sl5) // @pointsto slicelit@a4L5:18
|
|
print(&sl5[0]) // @pointsto slicelit[*]@a4L5:18
|
|
print(sl5[0]) // @pointsto main.b | main.a
|
|
|
|
var sl6 = sl5[:0]
|
|
print(sl6) // @pointsto slicelit@a4L5:18
|
|
print(&sl6[0]) // @pointsto slicelit[*]@a4L5:18
|
|
print(sl6[0]) // @pointsto main.b | main.a
|
|
}
|
|
|
|
func array5() {
|
|
var arr [2]*int
|
|
arr[0] = &a
|
|
arr[1] = &b
|
|
|
|
var n int
|
|
print(arr[n]) // @pointsto main.a | main.b
|
|
}
|
|
|
|
func main() {
|
|
array1()
|
|
array2()
|
|
array3()
|
|
array4()
|
|
array5()
|
|
}
|