mirror of
https://github.com/golang/go
synced 2024-11-21 16:04:45 -07:00
exp/template: do not take address of interface variable to find methods.
Also allow struct values as "with" targets. R=golang-dev, dsymonds CC=golang-dev https://golang.org/cl/4809086
This commit is contained in:
parent
7506ee7584
commit
1adda4601a
@ -179,6 +179,8 @@ func isTrue(val reflect.Value) (truth, ok bool) {
|
||||
truth = val.Float() != 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
truth = val.Uint() != 0
|
||||
case reflect.Struct:
|
||||
truth = true // Struct values are always true.
|
||||
default:
|
||||
return
|
||||
}
|
||||
@ -377,10 +379,10 @@ func (s *state) evalField(dot reflect.Value, fieldName string, args []parse.Node
|
||||
}
|
||||
typ := receiver.Type()
|
||||
receiver, _ = indirect(receiver)
|
||||
// Need to get to a value of type *T to guarantee we see all
|
||||
// methods of T and *T.
|
||||
// Unless it's an interface, need to get to a value of type *T to guarantee
|
||||
// we see all methods of T and *T.
|
||||
ptr := receiver
|
||||
if ptr.CanAddr() {
|
||||
if ptr.Kind() != reflect.Interface && ptr.CanAddr() {
|
||||
ptr = ptr.Addr()
|
||||
}
|
||||
if method, ok := methodByName(ptr, fieldName); ok {
|
||||
|
@ -43,6 +43,8 @@ type T struct {
|
||||
Empty2 interface{}
|
||||
Empty3 interface{}
|
||||
Empty4 interface{}
|
||||
// Non-empty interface.
|
||||
NonEmptyInterface I
|
||||
// Pointers
|
||||
PI *int
|
||||
PSI *[]int
|
||||
@ -69,13 +71,14 @@ var tVal = &T{
|
||||
{"one": 1, "two": 2},
|
||||
{"eleven": 11, "twelve": 12},
|
||||
},
|
||||
Empty1: 3,
|
||||
Empty2: "empty2",
|
||||
Empty3: []int{7, 8},
|
||||
Empty4: &U{"UinEmpty"},
|
||||
PI: newInt(23),
|
||||
PSI: newIntSlice(21, 22, 23),
|
||||
Tmpl: Must(New("x").Parse("test template")), // "x" is the value of .X
|
||||
Empty1: 3,
|
||||
Empty2: "empty2",
|
||||
Empty3: []int{7, 8},
|
||||
Empty4: &U{"UinEmpty"},
|
||||
NonEmptyInterface: new(T),
|
||||
PI: newInt(23),
|
||||
PSI: newIntSlice(21, 22, 23),
|
||||
Tmpl: Must(New("x").Parse("test template")), // "x" is the value of .X
|
||||
}
|
||||
|
||||
// A non-empty interface.
|
||||
@ -358,8 +361,12 @@ var execTests = []execTest{
|
||||
// Must separate dot and receiver; otherwise args are evaluated with dot set to variable.
|
||||
{"bug0", "{{range .MSIone}}{{if $.Method1 .}}X{{end}}{{end}}", "X", tVal, true},
|
||||
// Do not loop endlessly in indirect for non-empty interfaces.
|
||||
// The bug appears with *interface only; this is supposed to fail (cannot invoke Method0), but terminate.
|
||||
{"bug1", "{{.Method0}}", "", &iVal, false},
|
||||
// The bug appears with *interface only; looped forever.
|
||||
{"bug1", "{{.Method0}}", "M0", &iVal, true},
|
||||
// Was taking address of interface field, so method set was empty.
|
||||
{"bug2", "{{$.NonEmptyInterface.Method0}}", "M0", tVal, true},
|
||||
// Struct values were not legal in with - mere oversight.
|
||||
{"bug4", "{{with $}}{{.Method0}}{{end}}", "M0", tVal, true},
|
||||
}
|
||||
|
||||
func zeroArgs() string {
|
||||
|
Loading…
Reference in New Issue
Block a user