]> Cypherpunks repositories - gostls13.git/commitdiff
exp/template: dig into empty interfaces so a struct (say) stored in an empty
authorRob Pike <r@golang.org>
Mon, 18 Jul 2011 07:34:42 +0000 (17:34 +1000)
committerRob Pike <r@golang.org>
Mon, 18 Jul 2011 07:34:42 +0000 (17:34 +1000)
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

src/pkg/exp/template/exec.go
src/pkg/exp/template/exec_test.go

index 169c8c6918397784b8a031c64e1a8d80bbcfc061..4ec738f0dfdcbb503849b14e7947ca93bbfae36e 100644 (file)
@@ -589,12 +589,16 @@ 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.
+// 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) {
-       for v.Kind() == reflect.Ptr {
+       for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
                if v.IsNil() {
                        return v, true
                }
-               v = v.Elem()
+               if v.Kind() == reflect.Ptr || v.NumMethod() == 0 {
+                       v = v.Elem()
+               }
        }
        return v, false
 }
index efac443668e978bbd4c35285c97afd3d7e83a6fa..eb5ab71187a8b63a75f9f355846d5afbfb8f0245 100644 (file)
@@ -69,7 +69,7 @@ var tVal = &T{
        Empty1: 3,
        Empty2: "empty2",
        Empty3: []int{7, 8},
-       Empty4: &U{"v"},
+       Empty4: &U{"UinEmpty"},
        PI:     newInt(23),
        PSI:    newIntSlice(21, 22, 23),
        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 string", "{{.Empty2}}", "empty2", 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.
        {".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 emptymap", "{{with .MSIEmpty}}{{.}}{{else}}EMPTY{{end}}", "EMPTY", 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 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},