Commit 7162f39f authored by Robert Griesemer's avatar Robert Griesemer

exp/template: fix endless loop

No progress was made in indirect() if the reflect.Value
was an non-nil and non-empty interface.

R=r, r
CC=golang-dev
https://golang.org/cl/4810060
parent bf184398
...@@ -585,12 +585,12 @@ func (s *state) evalEmptyInterface(dot reflect.Value, n node) reflect.Value { ...@@ -585,12 +585,12 @@ func (s *state) evalEmptyInterface(dot reflect.Value, n node) reflect.Value {
// We indirect through pointers and empty interfaces (only) because // We indirect through pointers and empty interfaces (only) because
// non-empty interfaces have methods we might need. // 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 || v.Kind() == reflect.Interface { for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
if v.IsNil() { if v.IsNil() {
return v, true return v, true
} }
if v.Kind() == reflect.Ptr || v.NumMethod() == 0 { if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
v = v.Elem() break
} }
} }
return v, false return v, false
......
...@@ -75,6 +75,13 @@ var tVal = &T{ ...@@ -75,6 +75,13 @@ var tVal = &T{
Tmpl: Must(New("x").Parse("test template")), // "x" is the value of .X Tmpl: Must(New("x").Parse("test template")), // "x" is the value of .X
} }
// A non-empty interface.
type I interface {
Method0() string
}
var iVal I = tVal
// Helpers for creation. // Helpers for creation.
func newInt(n int) *int { func newInt(n int) *int {
p := new(int) p := new(int)
...@@ -344,6 +351,9 @@ var execTests = []execTest{ ...@@ -344,6 +351,9 @@ var execTests = []execTest{
// Fixed bugs. // Fixed bugs.
// Must separate dot and receiver; otherwise args are evaluated with dot set to variable. // Must separate dot and receiver; otherwise args are evaluated with dot set to variable.
{"bug0", "{{range .MSIone}}{{if $.Method1 .}}X{{end}}{{end}}", "X", tVal, true}, {"bug0", "{{range .MSIone}}{{if $.Method1 .}}X{{end}}{{end}}", "X", tVal, true},
// Do not loop endlessly in indirect for non-empty interfaces.
// The bug appears with *interface only; this is supposed to fail (cannot invoke Method0), but terminate.
{"bug1", "{{.Method0}}", "", &iVal, false},
} }
func zeroArgs() string { func zeroArgs() string {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment