Commit d45e808c authored by Rob Pike's avatar Rob Pike

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
parent 0783dd90
...@@ -506,8 +506,19 @@ func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Valu ...@@ -506,8 +506,19 @@ func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Valu
s.errorf("invalid value; expected %s", typ) s.errorf("invalid value; expected %s", typ)
} }
if !value.Type().AssignableTo(typ) { if !value.Type().AssignableTo(typ) {
// 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()) s.errorf("wrong type for value; expected %s; got %s", typ, value.Type())
} }
}
return value return value
} }
......
...@@ -416,6 +416,11 @@ var execTests = []execTest{ ...@@ -416,6 +416,11 @@ var execTests = []execTest{
{"bug4", "{{if .Empty0}}non-nil{{else}}nil{{end}}", "nil", tVal, true}, {"bug4", "{{if .Empty0}}non-nil{{else}}nil{{end}}", "nil", tVal, true},
// Stringer. // Stringer.
{"bug5", "{{.Str}}", "foozle", tVal, true}, {"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 { func zeroArgs() string {
...@@ -441,12 +446,18 @@ func count(n int) chan string { ...@@ -441,12 +446,18 @@ func count(n int) chan string {
return c 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) { func testExecute(execTests []execTest, set *Set, t *testing.T) {
b := new(bytes.Buffer) b := new(bytes.Buffer)
funcs := FuncMap{ funcs := FuncMap{
"count": count, "count": count,
"oneArg": oneArg, "oneArg": oneArg,
"typeOf": typeOf, "typeOf": typeOf,
"vfunc": vfunc,
"zeroArgs": zeroArgs, "zeroArgs": zeroArgs,
} }
for _, test := range execTests { for _, test := range execTests {
......
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