From 167a7123997c42e91d69de2203fc4c156897f0a2 Mon Sep 17 00:00:00 2001 From: Nodir Turakulov Date: Tue, 13 Oct 2015 19:09:32 -0700 Subject: [PATCH] text/template: resolve non-empty interface 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 --- src/text/template/exec.go | 5 ---- src/text/template/exec_test.go | 51 ++++++++++++++++++++++------------ 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/text/template/exec.go b/src/text/template/exec.go index 16839a8d6d..233d34a02b 100644 --- a/src/text/template/exec.go +++ b/src/text/template/exec.go @@ -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 } diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go index f9cb03eead..e507e917fe 100644 --- a/src/text/template/exec_test.go +++ b/src/text/template/exec_test.go @@ -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 {