aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNodir Turakulov <nodir@google.com>2015-10-13 19:09:32 -0700
committerAndrew Gerrand <adg@golang.org>2015-10-15 05:02:27 +0000
commit167a7123997c42e91d69de2203fc4c156897f0a2 (patch)
treefaad77e26c53585413e6f65463fcdaf58a1fc73e /src
parent65fc379daeda784d085f98d621a9ab712c096148 (diff)
downloadgo-167a7123997c42e91d69de2203fc4c156897f0a2.tar.xz
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 <adg@golang.org>
Diffstat (limited to 'src')
-rw-r--r--src/text/template/exec.go5
-rw-r--r--src/text/template/exec_test.go51
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 {