Skip to content

Commit 63825e7

Browse files
authored
interp: fix use of interfaces in composite types
The representation of non empty interfaces defined in the interpreter is now identical between refType() and frameType() functions, which are used to generate interpreter objects. Fixes #1447 and #1426.
1 parent 03ccda1 commit 63825e7

File tree

6 files changed

+58
-38
lines changed

6 files changed

+58
-38
lines changed

_test/assert2.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import (
55
"sync"
66
)
77

8-
// Defined an interface of stringBuilder that compatible with
9-
// strings.Builder(go 1.10) and bytes.Buffer(< go 1.10)
8+
// Define an interface of stringBuilder that is compatible with
9+
// strings.Builder(go 1.10) and bytes.Buffer(< go 1.10).
1010
type stringBuilder interface {
1111
WriteRune(r rune) (n int, err error)
1212
WriteString(s string) (int, error)

_test/issue-1447.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package main
2+
3+
import "fmt"
4+
5+
type I interface {
6+
Name() string
7+
}
8+
9+
type S struct {
10+
iMap map[string]I
11+
}
12+
13+
func main() {
14+
s := S{}
15+
s.iMap = map[string]I{}
16+
fmt.Println(s)
17+
}
18+
19+
// Output:
20+
// {map[]}

interp/run.go

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ func convert(n *node) {
553553
if c.isNil() { // convert nil to type
554554
// TODO(mpl): Try to completely remove, as maybe frameType already does the job for interfaces.
555555
if isInterfaceSrc(n.child[0].typ) && !isEmptyInterface(n.child[0].typ) {
556-
typ = reflect.TypeOf((*valueInterface)(nil)).Elem()
556+
typ = valueInterfaceType
557557
}
558558
n.exec = func(f *frame) bltn {
559559
dest(f).Set(reflect.New(typ).Elem())
@@ -713,7 +713,7 @@ func assign(n *node) {
713713
case isFuncSrc(typ):
714714
t = reflect.TypeOf((*node)(nil))
715715
case isInterfaceSrc(typ):
716-
t = reflect.TypeOf((*valueInterface)(nil)).Elem()
716+
t = valueInterfaceType
717717
default:
718718
t = typ.TypeOf()
719719
}
@@ -1007,7 +1007,7 @@ func genFunctionWrapper(n *node) func(*frame) reflect.Value {
10071007
}
10081008
typ := def.typ.arg[i]
10091009
switch {
1010-
case isEmptyInterface(typ):
1010+
case isEmptyInterface(typ) || typ.TypeOf() == valueInterfaceType:
10111011
d[i].Set(arg)
10121012
case isInterfaceSrc(typ):
10131013
d[i].Set(reflect.ValueOf(valueInterface{value: arg.Elem()}))
@@ -1560,12 +1560,9 @@ func callBin(n *node) {
15601560
case isInterfaceSrc(c.typ):
15611561
values = append(values, genValueInterfaceValue(c))
15621562
case c.typ.cat == arrayT || c.typ.cat == variadicT:
1563-
switch {
1564-
case isEmptyInterface(c.typ.val):
1563+
if isEmptyInterface(c.typ.val) {
15651564
values = append(values, genValueArray(c))
1566-
case isInterfaceSrc(c.typ.val):
1567-
values = append(values, genValueInterfaceArray(c))
1568-
default:
1565+
} else {
15691566
values = append(values, genInterfaceWrapper(c, defType))
15701567
}
15711568
case isPtrSrc(c.typ):
@@ -2703,8 +2700,6 @@ func doComposite(n *node, hasType bool, keyed bool) {
27032700
values[fieldIndex] = func(*frame) reflect.Value { return reflect.New(rft).Elem() }
27042701
case isFuncSrc(val.typ):
27052702
values[fieldIndex] = genValueAsFunctionWrapper(val)
2706-
case isArray(val.typ) && val.typ.val != nil && isInterfaceSrc(val.typ.val) && !isEmptyInterface(val.typ.val):
2707-
values[fieldIndex] = genValueInterfaceArray(val)
27082703
case isInterfaceSrc(ft) && (!isEmptyInterface(ft) || len(val.typ.method) > 0):
27092704
values[fieldIndex] = genValueInterface(val)
27102705
case isInterface(ft):
@@ -3585,7 +3580,7 @@ func convertLiteralValue(n *node, t reflect.Type) {
35853580
case n.typ.cat == nilT:
35863581
// Create a zero value of target type.
35873582
n.rval = reflect.New(t).Elem()
3588-
case !(n.kind == basicLit || n.rval.IsValid()) || t == nil || t.Kind() == reflect.Interface || t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Interface:
3583+
case !(n.kind == basicLit || n.rval.IsValid()) || t == nil || t.Kind() == reflect.Interface || t == valueInterfaceType || t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Interface:
35893584
// Skip non-constant values, undefined target type or interface target type.
35903585
case n.rval.IsValid():
35913586
// Convert constant value to target type.
@@ -3946,7 +3941,7 @@ func isNotNil(n *node) {
39463941
dest := genValue(n)
39473942

39483943
if n.fnext == nil {
3949-
if isInterfaceSrc(c0.typ) {
3944+
if isInterfaceSrc(c0.typ) && c0.typ.TypeOf() != valueInterfaceType {
39503945
if isInterface {
39513946
n.exec = func(f *frame) bltn {
39523947
dest(f).Set(reflect.ValueOf(!value(f).IsNil()).Convert(typ))
@@ -3991,7 +3986,7 @@ func isNotNil(n *node) {
39913986

39923987
fnext := getExec(n.fnext)
39933988

3994-
if isInterfaceSrc(c0.typ) {
3989+
if isInterfaceSrc(c0.typ) && c0.typ.TypeOf() != valueInterfaceType {
39953990
n.exec = func(f *frame) bltn {
39963991
if value(f).IsNil() {
39973992
dest(f).SetBool(false)

interp/type.go

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1817,8 +1817,9 @@ func exportName(s string) string {
18171817

18181818
var (
18191819
// TODO(mpl): generators.
1820-
interf = reflect.TypeOf((*interface{})(nil)).Elem()
1821-
constVal = reflect.TypeOf((*constant.Value)(nil)).Elem()
1820+
emptyInterfaceType = reflect.TypeOf((*interface{})(nil)).Elem()
1821+
valueInterfaceType = reflect.TypeOf((*valueInterface)(nil)).Elem()
1822+
constVal = reflect.TypeOf((*constant.Value)(nil)).Elem()
18221823
)
18231824

18241825
type fieldRebuild struct {
@@ -1971,7 +1972,12 @@ func (t *itype) refType(ctx *refTypeContext) reflect.Type {
19711972
}
19721973
t.rtype = reflect.FuncOf(in, out, variadic)
19731974
case interfaceT:
1974-
t.rtype = interf
1975+
if len(t.field) == 0 {
1976+
// empty interface, do not wrap it
1977+
t.rtype = emptyInterfaceType
1978+
break
1979+
}
1980+
t.rtype = valueInterfaceType
19751981
case mapT:
19761982
t.rtype = reflect.MapOf(t.key.refType(ctx), t.val.refType(ctx))
19771983
case ptrT:
@@ -2056,10 +2062,10 @@ func (t *itype) frameType() (r reflect.Type) {
20562062
case interfaceT:
20572063
if len(t.field) == 0 {
20582064
// empty interface, do not wrap it
2059-
r = reflect.TypeOf((*interface{})(nil)).Elem()
2065+
r = emptyInterfaceType
20602066
break
20612067
}
2062-
r = reflect.TypeOf((*valueInterface)(nil)).Elem()
2068+
r = valueInterfaceType
20632069
case mapT:
20642070
r = reflect.MapOf(t.key.frameType(), t.val.frameType())
20652071
case ptrT:
@@ -2072,6 +2078,14 @@ func (t *itype) frameType() (r reflect.Type) {
20722078

20732079
func (t *itype) implements(it *itype) bool {
20742080
if isBin(t) {
2081+
// Note: in case of a valueInterfaceType, we
2082+
// miss required data which will be available
2083+
// later, so we optimistically return true to progress,
2084+
// and additional checks will be hopefully performed at
2085+
// runtime.
2086+
if rt := it.TypeOf(); rt == valueInterfaceType {
2087+
return true
2088+
}
20752089
return t.TypeOf().Implements(it.TypeOf())
20762090
}
20772091
return t.methods().contains(it.methods())
@@ -2127,11 +2141,15 @@ func (t *itype) defaultType(v reflect.Value, sc *scope) *itype {
21272141
func (t *itype) isNil() bool { return t.cat == nilT }
21282142

21292143
func (t *itype) hasNil() bool {
2130-
switch t.TypeOf().Kind() {
2144+
switch rt := t.TypeOf(); rt.Kind() {
21312145
case reflect.UnsafePointer:
21322146
return true
21332147
case reflect.Slice, reflect.Ptr, reflect.Func, reflect.Interface, reflect.Map, reflect.Chan:
21342148
return true
2149+
case reflect.Struct:
2150+
if rt == valueInterfaceType {
2151+
return true
2152+
}
21352153
}
21362154
return false
21372155
}
@@ -2246,7 +2264,7 @@ func isInterfaceBin(t *itype) bool {
22462264
}
22472265

22482266
func isInterface(t *itype) bool {
2249-
return isInterfaceSrc(t) || t.TypeOf() != nil && t.TypeOf().Kind() == reflect.Interface
2267+
return isInterfaceSrc(t) || t.TypeOf() == valueInterfaceType || t.TypeOf() != nil && t.TypeOf().Kind() == reflect.Interface
22502268
}
22512269

22522270
func isBin(t *itype) bool {

interp/typecheck.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ func (check typecheck) typeAssertionExpr(n *node, typ *itype) error {
590590
// https://github.com/golang/go/issues/39717 lands. It is currently impractical to
591591
// type check Named types as they cannot be asserted.
592592

593-
if n.typ.TypeOf().Kind() != reflect.Interface {
593+
if rt := n.typ.TypeOf(); rt.Kind() != reflect.Interface && rt != valueInterfaceType {
594594
return n.cfgErrorf("invalid type assertion: non-interface type %s on left", n.typ.id())
595595
}
596596
ims := n.typ.methods()

interp/value.go

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ func genValue(n *node) func(*frame) reflect.Value {
176176
convertConstantValue(n)
177177
v := n.rval
178178
if !v.IsValid() {
179-
v = reflect.New(interf).Elem()
179+
v = reflect.New(emptyInterfaceType).Elem()
180180
}
181181
return func(f *frame) reflect.Value { return v }
182182
case funcDecl:
@@ -287,19 +287,6 @@ func genValueRangeArray(n *node) func(*frame) reflect.Value {
287287
}
288288
}
289289

290-
func genValueInterfaceArray(n *node) func(*frame) reflect.Value {
291-
value := genValue(n)
292-
return func(f *frame) reflect.Value {
293-
vi := value(f).Interface().([]valueInterface)
294-
v := reflect.MakeSlice(reflect.TypeOf([]interface{}{}), len(vi), len(vi))
295-
for i, vv := range vi {
296-
v.Index(i).Set(vv.value)
297-
}
298-
299-
return v
300-
}
301-
}
302-
303290
func genValueInterface(n *node) func(*frame) reflect.Value {
304291
value := genValue(n)
305292

@@ -356,7 +343,7 @@ func getConcreteValue(val reflect.Value) reflect.Value {
356343

357344
func zeroInterfaceValue() reflect.Value {
358345
n := &node{kind: basicLit, typ: &itype{cat: nilT, untyped: true, str: "nil"}}
359-
v := reflect.New(interf).Elem()
346+
v := reflect.New(emptyInterfaceType).Elem()
360347
return reflect.ValueOf(valueInterface{n, v})
361348
}
362349

0 commit comments

Comments
 (0)