Commit 39fa2a5b authored by Rob Pike's avatar Rob Pike

exp/template: truth for interface values.

Also protect against invalid (zero Value) reflect.Values.

R=rsc, gri
CC=golang-dev
https://golang.org/cl/4810094
parent 8f3c7497
...@@ -148,7 +148,7 @@ func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse. ...@@ -148,7 +148,7 @@ func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.
val := s.evalPipeline(dot, pipe) val := s.evalPipeline(dot, pipe)
truth, ok := isTrue(val) truth, ok := isTrue(val)
if !ok { if !ok {
s.errorf("if/with can't use value of type %T", val.Interface()) s.errorf("if/with can't use %v", val)
} }
if truth { if truth {
if typ == parse.NodeWith { if typ == parse.NodeWith {
...@@ -164,6 +164,10 @@ func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse. ...@@ -164,6 +164,10 @@ func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.
// isTrue returns whether the value is 'true', in the sense of not the zero of its type, // isTrue returns whether the value is 'true', in the sense of not the zero of its type,
// and whether the value has a meaningful truth value. // and whether the value has a meaningful truth value.
func isTrue(val reflect.Value) (truth, ok bool) { func isTrue(val reflect.Value) (truth, ok bool) {
if !val.IsValid() {
// Something like var x interface{}, never set. It's a form of nil.
return false, true
}
switch val.Kind() { switch val.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String: case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
truth = val.Len() > 0 truth = val.Len() > 0
...@@ -171,7 +175,7 @@ func isTrue(val reflect.Value) (truth, ok bool) { ...@@ -171,7 +175,7 @@ func isTrue(val reflect.Value) (truth, ok bool) {
truth = val.Bool() truth = val.Bool()
case reflect.Complex64, reflect.Complex128: case reflect.Complex64, reflect.Complex128:
truth = val.Complex() != 0 truth = val.Complex() != 0
case reflect.Chan, reflect.Func, reflect.Ptr: case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Interface:
truth = !val.IsNil() truth = !val.IsNil()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
truth = val.Int() != 0 truth = val.Int() != 0
......
...@@ -366,7 +366,9 @@ var execTests = []execTest{ ...@@ -366,7 +366,9 @@ var execTests = []execTest{
// Was taking address of interface field, so method set was empty. // Was taking address of interface field, so method set was empty.
{"bug2", "{{$.NonEmptyInterface.Method0}}", "M0", tVal, true}, {"bug2", "{{$.NonEmptyInterface.Method0}}", "M0", tVal, true},
// Struct values were not legal in with - mere oversight. // Struct values were not legal in with - mere oversight.
{"bug4", "{{with $}}{{.Method0}}{{end}}", "M0", tVal, true}, {"bug3", "{{with $}}{{.Method0}}{{end}}", "M0", tVal, true},
// Nil interface values in if.
{"bug4", "{{if .Empty0}}non-nil{{else}}nil{{end}}", "nil", tVal, true},
} }
func zeroArgs() string { func zeroArgs() string {
......
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