diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cmd/compile/internal/reflectdata/reflect.go | 30 |
1 files changed, 21 insertions, 9 deletions
diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 142b289dae..b1e2902385 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -846,14 +846,19 @@ func TypePtr(t *types.Type) *ir.AddrExpr { return typecheck.Expr(typecheck.NodAddr(n)).(*ir.AddrExpr) } -// ITabLsym returns the LSym representing the itab for concreate type typ -// implementing interface iface. +// ITabLsym returns the LSym representing the itab for concrete type typ implementing +// interface iface. A dummy tab will be created in the unusual case where typ doesn't +// implement iface. Normally, this wouldn't happen, because the typechecker would +// have reported a compile-time error. This situation can only happen when the +// destination type of a type assert or a type in a type switch is parameterized, so +// it may sometimes, but not always, be a type that can't implement the specified +// interface. func ITabLsym(typ, iface *types.Type) *obj.LSym { s, existed := ir.Pkgs.Itab.LookupOK(typ.LinkString() + "," + iface.LinkString()) lsym := s.Linksym() if !existed { - writeITab(lsym, typ, iface) + writeITab(lsym, typ, iface, true) } return lsym } @@ -865,7 +870,7 @@ func ITabAddr(typ, iface *types.Type) *ir.AddrExpr { lsym := s.Linksym() if !existed { - writeITab(lsym, typ, iface) + writeITab(lsym, typ, iface, false) } n := ir.NewLinksymExpr(base.Pos, lsym, types.Types[types.TUINT8]) @@ -1277,9 +1282,10 @@ func WriteRuntimeTypes() { } } -// writeITab writes the itab for concrete type typ implementing -// interface iface. -func writeITab(lsym *obj.LSym, typ, iface *types.Type) { +// writeITab writes the itab for concrete type typ implementing interface iface. If +// allowNonImplement is true, allow the case where typ does not implement iface, and just +// create a dummy itab with zeroed-out method entries. +func writeITab(lsym *obj.LSym, typ, iface *types.Type, allowNonImplement bool) { // TODO(mdempsky): Fix methodWrapper, geneq, and genhash (and maybe // others) to stop clobbering these. oldpos, oldfn := base.Pos, ir.CurFunc @@ -1306,7 +1312,8 @@ func writeITab(lsym *obj.LSym, typ, iface *types.Type) { } } } - if len(sigs) != 0 { + completeItab := len(sigs) == 0 + if !allowNonImplement && !completeItab { base.Fatalf("incomplete itab") } @@ -1323,7 +1330,12 @@ func writeITab(lsym *obj.LSym, typ, iface *types.Type) { o = objw.Uint32(lsym, o, types.TypeHash(typ)) // copy of type hash o += 4 // skip unused field for _, fn := range entries { - o = objw.SymPtrWeak(lsym, o, fn, 0) // method pointer for each method + if !completeItab { + // If typ doesn't implement iface, make method entries be zero. + o = objw.Uintptr(lsym, o, 0) + } else { + o = objw.SymPtrWeak(lsym, o, fn, 0) // method pointer for each method + } } // Nothing writes static itabs, so they are read only. objw.Global(lsym, int32(o), int16(obj.DUPOK|obj.RODATA)) |
