]> Cypherpunks repositories - gostls13.git/commitdiff
exp/template: do not take address of interface variable to find methods.
authorRob Pike <r@golang.org>
Tue, 9 Aug 2011 07:07:29 +0000 (17:07 +1000)
committerRob Pike <r@golang.org>
Tue, 9 Aug 2011 07:07:29 +0000 (17:07 +1000)
Also allow struct values as "with" targets.

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/4809086

src/pkg/exp/template/exec.go
src/pkg/exp/template/exec_test.go

index 6fc1da4a49c7e2430fa5cddccfae9c4464725694..7d7a9c73268921f1f8f4a0b4c91daec94649bf9c 100644 (file)
@@ -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 {
index 415f170080d039bf6fde35242569f621daa532bf..b7884744027e6d68151359848002cf5113ec6800 100644 (file)
@@ -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 {