aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2011-08-09 17:07:29 +1000
committerRob Pike <r@golang.org>2011-08-09 17:07:29 +1000
commit1adda4601aa9c28199f265d5826fd9c31ee73f64 (patch)
tree5acf1373f392e18c5c50526fba84f907a40fcec3
parent7506ee75847f94a536d3defa854efe4b361379d7 (diff)
downloadgo-1adda4601aa9c28199f265d5826fd9c31ee73f64.tar.gz
go-1adda4601aa9c28199f265d5826fd9c31ee73f64.zip
exp/template: do not take address of interface variable to find methods.
Also allow struct values as "with" targets. R=golang-dev, dsymonds CC=golang-dev https://golang.org/cl/4809086
-rw-r--r--src/pkg/exp/template/exec.go8
-rw-r--r--src/pkg/exp/template/exec_test.go25
2 files changed, 21 insertions, 12 deletions
diff --git a/src/pkg/exp/template/exec.go b/src/pkg/exp/template/exec.go
index 6fc1da4a49..7d7a9c7326 100644
--- a/src/pkg/exp/template/exec.go
+++ b/src/pkg/exp/template/exec.go
@@ -179,6 +179,8 @@ func isTrue(val reflect.Value) (truth, ok bool) {
truth = val.Float() != 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
truth = val.Uint() != 0
+ case reflect.Struct:
+ truth = true // Struct values are always true.
default:
return
}
@@ -377,10 +379,10 @@ func (s *state) evalField(dot reflect.Value, fieldName string, args []parse.Node
}
typ := receiver.Type()
receiver, _ = indirect(receiver)
- // Need to get to a value of type *T to guarantee we see all
- // methods of T and *T.
+ // Unless it's an interface, need to get to a value of type *T to guarantee
+ // we see all methods of T and *T.
ptr := receiver
- if ptr.CanAddr() {
+ if ptr.Kind() != reflect.Interface && ptr.CanAddr() {
ptr = ptr.Addr()
}
if method, ok := methodByName(ptr, fieldName); ok {
diff --git a/src/pkg/exp/template/exec_test.go b/src/pkg/exp/template/exec_test.go
index 415f170080..b788474402 100644
--- a/src/pkg/exp/template/exec_test.go
+++ b/src/pkg/exp/template/exec_test.go
@@ -43,6 +43,8 @@ type T struct {
Empty2 interface{}
Empty3 interface{}
Empty4 interface{}
+ // Non-empty interface.
+ NonEmptyInterface I
// Pointers
PI *int
PSI *[]int
@@ -69,13 +71,14 @@ var tVal = &T{
{"one": 1, "two": 2},
{"eleven": 11, "twelve": 12},
},
- Empty1: 3,
- Empty2: "empty2",
- Empty3: []int{7, 8},
- Empty4: &U{"UinEmpty"},
- PI: newInt(23),
- PSI: newIntSlice(21, 22, 23),
- 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: new(T),
+ PI: newInt(23),
+ PSI: newIntSlice(21, 22, 23),
+ Tmpl: Must(New("x").Parse("test template")), // "x" is the value of .X
}
// A non-empty interface.
@@ -358,8 +361,12 @@ var execTests = []execTest{
// 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},
// 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},
+ // The bug appears with *interface only; looped forever.
+ {"bug1", "{{.Method0}}", "M0", &iVal, true},
+ // Was taking address of interface field, so method set was empty.
+ {"bug2", "{{$.NonEmptyInterface.Method0}}", "M0", tVal, true},
+ // Struct values were not legal in with - mere oversight.
+ {"bug4", "{{with $}}{{.Method0}}{{end}}", "M0", tVal, true},
}
func zeroArgs() string {