diff options
Diffstat (limited to 'src/cmd/compile/internal/noder')
| -rw-r--r-- | src/cmd/compile/internal/noder/expr.go | 30 | ||||
| -rw-r--r-- | src/cmd/compile/internal/noder/stencil.go | 81 |
2 files changed, 85 insertions, 26 deletions
diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index d974b291d0..16470a5449 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -207,29 +207,43 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto n := ir.NewSelectorExpr(pos, ir.OXDOT, x, typecheck.Lookup(expr.Sel.Value)) typed(g.typ(typ), n) - // Fill in n.Selection for a generic method reference, even though we - // won't use it directly, since it is useful for analysis. - // Specifically do not fill in for fields or interfaces methods, so - // n.Selection being non-nil means a method reference, rather than an - // interface reference or reference to a field with a function value. + // Fill in n.Selection for a generic method reference or a bound + // interface method, even though we won't use it directly, since it + // is useful for analysis. Specifically do not fill in for fields or + // other interfaces methods (method call on an interface value), so + // n.Selection being non-nil means a method reference for a generic + // type or a method reference due to a bound. obj2 := g.info.Selections[expr].Obj() sig := types2.AsSignature(obj2.Type()) if sig == nil || sig.Recv() == nil { return n } - // recvType is the type of the last embedded field. Because of the + index := g.info.Selections[expr].Index() + last := index[len(index)-1] + // recvType is the receiver of the method being called. Because of the // way methods are imported, g.obj(obj2) doesn't work across // packages, so we have to lookup the method via the receiver type. recvType := deref2(sig.Recv().Type()) if types2.AsInterface(recvType.Underlying()) != nil { + fieldType := n.X.Type() + for _, ix := range index[:len(index)-1] { + fieldType = fieldType.Field(ix).Type + } + if fieldType.Kind() == types.TTYPEPARAM { + n.Selection = fieldType.Bound().AllMethods().Index(last) + //fmt.Printf(">>>>> %v: Bound call %v\n", base.FmtPos(pos), n.Sel) + } else { + assert(fieldType.Kind() == types.TINTER) + //fmt.Printf(">>>>> %v: Interface call %v\n", base.FmtPos(pos), n.Sel) + } return n } - index := g.info.Selections[expr].Index() - last := index[len(index)-1] recvObj := types2.AsNamed(recvType).Obj() recv := g.pkg(recvObj.Pkg()).Lookup(recvObj.Name()).Def n.Selection = recv.Type().Methods().Index(last) + //fmt.Printf(">>>>> %v: Method call %v\n", base.FmtPos(pos), n.Sel) + return n } 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 |
