func visitTypeAssert(inst *ssa.TypeAssert, fr *frame) { if iface, ok := inst.AssertedType.(*types.Interface); ok { if meth, _ := types.MissingMethod(inst.X.Type(), iface, true); meth == nil { // No missing methods switch vd, kind := fr.get(inst.X); kind { case Struct, LocalStruct, Array, LocalArray, Chan: fr.tuples[inst] = make(Tuples, 2) fr.tuples[inst][0] = vd fmt.Fprintf(os.Stderr, " %s = %s.(type assert %s) iface\n", reg(inst), reg(inst.X), inst.AssertedType.String()) fmt.Fprintf(os.Stderr, " ^ defined as %s\n", vd.String()) default: fmt.Fprintf(os.Stderr, " %s = %s.(type assert %s)\n", red(reg(inst)), reg(inst.X), inst.AssertedType.String()) fmt.Fprintf(os.Stderr, " ^ untracked/unknown\n") } return } } else { // Concrete type if types.Identical(inst.AssertedType.Underlying(), inst.X.Type().Underlying()) { switch vd, kind := fr.get(inst.X); kind { case Struct, LocalStruct, Array, LocalArray, Chan: fr.tuples[inst] = make(Tuples, 2) fr.tuples[inst][0] = vd fmt.Fprintf(os.Stderr, " %s = %s.(type assert %s) concrete\n", reg(inst), reg(inst.X), inst.AssertedType.String()) fmt.Fprintf(os.Stderr, " ^ defined as %s\n", vd.String()) default: fmt.Fprintf(os.Stderr, " %s = %s.(type assert %s)\n", red(reg(inst)), reg(inst.X), inst.AssertedType.String()) fmt.Fprintf(os.Stderr, " ^ untracked/unknown\n") } return } } fmt.Fprintf(os.Stderr, " # %s = %s.(%s) impossible type assertion\n", red(reg(inst)), reg(inst.X), inst.AssertedType.String()) }
// checkInterface checks that the method set of x implements the // interface itype. // On success it returns "", on failure, an error message. // func checkInterface(i *interpreter, itype *types.Interface, x iface) string { if meth, _ := types.MissingMethod(x.t, itype, true); meth != nil { return fmt.Sprintf("interface conversion: %v is not %v: missing method %s", x.t, itype, meth.Name()) } return "" // ok }
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) }
func (a *Analyzer) getImplementors(ifc *types.Interface) []types.Type { retval := make([]types.Type, 0) for _, o := range a.objects { log.Printf("\t\tChecking if %s implements %s", o.Type(), ifc) fnc, wrongType := types.MissingMethod(o.Type(), ifc, true) if fnc == nil { retval = append(retval, o.Type()) continue } else { log.Printf("%T (%v) does not implement %s: missing %s, wrong type: %t", o, o, ifc, fnc, wrongType) } } return retval }
func visitTypeAssert(instr *ssa.TypeAssert, infer *TypeInfer, ctx *Context) { if iface, ok := instr.AssertedType.(*types.Interface); ok { if meth, _ := types.MissingMethod(instr.X.Type(), iface, true); meth == nil { // No missing methods inst, ok := ctx.F.locals[instr.X] if !ok { infer.Logger.Fatalf("typeassert: %s: iface X %+v", ErrUnknownValue, instr.X.Name()) return } if instr.CommaOk { ctx.F.locals[instr] = &Value{instr, ctx.F.InstanceID(), ctx.L.Index} ctx.F.commaok[ctx.F.locals[instr]] = &CommaOk{Instr: instr, Result: ctx.F.locals[instr]} ctx.F.tuples[ctx.F.locals[instr]] = make(Tuples, 2) infer.Logger.Print(ctx.F.Sprintf(SkipSymbol+"%s = typeassert iface %s commaok", ctx.F.locals[instr], inst)) return } ctx.F.locals[instr] = inst infer.Logger.Print(ctx.F.Sprintf(SkipSymbol+"%s = typeassert iface %s", ctx.F.locals[instr], inst)) return } infer.Logger.Fatalf("typeassert: %s: %+v", ErrMethodNotFound, instr) return } inst, ok := ctx.F.locals[instr.X] if !ok { infer.Logger.Fatalf("typeassert: %s: assert from %+v", ErrUnknownValue, instr.X) return } if instr.CommaOk { ctx.F.locals[instr] = &Value{instr, ctx.F.InstanceID(), ctx.L.Index} ctx.F.commaok[ctx.F.locals[instr]] = &CommaOk{Instr: instr, Result: ctx.F.locals[instr]} ctx.F.tuples[ctx.F.locals[instr]] = make(Tuples, 2) infer.Logger.Print(ctx.F.Sprintf(SkipSymbol+"%s = typeassert %s commaok", ctx.F.locals[instr], inst)) return } ctx.F.locals[instr] = inst infer.Logger.Print(ctx.F.Sprintf(SkipSymbol+"%s = typeassert %s", ctx.F.locals[instr], ctx.F.locals[instr.X])) return //infer.Logger.Fatalf("typeassert: %s: %+v", ErrIncompatType, instr) }
func (caller *frame) callCommon(call *ssa.Call, common *ssa.CallCommon) { switch fn := common.Value.(type) { case *ssa.Builtin: caller.callBuiltin(common) case *ssa.MakeClosure: // TODO(nickng) Handle calling closure fmt.Fprintf(os.Stderr, " # TODO (handle closure) %s\n", fn.String()) case *ssa.Function: if common.StaticCallee() == nil { panic("Call with nil CallCommon!") } callee := &frame{ fn: common.StaticCallee(), locals: make(map[ssa.Value]*utils.Definition), arrays: make(map[*utils.Definition]Elems), structs: make(map[*utils.Definition]Fields), tuples: make(map[ssa.Value]Tuples), phi: make(map[ssa.Value][]ssa.Value), recvok: make(map[ssa.Value]*sesstype.Chan), retvals: make(Tuples, common.Signature().Results().Len()), defers: make([]*ssa.Defer, 0), caller: caller, env: caller.env, // Use the same env as caller gortn: caller.gortn, // Use the same role as caller } fmt.Fprintf(os.Stderr, "++ call %s(", orange(common.StaticCallee().String())) callee.translate(common) fmt.Fprintf(os.Stderr, ")\n") if callee.isRecursive() { fmt.Fprintf(os.Stderr, "-- Recursive %s()\n", orange(common.StaticCallee().String())) callee.printCallStack() } else { if hasCode := visitFunc(callee.fn, callee); hasCode { caller.handleRetvals(call.Value(), callee) } else { caller.handleExtRetvals(call.Value(), callee) } fmt.Fprintf(os.Stderr, "-- return from %s (%d retvals)\n", orange(common.StaticCallee().String()), len(callee.retvals)) } default: if !common.IsInvoke() { fmt.Fprintf(os.Stderr, "Unknown call type %v\n", common) return } switch vd, kind := caller.get(common.Value); kind { case Struct, LocalStruct: fmt.Fprintf(os.Stderr, "++ invoke %s.%s, type=%s\n", reg(common.Value), common.Method.String(), vd.Var.Type().String()) // If dealing with interfaces, check that the method is invokable if iface, ok := common.Value.Type().Underlying().(*types.Interface); ok { if meth, _ := types.MissingMethod(vd.Var.Type(), iface, true); meth != nil { fmt.Fprintf(os.Stderr, " ^ interface not fully implemented\n") } else { fn := findMethod(common.Value.Parent().Prog, common.Method, vd.Var.Type()) if fn != nil { fmt.Fprintf(os.Stderr, " ^ found function %s\n", fn.String()) callee := &frame{ fn: fn, locals: make(map[ssa.Value]*utils.Definition), arrays: make(map[*utils.Definition]Elems), structs: make(map[*utils.Definition]Fields), tuples: make(map[ssa.Value]Tuples), phi: make(map[ssa.Value][]ssa.Value), recvok: make(map[ssa.Value]*sesstype.Chan), retvals: make(Tuples, common.Signature().Results().Len()), defers: make([]*ssa.Defer, 0), caller: caller, env: caller.env, // Use the same env as caller gortn: caller.gortn, // Use the same role as caller } common.Args = append([]ssa.Value{common.Value}, common.Args...) fmt.Fprintf(os.Stderr, "++ call %s(", orange(fn.String())) callee.translate(common) fmt.Fprintf(os.Stderr, ")\n") if callee.isRecursive() { fmt.Fprintf(os.Stderr, "-- Recursive %s()\n", orange(fn.String())) callee.printCallStack() } else { if hasCode := visitFunc(callee.fn, callee); hasCode { caller.handleRetvals(call.Value(), callee) } else { caller.handleExtRetvals(call.Value(), callee) } fmt.Fprintf(os.Stderr, "-- return from %s (%d retvals)\n", orange(fn.String()), len(callee.retvals)) } } else { panic(fmt.Sprintf("Cannot call function: %s.%s is abstract (program not well-formed)", common.Value, common.Method.String())) } } } else { fmt.Fprintf(os.Stderr, " ^ method %s.%s does not exist\n", reg(common.Value), common.Method.String()) } default: fmt.Fprintf(os.Stderr, "++ invoke %s.%s\n", reg(common.Value), common.Method.String()) } } }