Пример #1
0
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())
}
Пример #2
0
// 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
}
Пример #3
0
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)
}
Пример #4
0
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
}
Пример #5
0
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)
}
Пример #6
0
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())
		}
	}
}