func (caller *Function) invoke(common *ssa.CallCommon, infer *TypeInfer, b *Block, l *Loop) *Function { iface, ok := common.Value.Type().Underlying().(*types.Interface) if !ok { infer.Logger.Fatalf("invoke: %s is not an interface", common.String()) return nil } ifaceInst, ok := caller.locals[common.Value] // SSA value initialised if !ok { infer.Logger.Fatalf("invoke: %s: %s", common.Value.Name(), ErrUnknownValue) return nil } switch inst := ifaceInst.(type) { case *Value: // OK case *Const: if inst.Const.IsNil() { return nil } infer.Logger.Fatalf("invoke: %+v is not nil nor concrete", ifaceInst) case *External: infer.Logger.Printf(caller.Sprintf("invoke: %+v external", ifaceInst)) return nil default: infer.Logger.Printf(caller.Sprintf("invoke: %+v unknown", ifaceInst)) return nil } meth, _ := types.MissingMethod(ifaceInst.(*Value).Type(), iface, true) // static if meth != nil { meth, _ = types.MissingMethod(ifaceInst.(*Value).Type(), iface, false) // non-static if meth != nil { infer.Logger.Printf("invoke: missing method %s: %s", meth.String(), ErrIfaceIncomplete) return nil } } fn := findMethod(common.Value.Parent().Prog, common.Method, ifaceInst.(*Value).Type(), infer) if fn == nil { if meth == nil { infer.Logger.Printf("invoke: cannot locate concrete method") } else { infer.Logger.Printf("invoke: cannot locate concrete method: %s", meth.String()) } return nil } return caller.call(common, fn, common.Value, infer, b, l) }