mirror of
https://github.com/golang/go
synced 2024-11-22 06:04:39 -07:00
exp/template: dig into empty interfaces so a struct (say) stored in an empty
interface field can be unpacked. We don't have type assertions here so we must be forthright. R=golang-dev, adg CC=golang-dev https://golang.org/cl/4757047
This commit is contained in:
parent
ab55133ca9
commit
9a5bb287e8
@ -589,13 +589,17 @@ func (s *state) evalEmptyInterface(dot reflect.Value, n node) reflect.Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
|
// indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
|
||||||
|
// We indirect through pointers and empty interfaces (only) because
|
||||||
|
// non-empty interfaces have methods we might need.
|
||||||
func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
|
func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
|
||||||
for v.Kind() == reflect.Ptr {
|
for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
|
||||||
if v.IsNil() {
|
if v.IsNil() {
|
||||||
return v, true
|
return v, true
|
||||||
}
|
}
|
||||||
|
if v.Kind() == reflect.Ptr || v.NumMethod() == 0 {
|
||||||
v = v.Elem()
|
v = v.Elem()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return v, false
|
return v, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ var tVal = &T{
|
|||||||
Empty1: 3,
|
Empty1: 3,
|
||||||
Empty2: "empty2",
|
Empty2: "empty2",
|
||||||
Empty3: []int{7, 8},
|
Empty3: []int{7, 8},
|
||||||
Empty4: &U{"v"},
|
Empty4: &U{"UinEmpty"},
|
||||||
PI: newInt(23),
|
PI: newInt(23),
|
||||||
PSI: newIntSlice(21, 22, 23),
|
PSI: newIntSlice(21, 22, 23),
|
||||||
Tmpl: New("x").MustParse("test template"), // "x" is the value of .X
|
Tmpl: New("x").MustParse("test template"), // "x" is the value of .X
|
||||||
@ -210,7 +210,8 @@ var execTests = []execTest{
|
|||||||
{"empty with int", "{{.Empty1}}", "3", tVal, true},
|
{"empty with int", "{{.Empty1}}", "3", tVal, true},
|
||||||
{"empty with string", "{{.Empty2}}", "empty2", tVal, true},
|
{"empty with string", "{{.Empty2}}", "empty2", tVal, true},
|
||||||
{"empty with slice", "{{.Empty3}}", "[7 8]", tVal, true},
|
{"empty with slice", "{{.Empty3}}", "[7 8]", tVal, true},
|
||||||
{"empty with struct", "{{.Empty4}}", "{v}", tVal, true},
|
{"empty with struct", "{{.Empty4}}", "{UinEmpty}", tVal, true},
|
||||||
|
{"empty with struct, field", "{{.Empty4.V}}", "UinEmpty", tVal, true},
|
||||||
|
|
||||||
// Method calls.
|
// Method calls.
|
||||||
{".Method0", "-{{.Method0}}-", "-M0-", tVal, true},
|
{".Method0", "-{{.Method0}}-", "-M0-", tVal, true},
|
||||||
@ -308,7 +309,7 @@ var execTests = []execTest{
|
|||||||
{"with slice", "{{with .SI}}{{.}}{{else}}EMPTY{{end}}", "[3 4 5]", tVal, true},
|
{"with slice", "{{with .SI}}{{.}}{{else}}EMPTY{{end}}", "[3 4 5]", tVal, true},
|
||||||
{"with emptymap", "{{with .MSIEmpty}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
|
{"with emptymap", "{{with .MSIEmpty}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
|
||||||
{"with map", "{{with .MSIone}}{{.}}{{else}}EMPTY{{end}}", "map[one:1]", tVal, true},
|
{"with map", "{{with .MSIone}}{{.}}{{else}}EMPTY{{end}}", "map[one:1]", tVal, true},
|
||||||
{"with empty interface, struct field", "{{with .Empty4}}{{.V}}{{end}}", "v", tVal, true},
|
{"with empty interface, struct field", "{{with .Empty4}}{{.V}}{{end}}", "UinEmpty", tVal, true},
|
||||||
{"with $x int", "{{with $x := .I}}{{$x}}{{end}}", "17", tVal, true},
|
{"with $x int", "{{with $x := .I}}{{$x}}{{end}}", "17", tVal, true},
|
||||||
{"with $x struct.U.V", "{{with $x := $}}{{$x.U.V}}{{end}}", "v", tVal, true},
|
{"with $x struct.U.V", "{{with $x := $}}{{$x.U.V}}{{end}}", "v", tVal, true},
|
||||||
{"with variable and action", "{{with $x := $}}{{$y := $.U.V}},{{$y}}{{end}}", "v,v", tVal, true},
|
{"with variable and action", "{{with $x := $}}{{$y := $.U.V}},{{$y}}{{end}}", "v,v", tVal, true},
|
||||||
|
Loading…
Reference in New Issue
Block a user