]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.r60] template: indirect or dereference function arguments if necessar...
authorAndrew Gerrand <adg@golang.org>
Thu, 8 Sep 2011 01:15:38 +0000 (11:15 +1000)
committerAndrew Gerrand <adg@golang.org>
Thu, 8 Sep 2011 01:15:38 +0000 (11:15 +1000)
««« CL 4967056 / a163a464ef59
template: indirect or dereference function arguments if necessary to match the type of the formal.
Fixes #2235

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

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

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

index dbe6541dbf6279968589a8c6dd794bc8985b2f0a..f1590b3bb63a36fe68b7c5dacb1c0e626a1135bc 100644 (file)
@@ -506,7 +506,18 @@ func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Valu
                s.errorf("invalid value; expected %s", typ)
        }
        if !value.Type().AssignableTo(typ) {
-               s.errorf("wrong type for value; expected %s; got %s", typ, value.Type())
+               // Does one dereference or indirection work? We could do more, as we
+               // do with method receivers, but that gets messy and method receivers
+               // are much more constrained, so it makes more sense there than here.
+               // Besides, one is almost always all you need.
+               switch {
+               case value.Kind() == reflect.Ptr && value.Elem().Type().AssignableTo(typ):
+                       value = value.Elem()
+               case reflect.PtrTo(value.Type()).AssignableTo(typ) && value.CanAddr():
+                       value = value.Addr()
+               default:
+                       s.errorf("wrong type for value; expected %s; got %s", typ, value.Type())
+               }
        }
        return value
 }
index 7e07e8c2dbcfa1b839d0d8efaef9be6737975af3..8e1894ea03be5c02da4bde35bdc2718f74f7357d 100644 (file)
@@ -416,6 +416,11 @@ var execTests = []execTest{
        {"bug4", "{{if .Empty0}}non-nil{{else}}nil{{end}}", "nil", tVal, true},
        // Stringer.
        {"bug5", "{{.Str}}", "foozle", tVal, true},
+       // Args need to be indirected and dereferenced sometimes.
+       {"bug6a", "{{vfunc .V0 .V1}}", "vfunc", tVal, true},
+       {"bug6b", "{{vfunc .V0 .V0}}", "vfunc", tVal, true},
+       {"bug6c", "{{vfunc .V1 .V0}}", "vfunc", tVal, true},
+       {"bug6d", "{{vfunc .V1 .V1}}", "vfunc", tVal, true},
 }
 
 func zeroArgs() string {
@@ -441,12 +446,18 @@ func count(n int) chan string {
        return c
 }
 
+// vfunc takes a *V and a V
+func vfunc(V, *V) string {
+       return "vfunc"
+}
+
 func testExecute(execTests []execTest, set *Set, t *testing.T) {
        b := new(bytes.Buffer)
        funcs := FuncMap{
                "count":    count,
                "oneArg":   oneArg,
                "typeOf":   typeOf,
+               "vfunc":    vfunc,
                "zeroArgs": zeroArgs,
        }
        for _, test := range execTests {