Пример #1
0
// tysubst attempts to substitute all type variables within a single return
// type with their corresponding Go type from the type environment.
//
// tysubst will panic if a type variable is unbound, or if it encounters a
// type that cannot be dynamically created. Such types include arrays,
// functions and structs. (A limitation of the `reflect` package.)
func (rt returnType) tysubst(typ reflect.Type) reflect.Type {
	if tyname := tyvarName(typ); len(tyname) > 0 {
		if thetype, ok := rt.tyenv[tyname]; !ok {
			rt.panic("Unbound type variable %s.", tyname)
		} else {
			return thetype
		}
	}

	switch typ.Kind() {
	case reflect.Array:
		rt.panic("Cannot dynamically create Array types.")
	case reflect.Chan:
		return reflect.ChanOf(typ.ChanDir(), rt.tysubst(typ.Elem()))
	case reflect.Func:
		rt.panic("Cannot dynamically create Function types.")
	case reflect.Interface:
		rt.panic("TODO")
	case reflect.Map:
		return reflect.MapOf(rt.tysubst(typ.Key()), rt.tysubst(typ.Elem()))
	case reflect.Ptr:
		return reflect.PtrTo(rt.tysubst(typ.Elem()))
	case reflect.Slice:
		return reflect.SliceOf(rt.tysubst(typ.Elem()))
	case reflect.Struct:
		rt.panic("Cannot dynamically create Struct types.")
	case reflect.UnsafePointer:
		rt.panic("Cannot dynamically create unsafe.Pointer types.")
	}

	// We've covered all the composite types, so we're only left with
	// base types.
	return typ
}
Пример #2
0
// Return the string that should be used to refer to the supplied type within
// the given package. The output is not guaranteed to be pretty, and should be
// run through a tool like gofmt afterward.
//
// For example, a pointer to an io.Reader may be rendered as "*Reader" or
// "*io.Reader" depending on whether the package path is "io" or not.
func typeString(
	t reflect.Type,
	pkgPath string) (s string) {
	// Is this type named? If so we use its name, possibly with a package prefix.
	//
	// Examples:
	//
	//     int
	//     string
	//     error
	//     gcs.Bucket
	//
	if t.Name() != "" {
		if t.PkgPath() == pkgPath {
			s = t.Name()
		} else {
			s = t.String()
		}

		return
	}

	// This type is unnamed. Recurse.
	switch t.Kind() {
	case reflect.Array:
		s = fmt.Sprintf("[%d]%s", t.Len(), typeString(t.Elem(), pkgPath))

	case reflect.Chan:
		s = fmt.Sprintf("%s %s", t.ChanDir(), typeString(t.Elem(), pkgPath))

	case reflect.Func:
		s = typeString_Func(t, pkgPath)

	case reflect.Interface:
		s = typeString_Interface(t, pkgPath)

	case reflect.Map:
		s = fmt.Sprintf(
			"map[%s]%s",
			typeString(t.Key(), pkgPath),
			typeString(t.Elem(), pkgPath))

	case reflect.Ptr:
		s = fmt.Sprintf("*%s", typeString(t.Elem(), pkgPath))

	case reflect.Slice:
		s = fmt.Sprintf("[]%s", typeString(t.Elem(), pkgPath))

	case reflect.Struct:
		s = typeString_Struct(t, pkgPath)

	default:
		log.Panicf("Unhandled kind %v for type: %v", t.Kind(), t)
	}

	return
}
Пример #3
0
func ValType(t reflect.Type) (decl string) {
	switch k := t.Kind(); k {
	case reflect.Struct:
		decl = "struct {\n"
		for i, ed := 0, t.NumField(); i < ed; i++ {
			ft := t.Field(i)
			if ft.Tag != "-" || ft.Tag.Get("goval") == "-" {
				s := ft.Name + " " + ValType(ft.Type)
				if ft.Tag != "" {
					s += " `" + strings.Replace("`", "\\`", string(ft.Tag), -1) + "`"
				}
				decl += indent(s) + "\n"
			}
		}
		decl += "}"
	case reflect.Array:
		decl = "[" + strconv.Itoa(t.Len()) + "]" + Val(t.Elem())
	case reflect.Slice:
		decl = "[]" + Val(t.Elem())
	case reflect.Chan:
		switch t.ChanDir() {
		case reflect.RecvDir:
			decl = "<-chan "
		case reflect.SendDir:
			decl = "chan<- "
		case reflect.BothDir:
			decl = "chan "
		default:
			panic("Didn't expect a dir other than send, recieve or both.")
		}
		decl += Val(t.Elem())
	case reflect.Map:
		decl = "map[" + ValType(t.Key()) + "]" + ValType(t.Elem())
	case reflect.Ptr:
		decl = "*" + ValType(t.Elem())
	case reflect.Interface:
		decl = "interface {\n"
		for i, ed := 0, t.NumMethod(); i < ed; i++ {
			ft := t.Method(i)
			s := ft.Name + FormatFuncArguments(ft.Type)
			decl += indent(s) + "\n"
		}
		decl += "}"
	case reflect.Func:
		decl = "func" + FormatFuncArguments(t)
	default:
		return k.String()
	}

	return
}
Пример #4
0
// checkMethod verifies whether the specified method has a valid RPC handler
// signature:
//   func(R, Context, IN, chan<- OUT) error
//   func(R, Context, IN) (OUT, error)
//
// If so, returns a filled-in *Method; otherwise returns an error.
func checkMethod(rcvr interface{}, m reflect.Method) (*Method, error) {
	if !ast.IsExported(m.Name) {
		return nil, errors.New("method is not exported")
	}
	t := m.Type

	if t.Kind() != reflect.Func || t.NumIn() < 3 || t.In(1) != ctxType || !structOrStructPtr(t.In(2)) {
		return nil, errors.New("invalid method signature")
	}

	var (
		stream bool
		out    reflect.Type
	)
	switch {
	case t.NumIn() == 4 && t.NumOut() == 1 && t.Out(0) == errType:
		// Signature: (receiver, Context, input, chan output) => error
		out = t.In(3)
		if out.Kind() != reflect.Chan || out.ChanDir()&reflect.SendDir == 0 {
			return nil, errors.New("invalid output type")
		}
		stream = true
		out = out.Elem()
	case t.NumIn() == 3 && t.NumOut() == 2 && t.Out(1) == errType:
		// Signature: (receiver, Context, input) => (output, error)
		out = t.Out(0)
	}

	in := t.In(2)
	if in.Kind() == reflect.Ptr {
		in = in.Elem()
	}

	params := []string{}
	for i := 0; i < in.NumField(); i++ {
		params = append(params, in.Field(i).Name)
	}
	sort.Strings(params)

	return &Method{
		Name:   m.Name,
		Params: params,
		Stream: stream,

		input:  t.In(2),
		output: out,

		rcvr: reflect.ValueOf(rcvr),
		fun:  m.Func,
	}, nil
}
Пример #5
0
func main() {
	var i int
	var recvDir reflect.ChanDir = reflect.RecvDir
	var chanOf reflect.Type = reflect.ChanOf(recvDir, reflect.TypeOf(i))
	fmt.Println(chanOf.Kind())    // chan
	fmt.Println(chanOf.ChanDir()) // <-chan
	fmt.Println(chanOf.String())  // <-chan int

	var i1 int
	var recvDir1 reflect.ChanDir = reflect.SendDir
	var chanOf1 reflect.Type = reflect.ChanOf(recvDir1, reflect.TypeOf(i1))
	fmt.Println(chanOf1.Kind(), chanOf1.ChanDir(), chanOf1.String())
	// chan chan<- chan<- int

	var i2 int
	var recvDir2 reflect.ChanDir = reflect.BothDir
	var chanOf2 reflect.Type = reflect.ChanOf(recvDir2, reflect.TypeOf(i2))
	fmt.Println(chanOf2.Kind(), chanOf2.ChanDir(), chanOf2.String())
	// chan chan chan int

	var i3 string
	var recvDir3 reflect.ChanDir = reflect.BothDir
	var chanOf3 reflect.Type = reflect.ChanOf(recvDir3, reflect.TypeOf(i3))
	fmt.Println(chanOf3.Kind(), chanOf3.ChanDir(), chanOf3.String())
	// chan chan chan string
}
Пример #6
0
// unify attempts to satisfy a pair of types, where the `param` type is the
// expected type of a function argument and the `input` type is the known
// type of a function argument. The `param` type may be parametric (that is,
// it may contain a type that is convertible to TypeVariable) but the
// `input` type may *not* be parametric.
//
// Any failure to unify the two types results in a panic.
//
// The end result of unification is a type environment: a set of substitutions
// from type variable to a Go type.
func (tp typePair) unify(param, input reflect.Type) error {
	if tyname := tyvarName(input); len(tyname) > 0 {
		return tp.error("Type variables are not allowed in the types of " +
			"arguments.")
	}
	if tyname := tyvarName(param); len(tyname) > 0 {
		if cur, ok := tp.tyenv[tyname]; ok && cur != input {
			return tp.error("Type variable %s expected type '%s' but got '%s'.",
				tyname, cur, input)
		} else if !ok {
			tp.tyenv[tyname] = input
		}
		return nil
	}
	if param.Kind() != input.Kind() {
		return tp.error("Cannot unify different kinds of types '%s' and '%s'.",
			param, input)
	}

	switch param.Kind() {
	case reflect.Array:
		return tp.unify(param.Elem(), input.Elem())
	case reflect.Chan:
		if param.ChanDir() != input.ChanDir() {
			return tp.error("Cannot unify '%s' with '%s' "+
				"(channel directions are different: '%s' != '%s').",
				param, input, param.ChanDir(), input.ChanDir())
		}
		return tp.unify(param.Elem(), input.Elem())
	case reflect.Func:
		if param.NumIn() != input.NumIn() || param.NumOut() != input.NumOut() {
			return tp.error("Cannot unify '%s' with '%s'.", param, input)
		}
		for i := 0; i < param.NumIn(); i++ {
			if err := tp.unify(param.In(i), input.In(i)); err != nil {
				return err
			}
		}
		for i := 0; i < param.NumOut(); i++ {
			if err := tp.unify(param.Out(i), input.Out(i)); err != nil {
				return err
			}
		}
	case reflect.Map:
		if err := tp.unify(param.Key(), input.Key()); err != nil {
			return err
		}
		return tp.unify(param.Elem(), input.Elem())
	case reflect.Ptr:
		return tp.unify(param.Elem(), input.Elem())
	case reflect.Slice:
		return tp.unify(param.Elem(), input.Elem())
	}

	// The only other container types are Interface and Struct.
	// I am unsure about what to do with interfaces. Mind is fuzzy.
	// Structs? I don't think it really makes much sense to use type
	// variables inside of them.
	return nil
}
Пример #7
0
// GetName of a type.
func (opts *GenOpts) GetName(t reflect.Type) string {
	name := t.Name()
	if name != "" {
		pkg, _ := packageAndName(t)
		// Handle the case the type is in the package we are generating code for.
		if pkg == "" || pkg == opts.PkgName {
			return name
		}
		return fmt.Sprintf("%s.%s", pkg, name)
	}
	switch t.Kind() {
	case reflect.Ptr:
		return fmt.Sprintf("*%s", opts.GetName(t.Elem()))
	case reflect.Map:
		return fmt.Sprintf("map[%s]%s", opts.GetName(t.Key()), opts.GetName(t.Elem()))
	case reflect.Slice:
		return fmt.Sprintf("[]%s", opts.GetName(t.Elem()))
	case reflect.Chan:
		return fmt.Sprintf("%s %s", t.ChanDir().String(), opts.GetName(t.Elem()))
	case reflect.Array:
		return fmt.Sprintf("[%d]%s", t.Len(), opts.GetName(t.Elem()))
	case reflect.Func:
		inputs := make([]string, t.NumIn())
		for i := range inputs {
			inputs[i] = opts.GetName(t.In(i))
		}
		outputs := make([]string, t.NumOut())
		for i := range outputs {
			outputs[i] = opts.GetName(t.Out(i))
		}
		out := strings.Join(outputs, ", ")
		if len(outputs) > 1 {
			out = fmt.Sprintf("(%s)", out)
		}
		return fmt.Sprintf("func (%s) %s", strings.Join(inputs, ", "), out)
	default:
		return t.String()
	}
}
Пример #8
0
func typeFromType(t reflect.Type) (Type, error) {
	// Hack workaround for https://golang.org/issue/3853.
	// This explicit check should not be necessary.
	if t == byteType {
		return PredeclaredType("byte"), nil
	}

	if imp := t.PkgPath(); imp != "" {
		return &NamedType{
			Package: imp,
			Type:    t.Name(),
		}, nil
	}

	// only unnamed or predeclared types after here

	// Lots of types have element types. Let's do the parsing and error checking for all of them.
	var elemType Type
	switch t.Kind() {
	case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice:
		var err error
		elemType, err = typeFromType(t.Elem())
		if err != nil {
			return nil, err
		}
	}

	switch t.Kind() {
	case reflect.Array:
		return &ArrayType{
			Len:  t.Len(),
			Type: elemType,
		}, nil
	case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
		reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String:
		return PredeclaredType(t.Kind().String()), nil
	case reflect.Chan:
		var dir ChanDir
		switch t.ChanDir() {
		case reflect.RecvDir:
			dir = RecvDir
		case reflect.SendDir:
			dir = SendDir
		}
		return &ChanType{
			Dir:  dir,
			Type: elemType,
		}, nil
	case reflect.Func:
		in, variadic, out, err := funcArgsFromType(t)
		if err != nil {
			return nil, err
		}
		return &FuncType{
			In:       in,
			Out:      out,
			Variadic: variadic,
		}, nil
	case reflect.Interface:
		// Two special interfaces.
		if t.NumMethod() == 0 {
			return PredeclaredType("interface{}"), nil
		}
		if t == errorType {
			return PredeclaredType("error"), nil
		}
	case reflect.Map:
		kt, err := typeFromType(t.Key())
		if err != nil {
			return nil, err
		}
		return &MapType{
			Key:   kt,
			Value: elemType,
		}, nil
	case reflect.Ptr:
		return &PointerType{
			Type: elemType,
		}, nil
	case reflect.Slice:
		return &ArrayType{
			Len:  -1,
			Type: elemType,
		}, nil
	case reflect.Struct:
		if t.NumField() == 0 {
			return PredeclaredType("struct{}"), nil
		}
	}

	// TODO: Struct, UnsafePointer
	return nil, fmt.Errorf("can't yet turn %v (%v) into a model.Type", t, t.Kind())
}