Commit 83348a13 authored by Elias Naur's avatar Elias Naur Committed by Rob Pike

text/template: Make function call builtin handle nil errors correctly

The call builtin unconditionally tries to convert a second return value from a function to the error type. This fails in case nil is returned, effectively making call useless for functions returning two values.

This CL adds a nil check for the second return value, and adds a test.

Note that for regular function and method calls the nil error case is handled correctly and is verified by a test.

R=r
CC=golang-dev
https://golang.org/cl/12804043
parent 9a0a59f1
...@@ -64,6 +64,7 @@ type T struct { ...@@ -64,6 +64,7 @@ type T struct {
VariadicFunc func(...string) string VariadicFunc func(...string) string
VariadicFuncInt func(int, ...string) string VariadicFuncInt func(int, ...string) string
NilOKFunc func(*int) bool NilOKFunc func(*int) bool
ErrFunc func() (string, error)
// Template to test evaluation of templates. // Template to test evaluation of templates.
Tmpl *Template Tmpl *Template
// Unexported field; cannot be accessed by template. // Unexported field; cannot be accessed by template.
...@@ -129,6 +130,7 @@ var tVal = &T{ ...@@ -129,6 +130,7 @@ var tVal = &T{
VariadicFunc: func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") }, VariadicFunc: func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") },
VariadicFuncInt: func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") }, VariadicFuncInt: func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") },
NilOKFunc: func(s *int) bool { return s == nil }, NilOKFunc: func(s *int) bool { return s == nil },
ErrFunc: func() (string, error) { return "bla", nil },
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
} }
...@@ -322,6 +324,7 @@ var execTests = []execTest{ ...@@ -322,6 +324,7 @@ var execTests = []execTest{
{"if .BinaryFunc call", "{{ if .BinaryFunc}}{{call .BinaryFunc `1` `2`}}{{end}}", "[1=2]", tVal, true}, {"if .BinaryFunc call", "{{ if .BinaryFunc}}{{call .BinaryFunc `1` `2`}}{{end}}", "[1=2]", tVal, true},
{"if not .BinaryFunc call", "{{ if not .BinaryFunc}}{{call .BinaryFunc `1` `2`}}{{else}}No{{end}}", "No", tVal, true}, {"if not .BinaryFunc call", "{{ if not .BinaryFunc}}{{call .BinaryFunc `1` `2`}}{{else}}No{{end}}", "No", tVal, true},
{"Interface Call", `{{stringer .S}}`, "foozle", map[string]interface{}{"S": bytes.NewBufferString("foozle")}, true}, {"Interface Call", `{{stringer .S}}`, "foozle", map[string]interface{}{"S": bytes.NewBufferString("foozle")}, true},
{".ErrFunc", "{{call .ErrFunc}}", "bla", tVal, true},
// Erroneous function calls (check args). // Erroneous function calls (check args).
{".BinaryFuncTooFew", "{{call .BinaryFunc `1`}}", "", tVal, false}, {".BinaryFuncTooFew", "{{call .BinaryFunc `1`}}", "", tVal, false},
......
...@@ -199,7 +199,7 @@ func call(fn interface{}, args ...interface{}) (interface{}, error) { ...@@ -199,7 +199,7 @@ func call(fn interface{}, args ...interface{}) (interface{}, error) {
argv[i] = value argv[i] = value
} }
result := v.Call(argv) result := v.Call(argv)
if len(result) == 2 { if len(result) == 2 && !result[1].IsNil() {
return result[0].Interface(), result[1].Interface().(error) return result[0].Interface(), result[1].Interface().(error)
} }
return result[0].Interface(), nil return result[0].Interface(), nil
......
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