]> Cypherpunks repositories - gostls13.git/commitdiff
text/template: resolve non-empty interface
authorNodir Turakulov <nodir@google.com>
Wed, 14 Oct 2015 02:09:32 +0000 (19:09 -0700)
committerAndrew Gerrand <adg@golang.org>
Thu, 15 Oct 2015 05:02:27 +0000 (05:02 +0000)
Read what a non-empty interface points to.

The deleted lines were added in https://codereview.appspot.com/4810060/,
which attempted to break an infinite loop. That was a long time ago.
If I just delete these lines with current codebase, the test "bug1"
(added in that CL) does not fail.

All new tests fail without this fix.

Fixes #12924

Change-Id: I9370ca44facd6af3019850aa065b936e5a482d37
Reviewed-on: https://go-review.googlesource.com/15809
Reviewed-by: Andrew Gerrand <adg@golang.org>
src/text/template/exec.go
src/text/template/exec_test.go

index 16839a8d6dd6c8db1fa8d68530f4d2f948ac0090..233d34a02bc6e30ed4e8a36a58137e4a6e9cf9e2 100644 (file)
@@ -829,16 +829,11 @@ func (s *state) evalEmptyInterface(dot reflect.Value, n parse.Node) reflect.Valu
 }
 
 // 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 || v.Kind() == reflect.Interface; v = v.Elem() {
                if v.IsNil() {
                        return v, true
                }
-               if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
-                       break
-               }
        }
        return v, false
 }
index f9cb03eead8f94bf7bf0a7a1cc6582bc9b7a360f..e507e917fe51aa48b4e785b01aef3815b71aaf8f 100644 (file)
@@ -51,8 +51,9 @@ type T struct {
        Empty2 interface{}
        Empty3 interface{}
        Empty4 interface{}
-       // Non-empty interface.
-       NonEmptyInterface I
+       // Non-empty interfaces.
+       NonEmptyInterface    I
+       NonEmptyInterfacePtS *I
        // Stringer.
        Str fmt.Stringer
        Err error
@@ -73,6 +74,12 @@ type T struct {
        unexported int
 }
 
+type S []string
+
+func (S) Method0() string {
+       return "M0"
+}
+
 type U struct {
        V string
 }
@@ -99,6 +106,8 @@ func (w *W) Error() string {
        return fmt.Sprintf("[%d]", w.k)
 }
 
+var siVal = I(S{"a", "b"})
+
 var tVal = &T{
        True:   true,
        I:      17,
@@ -119,22 +128,23 @@ var tVal = &T{
                {"one": 1, "two": 2},
                {"eleven": 11, "twelve": 12},
        },
-       Empty1:            3,
-       Empty2:            "empty2",
-       Empty3:            []int{7, 8},
-       Empty4:            &U{"UinEmpty"},
-       NonEmptyInterface: new(T),
-       Str:               bytes.NewBuffer([]byte("foozle")),
-       Err:               errors.New("erroozle"),
-       PI:                newInt(23),
-       PS:                newString("a string"),
-       PSI:               newIntSlice(21, 22, 23),
-       BinaryFunc:        func(a, b string) string { return fmt.Sprintf("[%s=%s]", a, b) },
-       VariadicFunc:      func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") },
-       VariadicFuncInt:   func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") },
-       NilOKFunc:         func(s *int) bool { return s == nil },
-       ErrFunc:           func() (string, error) { return "bla", nil },
-       Tmpl:              Must(New("x").Parse("test template")), // "x" is the value of .X
+       Empty1:               3,
+       Empty2:               "empty2",
+       Empty3:               []int{7, 8},
+       Empty4:               &U{"UinEmpty"},
+       NonEmptyInterface:    &T{X: "x"},
+       NonEmptyInterfacePtS: &siVal,
+       Str:                  bytes.NewBuffer([]byte("foozle")),
+       Err:                  errors.New("erroozle"),
+       PI:                   newInt(23),
+       PS:                   newString("a string"),
+       PSI:                  newIntSlice(21, 22, 23),
+       BinaryFunc:           func(a, b string) string { return fmt.Sprintf("[%s=%s]", a, b) },
+       VariadicFunc:         func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") },
+       VariadicFuncInt:      func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") },
+       NilOKFunc:            func(s *int) bool { return s == nil },
+       ErrFunc:              func() (string, error) { return "bla", nil },
+       Tmpl:                 Must(New("x").Parse("test template")), // "x" is the value of .X
 }
 
 // A non-empty interface.
@@ -550,6 +560,11 @@ var execTests = []execTest{
        {"bug16i", "{{\"aaa\"|oneArg}}", "oneArg=aaa", tVal, true},
        {"bug16j", "{{1+2i|printf \"%v\"}}", "(1+2i)", tVal, true},
        {"bug16k", "{{\"aaa\"|printf }}", "aaa", tVal, true},
+       {"bug17a", "{{.NonEmptyInterface.X}}", "x", tVal, true},
+       {"bug17b", "-{{.NonEmptyInterface.Method1 1234}}-", "-1234-", tVal, true},
+       {"bug17c", "{{len .NonEmptyInterfacePtS}}", "2", tVal, true},
+       {"bug17d", "{{index .NonEmptyInterfacePtS 0}}", "a", tVal, true},
+       {"bug17e", "{{range .NonEmptyInterfacePtS}}-{{.}}-{{end}}", "-a--b-", tVal, true},
 }
 
 func zeroArgs() string {