Skip to content

Commit

Permalink
interp: improve handling of wrapped interface values
Browse files Browse the repository at this point in the history
This test (assert2.go) display 2 separate issues:
1. assert2.go L28: Type assert tries to set an `interface{}` to a `valueInterface`. The typing here is complex, we have a valueT(strings.Builder) wrapped in a ptrT wrapped in a src iface wrapped in a valueT(interface{}). Type assert fails to realise that the `valueT` `interface{}` is wrapping the `valueInterface`.
2. assert2.go L29: `genValueBinMethodOnInterface` does not try and get the bin method, as the `typ.node` (`ptrT` or a `valueT`(`string.Builder`)) is set. In this case the src iface is called with a receiver argument. To fix this the method is looked for first if possible, and only if not found does it fall back to the `defaultGen`.

Fixes #1227
  • Loading branch information
nrwiersma authored Sep 6, 2021
1 parent 91a55cc commit c33caeb
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 4 deletions.
37 changes: 37 additions & 0 deletions _test/assert2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package main

import (
"strings"
"sync"
)

// Defined an interface of stringBuilder that compatible with
// strings.Builder(go 1.10) and bytes.Buffer(< go 1.10)
type stringBuilder interface {
WriteRune(r rune) (n int, err error)
WriteString(s string) (int, error)
Reset()
Grow(n int)
String() string
}

var builderPool = sync.Pool{New: func() interface{} {
return newStringBuilder()
}}

func newStringBuilder() stringBuilder {
return &strings.Builder{}
}

func main() {
i := builderPool.Get()
sb := i.(stringBuilder)
_, _ = sb.WriteString("hello")

println(sb.String())

builderPool.Put(i)
}

// Output:
// hello
3 changes: 3 additions & 0 deletions interp/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,9 @@ func typeAssert(n *node, withResult, withOk bool) {
}
return next
}
if c0.typ.cat == valueT {
valf = reflect.ValueOf(v)
}
if v.node.typ.id() == typID {
if withResult {
value0(f).Set(valf)
Expand Down
10 changes: 6 additions & 4 deletions interp/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,17 @@ func genValueBinMethodOnInterface(n *node, defaultGen func(*frame) reflect.Value
nod = vi.node
}

if nod == nil {
if nod == nil || nod.typ.rtype == nil {
return defaultGen(f)
}

typ := nod.typ
if typ.node != nil || typ.cat != valueT {
// Try to get the bin method, if it doesnt exist, fall back to
// the default generator function.
meth, ok := nod.typ.rtype.MethodByName(c0.child[1].ident)
if !ok {
return defaultGen(f)
}
meth, _ := typ.rtype.MethodByName(c0.child[1].ident)

return meth.Func
}
}
Expand Down

0 comments on commit c33caeb

Please sign in to comment.