diff options
Diffstat (limited to 'src/cmd/compile/internal/noder/stencil.go')
-rw-r--r-- | src/cmd/compile/internal/noder/stencil.go | 81 |
1 files changed, 63 insertions, 18 deletions
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index d292bfd5c6..1759fbc4cf 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -158,12 +158,9 @@ func (g *irgen) stencil() { st := g.getInstantiation(gf, targs, true) dictValue, usingSubdict := g.getDictOrSubdict(declInfo, n, gf, targs, true) - _ = usingSubdict - // TODO: We should do assert(usingSubdict) here, but - // not creating sub-dictionary entry for - // absDifference in absdiff.go yet. Unusual case, - // where there are different generic method - // implementations of Abs in absDifference. + // We have to be using a subdictionary, since this is + // a generic method call. + assert(usingSubdict) call.SetOp(ir.OCALL) call.X = st.Nname @@ -741,10 +738,9 @@ func gcshapeType(t *types.Type) (*types.Type, string) { return gcshape, buf.String() } -// getInstantiation gets the instantiantion and dictionary of the function or method nameNode -// with the type arguments targs. If the instantiated function is not already -// cached, then it calls genericSubst to create the new instantiation. -func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth bool) *ir.Func { +// checkFetchBody checks if a generic body can be fetched, but hasn't been loaded +// yet. If so, it imports the body. +func checkFetchBody(nameNode *ir.Name) { if nameNode.Func.Body == nil && nameNode.Func.Inl != nil { // If there is no body yet but Func.Inl exists, then we can can // import the whole generic body. @@ -754,6 +750,13 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth nameNode.Func.Body = nameNode.Func.Inl.Body nameNode.Func.Dcl = nameNode.Func.Inl.Dcl } +} + +// getInstantiation gets the instantiantion and dictionary of the function or method nameNode +// with the type arguments targs. If the instantiated function is not already +// cached, then it calls genericSubst to create the new instantiation. +func (g *irgen) getInstantiation(nameNode *ir.Name, targs []*types.Type, isMeth bool) *ir.Func { + checkFetchBody(nameNode) sym := typecheck.MakeInstName(nameNode.Sym(), targs, isMeth) info := g.instInfoMap[sym] if info == nil { @@ -1405,13 +1408,41 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) case ir.OCALL: call := n.(*ir.CallExpr) if call.X.Op() == ir.OXDOT { - subtargs := deref(call.X.(*ir.SelectorExpr).X.Type()).RParams() - s2targs := make([]*types.Type, len(subtargs)) - for i, t := range subtargs { - s2targs[i] = subst.Typ(t) + var nameNode *ir.Name + se := call.X.(*ir.SelectorExpr) + if types.IsInterfaceMethod(se.Selection.Type) { + // This is a method call enabled by a type bound. + tmpse := ir.NewSelectorExpr(base.Pos, ir.OXDOT, se.X, se.Sel) + tmpse = typecheck.AddImplicitDots(tmpse) + tparam := tmpse.X.Type() + assert(tparam.IsTypeParam()) + recvType := targs[tparam.Index()] + if len(recvType.RParams()) == 0 { + // No sub-dictionary entry is + // actually needed, since the + // typeparam is not an + // instantiated type that + // will have generic methods. + break + } + // This is a method call for an + // instantiated type, so we need a + // sub-dictionary. + targs := recvType.RParams() + genRecvType := recvType.OrigSym.Def.Type() + nameNode = typecheck.Lookdot1(call.X, se.Sel, genRecvType, genRecvType.Methods(), 1).Nname.(*ir.Name) + sym = g.getDictionarySym(nameNode, targs, true) + } else { + // This is the case of a normal + // method call on a generic type. + nameNode = call.X.(*ir.SelectorExpr).Selection.Nname.(*ir.Name) + subtargs := deref(call.X.(*ir.SelectorExpr).X.Type()).RParams() + s2targs := make([]*types.Type, len(subtargs)) + for i, t := range subtargs { + s2targs[i] = subst.Typ(t) + } + sym = g.getDictionarySym(nameNode, s2targs, true) } - nameNode := call.X.(*ir.SelectorExpr).Selection.Nname.(*ir.Name) - sym = g.getDictionarySym(nameNode, s2targs, true) } else { inst := call.X.(*ir.InstExpr) var nameNode *ir.Name @@ -1452,8 +1483,14 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool) assert(false) } - off = objw.SymPtr(lsym, off, sym.Linksym(), 0) - infoPrint(" - Subdict %v\n", sym.Name) + if sym == nil { + // Unused sub-dictionary entry, just emit 0. + off = objw.Uintptr(lsym, off, 0) + infoPrint(" - Unused subdict entry\n") + } else { + off = objw.SymPtr(lsym, off, sym.Linksym(), 0) + infoPrint(" - Subdict %v\n", sym.Name) + } } objw.Global(lsym, int32(off), obj.DUPOK|obj.RODATA) infoPrint("=== Done dictionary\n") @@ -1512,6 +1549,7 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { return infop } + checkFetchBody(gn) var info gfInfo gf := gn.Func recv := gf.Type().Recv() @@ -1575,6 +1613,13 @@ func (g *irgen) getGfInfo(gn *ir.Name) *gfInfo { info.subDictCalls = append(info.subDictCalls, n) } } + if n.Op() == ir.OCALL && n.(*ir.CallExpr).X.Op() == ir.OXDOT && + n.(*ir.CallExpr).X.(*ir.SelectorExpr).Selection != nil && + deref(n.(*ir.CallExpr).X.(*ir.SelectorExpr).X.Type()).IsTypeParam() { + n.(*ir.CallExpr).X.(*ir.SelectorExpr).SetImplicit(true) + infoPrint(" Optional subdictionary at generic bound call: %v\n", n) + info.subDictCalls = append(info.subDictCalls, n) + } if n.Op() == ir.OCLOSURE { // Visit the closure body and add all relevant entries to the // dictionary of the outer function (closure will just use |