Commit 6ca968c7 authored by Rob Pike's avatar Rob Pike

exp/template: find the String method by taking the address if we need to.

Also simplify nil handling in printing.

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/4869042
parent f3625e70
...@@ -425,7 +425,8 @@ func methodByName(receiver reflect.Value, name string) (reflect.Value, bool) { ...@@ -425,7 +425,8 @@ func methodByName(receiver reflect.Value, name string) (reflect.Value, bool) {
} }
var ( var (
osErrorType = reflect.TypeOf(new(os.Error)).Elem() osErrorType = reflect.TypeOf((*os.Error)(nil)).Elem()
fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
) )
// evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so // evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so
...@@ -625,13 +626,13 @@ func (s *state) printValue(n parse.Node, v reflect.Value) { ...@@ -625,13 +626,13 @@ func (s *state) printValue(n parse.Node, v reflect.Value) {
} }
switch v.Kind() { switch v.Kind() {
case reflect.Ptr: case reflect.Ptr:
var isNil bool v, _ = indirect(v) // fmt.Fprint handles nil.
if v, isNil = indirect(v); isNil {
fmt.Fprint(s.wr, "<nil>")
return
}
case reflect.Chan, reflect.Func, reflect.Interface: case reflect.Chan, reflect.Func, reflect.Interface:
s.errorf("can't print %s of type %s", n, v.Type()) s.errorf("can't print %s of type %s", n, v.Type())
} }
// If it's a value but the pointer implements Stringer, use the pointer.
if v.Kind() != reflect.Ptr && v.CanAddr() && reflect.PtrTo(v.Type()).Implements(fmtStringerType) {
v = v.Addr()
}
fmt.Fprint(s.wr, v.Interface()) fmt.Fprint(s.wr, v.Interface())
} }
...@@ -28,6 +28,9 @@ type T struct { ...@@ -28,6 +28,9 @@ type T struct {
ComplexZero float64 ComplexZero float64
// Nested structs. // Nested structs.
U *U U *U
// Struct with String method.
V0 V
V1, V2 *V
// Slices // Slices
SI []int SI []int
SIEmpty []int SIEmpty []int
...@@ -57,12 +60,25 @@ type U struct { ...@@ -57,12 +60,25 @@ type U struct {
V string V string
} }
type V struct {
j int
}
func (v *V) String() string {
if v == nil {
return "nilV"
}
return fmt.Sprintf("<%d>", v.j)
}
var tVal = &T{ var tVal = &T{
True: true, True: true,
I: 17, I: 17,
U16: 16, U16: 16,
X: "x", X: "x",
U: &U{"v"}, U: &U{"v"},
V0: V{6666},
V1: &V{7777}, // leave V2 as nil
SI: []int{3, 4, 5}, SI: []int{3, 4, 5},
SB: []bool{true, false}, SB: []bool{true, false},
MSI: map[string]int{"one": 1, "two": 2, "three": 3}, MSI: map[string]int{"one": 1, "two": 2, "three": 3},
...@@ -212,6 +228,11 @@ var execTests = []execTest{ ...@@ -212,6 +228,11 @@ var execTests = []execTest{
{"$.U.V", "{{$.U.V}}", "v", tVal, true}, {"$.U.V", "{{$.U.V}}", "v", tVal, true},
{"declare in action", "{{$x := $.U.V}}{{$x}}", "v", tVal, true}, {"declare in action", "{{$x := $.U.V}}{{$x}}", "v", tVal, true},
// Type with String method.
{"V{6666}.String()", "-{{.V0}}-", "-<6666>-", tVal, true},
{"&V{7777}.String()", "-{{.V1}}-", "-<7777>-", tVal, true},
{"(*V)(nil).String()", "-{{.V2}}-", "-nilV-", tVal, true},
// Pointers. // Pointers.
{"*int", "{{.PI}}", "23", tVal, true}, {"*int", "{{.PI}}", "23", tVal, true},
{"*[]int", "{{.PSI}}", "[21 22 23]", tVal, true}, {"*[]int", "{{.PSI}}", "[21 22 23]", tVal, true},
......
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