func (g *ObjcGen) genWrite(varName string, t types.Type, mode varMode) { switch t := t.(type) { case *types.Basic: switch t.Kind() { case types.String: g.Printf("nstring _%s = go_seq_from_objc_string(%s);\n", varName, varName) default: g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName) } case *types.Slice: switch e := t.Elem().(type) { case *types.Basic: switch e.Kind() { case types.Uint8: // Byte. g.Printf("nbyteslice _%s = go_seq_from_objc_bytearray(%s, %d);\n", varName, varName, toCFlag(mode == modeRetained)) default: g.errorf("unsupported type: %s", t) } default: g.errorf("unsupported type: %s", t) } case *types.Named: switch u := t.Underlying().(type) { case *types.Interface: g.genRefWrite(varName) default: g.errorf("unsupported named type: %s / %T", u, u) } case *types.Pointer: g.genRefWrite(varName) default: g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName) } }
// zeroConst returns a new "zero" constant of the specified type, // which must not be an array or struct type: the zero values of // aggregates are well-defined but cannot be represented by Const. // func zeroConst(t types.Type) *Const { switch t := t.(type) { case *types.Basic: switch { case t.Info()&types.IsBoolean != 0: return NewConst(exact.MakeBool(false), t) case t.Info()&types.IsNumeric != 0: return NewConst(exact.MakeInt64(0), t) case t.Info()&types.IsString != 0: return NewConst(exact.MakeString(""), t) case t.Kind() == types.UnsafePointer: fallthrough case t.Kind() == types.UntypedNil: return nilConst(t) default: panic(fmt.Sprint("zeroConst for unexpected type:", t)) } case *types.Pointer, *types.Slice, *types.Interface, *types.Chan, *types.Map, *types.Signature: return nilConst(t) case *types.Named: return NewConst(zeroConst(t.Underlying()).Value, t) case *types.Array, *types.Struct, *types.Tuple: panic(fmt.Sprint("zeroConst applied to aggregate:", t)) } panic(fmt.Sprint("zeroConst: unexpected ", t)) }
func asmKindForType(t types.Type, size int) asmKind { switch t := t.Underlying().(type) { case *types.Basic: switch t.Kind() { case types.String: return asmString case types.Complex64, types.Complex128: return asmComplex } return asmKind(size) case *types.Pointer, *types.Chan, *types.Map, *types.Signature: return asmKind(size) case *types.Struct: return asmStruct case *types.Interface: if t.Empty() { return asmEmptyInterface } return asmInterface case *types.Array: return asmArray case *types.Slice: return asmSlice } panic("unreachable") }
// javaTypeDefault returns a string that represents the default value of the mapped java type. // TODO(hyangah): Combine javaType and javaTypeDefault? func (g *javaGen) javaTypeDefault(T types.Type) string { switch T := T.(type) { case *types.Basic: switch T.Kind() { case types.Bool: return "false" case types.Int, types.Int8, types.Int16, types.Int32, types.Int64, types.Uint8: return "0" case types.Float32, types.Float64: return "0.0" case types.String: return "null" default: g.errorf("unsupported return type: %s", T) return "TODO" } case *types.Slice, *types.Pointer, *types.Named: return "null" default: g.errorf("unsupported javaType: %#+v, %s\n", T, T) return "TODO" } }
// cgoType returns the name of a Cgo type suitable for converting a value of // the given type. func (g *generator) cgoType(t types.Type) string { if isErrorType(t) { return g.cgoType(types.Typ[types.String]) } switch t := t.(type) { case *types.Basic: switch t.Kind() { case types.Bool, types.UntypedBool: return "char" case types.Int: return "nint" case types.Int8: return "int8_t" case types.Int16: return "int16_t" case types.Int32, types.UntypedRune: // types.Rune return "int32_t" case types.Int64, types.UntypedInt: return "int64_t" case types.Uint8: // types.Byte return "uint8_t" // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: case types.Float32: return "float" case types.Float64, types.UntypedFloat: return "double" case types.String: return "nstring" default: g.errorf("unsupported basic type: %s", t) } case *types.Slice: switch e := t.Elem().(type) { case *types.Basic: switch e.Kind() { case types.Uint8: // Byte. return "nbyteslice" default: g.errorf("unsupported slice type: %s", t) } default: g.errorf("unsupported slice type: %s", t) } case *types.Pointer: if _, ok := t.Elem().(*types.Named); ok { return g.cgoType(t.Elem()) } g.errorf("unsupported pointer to type: %s", t) case *types.Named: return "int32_t" default: g.errorf("unsupported type: %s", t) } return "TODO" }
func (g *goGen) genWrite(toVar, fromVar string, t types.Type, mode varMode) { if isErrorType(t) { g.Printf("var %s_str string\n", toVar) g.Printf("if %s == nil {\n", fromVar) g.Printf(" %s_str = \"\"\n", toVar) g.Printf("} else {\n") g.Printf(" %s_str = %s.Error()\n", toVar, fromVar) g.Printf("}\n") g.genWrite(toVar, toVar+"_str", types.Typ[types.String], mode) return } switch t := t.(type) { case *types.Basic: switch t.Kind() { case types.String: g.Printf("%s := encodeString(%s)\n", toVar, fromVar) case types.Bool: g.Printf("var %s C.%s = 0\n", toVar, g.cgoType(t)) g.Printf("if %s { %s = 1 }\n", fromVar, toVar) default: g.Printf("%s := C.%s(%s)\n", toVar, g.cgoType(t), fromVar) } case *types.Slice: switch e := t.Elem().(type) { case *types.Basic: switch e.Kind() { case types.Uint8: // Byte. g.Printf("%s := fromSlice(%s, %v)\n", toVar, fromVar, mode == modeRetained) default: g.errorf("unsupported type: %s", t) } default: g.errorf("unsupported type: %s", t) } case *types.Pointer: // TODO(crawshaw): test *int // TODO(crawshaw): test **Generator switch t := t.Elem().(type) { case *types.Named: g.genToRefNum(toVar, fromVar) default: g.errorf("unsupported type %s", t) } case *types.Named: switch u := t.Underlying().(type) { case *types.Interface, *types.Pointer: g.genToRefNum(toVar, fromVar) default: g.errorf("unsupported, direct named type %s: %s", t, u) } default: g.errorf("unsupported type %s", t) } }
// javaType returns a string that can be used as a Java type. func (g *javaGen) javaType(T types.Type) string { switch T := T.(type) { case *types.Basic: switch T.Kind() { case types.Bool: return "boolean" case types.Int: return "long" case types.Int8: return "byte" case types.Int16: return "short" case types.Int32: return "int" case types.Int64: return "long" case types.Uint8: // TODO(crawshaw): Java bytes are signed, so this is // questionable, but vital. return "byte" // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: case types.Float32: return "float" case types.Float64: return "double" case types.String: return "String" default: g.errorf("unsupported return type: %s", T) return "TODO" } case *types.Slice: elem := g.javaType(T.Elem()) return elem + "[]" case *types.Pointer: if _, ok := T.Elem().(*types.Named); ok { return g.javaType(T.Elem()) } panic(fmt.Sprintf("unsupporter pointer to type: %s", T)) case *types.Named: n := T.Obj() if n.Pkg() != g.pkg { panic(fmt.Sprintf("type %s is in package %s, must be defined in package %s", n.Name(), n.Pkg().Name(), g.pkg.Name())) } // TODO(crawshaw): more checking here return n.Name() default: g.errorf("unsupported javaType: %#+v, %s\n", T, T) return "TODO" } }
// jniType returns a string that can be used as a JNI type. func (g *javaGen) jniType(T types.Type) string { if isErrorType(T) { // The error type is usually translated into an exception in // Java, however the type can be exposed in other ways, such // as an exported field. return g.jniType(types.Typ[types.String]) } switch T := T.(type) { case *types.Basic: switch T.Kind() { case types.Bool, types.UntypedBool: return "jboolean" case types.Int: return "jlong" case types.Int8: return "jbyte" case types.Int16: return "jshort" case types.Int32, types.UntypedRune: // types.Rune return "jint" case types.Int64, types.UntypedInt: return "jlong" case types.Uint8: // types.Byte // TODO(crawshaw): Java bytes are signed, so this is // questionable, but vital. return "jbyte" // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: case types.Float32: return "jfloat" case types.Float64, types.UntypedFloat: return "jdouble" case types.String, types.UntypedString: return "jstring" default: g.errorf("unsupported basic type: %s", T) return "TODO" } case *types.Slice: return "jbyteArray" case *types.Pointer: if _, ok := T.Elem().(*types.Named); ok { return g.jniType(T.Elem()) } g.errorf("unsupported pointer to type: %s", T) case *types.Named: return "jobject" default: g.errorf("unsupported jniType: %#+v, %s\n", T, T) } return "TODO" }
func (g *javaGen) genCToJava(toName, fromName string, t types.Type, mode varMode) { if isErrorType(t) { g.genCToJava(toName, fromName, types.Typ[types.String], mode) return } switch t := t.(type) { case *types.Basic: switch t.Kind() { case types.String: g.Printf("jstring %s = go_seq_to_java_string(env, %s);\n", toName, fromName) case types.Bool: g.Printf("jboolean %s = %s ? JNI_TRUE : JNI_FALSE;\n", toName, fromName) default: g.Printf("%s %s = (%s)%s;\n", g.jniType(t), toName, g.jniType(t), fromName) } case *types.Slice: switch e := t.Elem().(type) { case *types.Basic: switch e.Kind() { case types.Uint8: // Byte. g.Printf("jbyteArray %s = go_seq_to_java_bytearray(env, %s, %d);\n", toName, fromName, g.toCFlag(mode == modeRetained)) default: g.errorf("unsupported type: %s", t) } default: g.errorf("unsupported type: %s", t) } case *types.Pointer: // TODO(crawshaw): test *int // TODO(crawshaw): test **Generator switch t := t.Elem().(type) { case *types.Named: g.genFromRefnum(toName, fromName, t, t.Obj()) default: g.errorf("unsupported type %s", t) } case *types.Named: switch t.Underlying().(type) { case *types.Interface, *types.Pointer: g.genFromRefnum(toName, fromName, t, t.Obj()) default: g.errorf("unsupported, direct named type %s", t) } default: g.Printf("%s %s = (%s)%s;\n", g.jniType(t), toName, g.jniType(t), fromName) } }
// jniType returns a string that can be used as a JNI type. func (g *JavaGen) jniType(T types.Type) string { switch T := T.(type) { case *types.Basic: switch T.Kind() { case types.Bool, types.UntypedBool: return "jboolean" case types.Int: return "jlong" case types.Int8: return "jbyte" case types.Int16: return "jshort" case types.Int32, types.UntypedRune: // types.Rune return "jint" case types.Int64, types.UntypedInt: return "jlong" case types.Uint8: // types.Byte // TODO(crawshaw): Java bytes are signed, so this is // questionable, but vital. return "jbyte" // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: case types.Float32: return "jfloat" case types.Float64, types.UntypedFloat: return "jdouble" case types.String, types.UntypedString: return "jstring" default: g.errorf("unsupported basic type: %s", T) return "TODO" } case *types.Slice: return "jbyteArray" case *types.Pointer: if _, ok := T.Elem().(*types.Named); ok { return g.jniType(T.Elem()) } g.errorf("unsupported pointer to type: %s", T) case *types.Named: return "jobject" default: g.errorf("unsupported jniType: %#+v, %s\n", T, T) } return "TODO" }
func (g *objcGen) genRead(toName, fromName string, t types.Type, mode varMode) { if isErrorType(t) { g.genRead(toName, fromName, types.Typ[types.String], mode) return } switch t := t.(type) { case *types.Basic: switch t.Kind() { case types.String: g.Printf("NSString *%s = go_seq_to_objc_string(%s);\n", toName, fromName) case types.Bool: g.Printf("BOOL %s = %s ? YES : NO;\n", toName, fromName) default: g.Printf("%s %s = (%s)%s;\n", g.objcType(t), toName, g.objcType(t), fromName) } case *types.Slice: switch e := t.Elem().(type) { case *types.Basic: switch e.Kind() { case types.Uint8: // Byte. g.Printf("NSData *%s = go_seq_to_objc_bytearray(%s, %d);\n", toName, fromName, g.toCFlag(mode == modeRetained)) default: g.errorf("unsupported type: %s", t) } default: g.errorf("unsupported type: %s", t) } case *types.Pointer: switch t := t.Elem().(type) { case *types.Named: g.genRefRead(toName, fromName, types.NewPointer(t)) default: g.errorf("unsupported type %s", t) } case *types.Named: switch t.Underlying().(type) { case *types.Interface, *types.Pointer: g.genRefRead(toName, fromName, t) default: g.errorf("unsupported, direct named type %s", t) } default: g.Printf("%s %s = (%s)%s;\n", g.objcType(t), toName, g.objcType(t), fromName) } }
func (g *javaGen) jniSigType(T types.Type) string { if isErrorType(T) { return g.jniSigType(types.Typ[types.String]) } switch T := T.(type) { case *types.Basic: switch T.Kind() { case types.Bool, types.UntypedBool: return "Z" case types.Int: return "J" case types.Int8: return "B" case types.Int16: return "S" case types.Int32, types.UntypedRune: // types.Rune return "I" case types.Int64, types.UntypedInt: return "J" case types.Uint8: // types.Byte return "B" case types.Float32: return "F" case types.Float64, types.UntypedFloat: return "D" case types.String, types.UntypedString: return "Ljava/lang/String;" default: g.errorf("unsupported basic type: %s", T) return "TODO" } case *types.Slice: return "[" + g.jniSigType(T.Elem()) case *types.Pointer: if _, ok := T.Elem().(*types.Named); ok { return g.jniSigType(T.Elem()) } g.errorf("unsupported pointer to type: %s", T) case *types.Named: return "L" + g.jniClassSigPrefix(T.Obj().Pkg()) + T.Obj().Name() + ";" default: g.errorf("unsupported jniType: %#+v, %s\n", T, T) } return "TODO" }
func (f *File) validResultType(typ types.Type) *Error { switch typ.(type) { default: name := typ.String() if named, ok := typ.(*types.Named); ok { name = named.Obj().Name() } return &Error{errors.New(fmt.Sprint("Invalid result type:", name)), 0} case *types.Basic: typ := typ.(*types.Basic) switch typ.Kind() { default: return &Error{errors.New(fmt.Sprint("Invalid basic type for result type :", typ.Info())), 0} case types.Bool: return nil case types.Int: return nil case types.Int8: return nil case types.Int16: return nil case types.Int32: return nil case types.Int64: return nil case types.Uint: return nil case types.Uint8: return nil case types.Uint16: return nil case types.Uint32: return nil case types.Uint64: return nil case types.Float32: return nil case types.Float64: return nil } } }
func (g *javaGen) jniCallType(t types.Type) string { if isErrorType(t) { return g.jniCallType(types.Typ[types.String]) } switch t := t.(type) { case *types.Basic: switch t.Kind() { case types.Bool, types.UntypedBool: return "Boolean" case types.Int: return "Long" case types.Int8, types.Uint8: // types.Byte return "Byte" case types.Int16: return "Short" case types.Int32, types.UntypedRune: // types.Rune return "Int" case types.Int64, types.UntypedInt: return "Long" case types.Float32: return "Float" case types.Float64, types.UntypedFloat: return "Double" case types.String, types.UntypedString: return "Object" default: g.errorf("unsupported basic type: %s", t) } case *types.Slice: return "Object" case *types.Pointer: if _, ok := t.Elem().(*types.Named); ok { return g.jniCallType(t.Elem()) } g.errorf("unsupported pointer to type: %s", t) case *types.Named: return "Object" default: return "Object" } return "TODO" }
func (g *javaGen) genJavaToC(varName string, t types.Type, mode varMode) { if isErrorType(t) { g.genJavaToC(varName, types.Typ[types.String], mode) return } switch t := t.(type) { case *types.Basic: switch t.Kind() { case types.String: g.Printf("nstring _%s = go_seq_from_java_string(env, %s);\n", varName, varName) default: g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName) } case *types.Slice: switch e := t.Elem().(type) { case *types.Basic: switch e.Kind() { case types.Uint8: // Byte. g.Printf("nbyteslice _%s = go_seq_from_java_bytearray(env, %s, %d);\n", varName, varName, g.toCFlag(mode == modeRetained)) default: g.errorf("unsupported type: %s", t) } default: g.errorf("unsupported type: %s", t) } case *types.Named: switch u := t.Underlying().(type) { case *types.Interface: g.Printf("int32_t _%s = go_seq_to_refnum(env, %s);\n", varName, varName) default: g.errorf("unsupported named type: %s / %T", u, u) } case *types.Pointer: g.Printf("int32_t _%s = go_seq_to_refnum(env, %s);\n", varName, varName) default: g.Printf("%s _%s = (%s)%s;\n", g.cgoType(t), varName, g.cgoType(t), varName) } }
// matchArgTypeInternal is the internal version of matchArgType. It carries a map // remembering what types are in progress so we don't recur when faced with recursive // types or mutually recursive types. func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Expr, inProgress map[types.Type]bool) bool { // %v, %T accept any argument type. if t == anyType { return true } if typ == nil { // external call typ = f.pkg.types[arg].Type if typ == nil { return true // probably a type check problem } } // If the type implements fmt.Formatter, we have nothing to check. if f.isFormatter(typ) { return true } // If we can use a string, might arg (dynamically) implement the Stringer or Error interface? if t&argString != 0 { if types.AssertableTo(errorType, typ) || stringerType != nil && types.AssertableTo(stringerType, typ) { return true } } typ = typ.Underlying() if inProgress[typ] { // We're already looking at this type. The call that started it will take care of it. return true } inProgress[typ] = true switch typ := typ.(type) { case *types.Signature: return t&argPointer != 0 case *types.Map: // Recur: map[int]int matches %d. return t&argPointer != 0 || (f.matchArgTypeInternal(t, typ.Key(), arg, inProgress) && f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress)) case *types.Chan: return t&argPointer != 0 case *types.Array: // Same as slice. if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 { return true // %s matches []byte } // Recur: []int matches %d. return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem().Underlying(), arg, inProgress) case *types.Slice: // Same as array. if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 { return true // %s matches []byte } // Recur: []int matches %d. But watch out for // type T []T // If the element is a pointer type (type T[]*T), it's handled fine by the Pointer case below. return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress) case *types.Pointer: // Ugly, but dealing with an edge case: a known pointer to an invalid type, // probably something from a failed import. if typ.Elem().String() == "invalid type" { if *verbose { f.Warnf(arg.Pos(), "printf argument %v is pointer to invalid or unknown type", f.gofmt(arg)) } return true // special case } // If it's actually a pointer with %p, it prints as one. if t == argPointer { return true } // If it's pointer to struct, that's equivalent in our analysis to whether we can print the struct. if str, ok := typ.Elem().Underlying().(*types.Struct); ok { return f.matchStructArgType(t, str, arg, inProgress) } // The rest can print with %p as pointers, or as integers with %x etc. return t&(argInt|argPointer) != 0 case *types.Struct: return f.matchStructArgType(t, typ, arg, inProgress) case *types.Interface: // There's little we can do. // Whether any particular verb is valid depends on the argument. // The user may have reasonable prior knowledge of the contents of the interface. return true case *types.Basic: switch typ.Kind() { case types.UntypedBool, types.Bool: return t&argBool != 0 case types.UntypedInt, types.Int, types.Int8, types.Int16, types.Int32, types.Int64, types.Uint, types.Uint8, types.Uint16, types.Uint32, types.Uint64, types.Uintptr: return t&argInt != 0 case types.UntypedFloat, types.Float32, types.Float64: return t&argFloat != 0 case types.UntypedComplex, types.Complex64, types.Complex128: return t&argComplex != 0 case types.UntypedString, types.String: return t&argString != 0 case types.UnsafePointer: return t&(argPointer|argInt) != 0 case types.UntypedRune: return t&(argInt|argRune) != 0 case types.UntypedNil: return t&argPointer != 0 // TODO? case types.Invalid: if *verbose { f.Warnf(arg.Pos(), "printf argument %v has invalid or unknown type", f.gofmt(arg)) } return true // Probably a type check problem. } panic("unreachable") } return false }
func (g *ObjcGen) objcType(typ types.Type) string { if isErrorType(typ) { return "NSError*" } switch typ := typ.(type) { case *types.Basic: switch typ.Kind() { case types.Bool, types.UntypedBool: return "BOOL" case types.Int: return "long" case types.Int8: return "int8_t" case types.Int16: return "int16_t" case types.Int32, types.UntypedRune: // types.Rune return "int32_t" case types.Int64, types.UntypedInt: return "int64_t" case types.Uint8: // byte is an alias of uint8, and the alias is lost. return "byte" case types.Uint16: return "uint16_t" case types.Uint32: return "uint32_t" case types.Uint64: return "uint64_t" case types.Float32: return "float" case types.Float64, types.UntypedFloat: return "double" case types.String, types.UntypedString: return "NSString*" default: g.errorf("unsupported type: %s", typ) return "TODO" } case *types.Slice: elem := g.objcType(typ.Elem()) // Special case: NSData seems to be a better option for byte slice. if elem == "byte" { return "NSData*" } // TODO(hyangah): support other slice types: NSArray or CFArrayRef. // Investigate the performance implication. g.errorf("unsupported type: %s", typ) return "TODO" case *types.Pointer: if _, ok := typ.Elem().(*types.Named); ok { return g.objcType(typ.Elem()) + "*" } g.errorf("unsupported pointer to type: %s", typ) return "TODO" case *types.Named: n := typ.Obj() if isObjcType(typ) { w := g.wrapMap[n.Name()] return w.ObjcType() } if !isErrorType(typ) && !g.validPkg(n.Pkg()) { g.errorf("type %s is in package %s, which is not bound", n.Name(), n.Pkg().Name()) return "TODO" } switch t := typ.Underlying().(type) { case *types.Interface: if makeIfaceSummary(t).implementable { return "id<" + g.namePrefixOf(n.Pkg()) + n.Name() + ">" } else { return g.namePrefixOf(n.Pkg()) + n.Name() + "*" } case *types.Struct: return g.namePrefixOf(n.Pkg()) + n.Name() } g.errorf("unsupported, named type %s", typ) return "TODO" default: g.errorf("unsupported type: %#+v, %s", typ, typ) return "TODO" } }
// javaType returns a string that can be used as a Java type. func (g *javaGen) javaType(T types.Type) string { if isErrorType(T) { // The error type is usually translated into an exception in // Java, however the type can be exposed in other ways, such // as an exported field. return "String" } switch T := T.(type) { case *types.Basic: switch T.Kind() { case types.Bool, types.UntypedBool: return "boolean" case types.Int: return "long" case types.Int8: return "byte" case types.Int16: return "short" case types.Int32, types.UntypedRune: // types.Rune return "int" case types.Int64, types.UntypedInt: return "long" case types.Uint8: // types.Byte // TODO(crawshaw): Java bytes are signed, so this is // questionable, but vital. return "byte" // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: case types.Float32: return "float" case types.Float64, types.UntypedFloat: return "double" case types.String, types.UntypedString: return "String" default: g.errorf("unsupported basic type: %s", T) return "TODO" } case *types.Slice: elem := g.javaType(T.Elem()) return elem + "[]" case *types.Pointer: if _, ok := T.Elem().(*types.Named); ok { return g.javaType(T.Elem()) } panic(fmt.Sprintf("unsupported pointer to type: %s", T)) case *types.Named: n := T.Obj() if n.Pkg() != g.pkg { nPkgName := "<nilpkg>" if nPkg := n.Pkg(); nPkg != nil { nPkgName = nPkg.Name() } panic(fmt.Sprintf("type %s is in package %s, must be defined in package %s", n.Name(), nPkgName, g.pkg.Name())) } // TODO(crawshaw): more checking here return n.Name() default: g.errorf("unsupported javaType: %#+v, %s\n", T, T) return "TODO" } }
func (w *Walker) writeType(buf *bytes.Buffer, typ types.Type) { switch typ := typ.(type) { case *types.Basic: s := typ.Name() switch typ.Kind() { case types.UnsafePointer: s = "unsafe.Pointer" case types.UntypedBool: s = "ideal-bool" case types.UntypedInt: s = "ideal-int" case types.UntypedRune: // "ideal-char" for compatibility with old tool // TODO(gri) change to "ideal-rune" s = "ideal-char" case types.UntypedFloat: s = "ideal-float" case types.UntypedComplex: s = "ideal-complex" case types.UntypedString: s = "ideal-string" case types.UntypedNil: panic("should never see untyped nil type") default: switch s { case "byte": s = "uint8" case "rune": s = "int32" } } buf.WriteString(s) case *types.Array: fmt.Fprintf(buf, "[%d]", typ.Len()) w.writeType(buf, typ.Elem()) case *types.Slice: buf.WriteString("[]") w.writeType(buf, typ.Elem()) case *types.Struct: buf.WriteString("struct") case *types.Pointer: buf.WriteByte('*') w.writeType(buf, typ.Elem()) case *types.Tuple: panic("should never see a tuple type") case *types.Signature: buf.WriteString("func") w.writeSignature(buf, typ) case *types.Interface: buf.WriteString("interface{") if typ.NumMethods() > 0 { buf.WriteByte(' ') buf.WriteString(strings.Join(sortedMethodNames(typ), ", ")) buf.WriteByte(' ') } buf.WriteString("}") case *types.Map: buf.WriteString("map[") w.writeType(buf, typ.Key()) buf.WriteByte(']') w.writeType(buf, typ.Elem()) case *types.Chan: var s string switch typ.Dir() { case types.SendOnly: s = "chan<- " case types.RecvOnly: s = "<-chan " case types.SendRecv: s = "chan " default: panic("unreachable") } buf.WriteString(s) w.writeType(buf, typ.Elem()) case *types.Named: obj := typ.Obj() pkg := obj.Pkg() if pkg != nil && pkg != w.current { buf.WriteString(pkg.Name()) buf.WriteByte('.') } buf.WriteString(typ.Obj().Name()) default: panic(fmt.Sprintf("unknown type %T", typ)) } }
func (g *objcGen) objcType(typ types.Type) string { if isErrorType(typ) { return "NSError*" } switch typ := typ.(type) { case *types.Basic: switch typ.Kind() { case types.Bool: return "BOOL" case types.Int: return "int" case types.Int8: return "int8_t" case types.Int16: return "int16_t" case types.Int32: return "int32_t" case types.Int64: return "int64_t" case types.Uint8: // byte is an alias of uint8, and the alias is lost. return "byte" case types.Uint16: return "uint16_t" case types.Uint32: return "uint32_t" case types.Uint64: return "uint64_t" case types.Float32: return "float" case types.Float64: return "double" case types.String: return "NSString*" default: g.errorf("unsupported type: %s", typ) return "TODO" } case *types.Slice: elem := g.objcType(typ.Elem()) // Special case: NSData seems to be a better option for byte slice. if elem == "byte" { return "NSData*" } // TODO(hyangah): support other slice types: NSArray or CFArrayRef. // Investigate the performance implication. g.errorf("unsupported type: %s", typ) return "TODO" case *types.Pointer: if _, ok := typ.Elem().(*types.Named); ok { return g.objcType(typ.Elem()) + "*" } g.errorf("unsupported pointer to type: %s", typ) return "TODO" case *types.Named: n := typ.Obj() if n.Pkg() != g.pkg { g.errorf("type %s is in package %s; only types defined in package %s is supported", n.Name(), n.Pkg().Name(), g.pkg.Name()) return "TODO" } switch typ.Underlying().(type) { case *types.Interface: return "id<" + g.namePrefix + n.Name() + ">" case *types.Struct: return g.namePrefix + n.Name() } g.errorf("unsupported, named type %s", typ) return "TODO" default: g.errorf("unsupported type: %#+v, %s", typ, typ) return "TODO" } }
// seqType returns a string that can be used for reading and writing a // type using the seq library. // TODO(hyangah): avoid panic; gobind needs to output the problematic code location. func seqType(t types.Type) string { if isErrorType(t) { return "String" } switch t := t.(type) { case *types.Basic: switch t.Kind() { case types.Bool: return "Bool" case types.Int: return "Int" case types.Int8: return "Int8" case types.Int16: return "Int16" case types.Int32: return "Int32" case types.Int64: return "Int64" case types.Uint8: // Byte. // TODO(crawshaw): questionable, but vital? return "Byte" // TODO(crawshaw): case types.Uint, types.Uint16, types.Uint32, types.Uint64: case types.Float32: return "Float32" case types.Float64: return "Float64" case types.String: return "String" default: // Should be caught earlier in processing. panic(fmt.Sprintf("unsupported basic seqType: %s", t)) } case *types.Named: switch u := t.Underlying().(type) { case *types.Interface: return "Ref" default: panic(fmt.Sprintf("unsupported named seqType: %s / %T", u, u)) } case *types.Slice: switch e := t.Elem().(type) { case *types.Basic: switch e.Kind() { case types.Uint8: // Byte. return "ByteArray" default: panic(fmt.Sprintf("unsupported seqType: %s(%s) / %T(%T)", t, e, t, e)) } default: panic(fmt.Sprintf("unsupported seqType: %s(%s) / %T(%T)", t, e, t, e)) } // TODO: let the types.Array case handled like types.Slice? case *types.Pointer: if _, ok := t.Elem().(*types.Named); ok { return "Ref" } panic(fmt.Sprintf("not supported yet, pointer type: %s / %T", t, t)) default: panic(fmt.Sprintf("unsupported seqType: %s / %T", t, t)) } }
// zero returns a new "zero" value of the specified type. func zero(t types.Type) value { switch t := t.(type) { case *types.Basic: if t.Kind() == types.UntypedNil { panic("untyped nil has no zero value") } if t.Info()&types.IsUntyped != 0 { // TODO(adonovan): make it an invariant that // this is unreachable. Currently some // constants have 'untyped' types when they // should be defaulted by the typechecker. t = ssa.DefaultType(t).(*types.Basic) } switch t.Kind() { case types.Bool: return false case types.Int: return int(0) case types.Int8: return int8(0) case types.Int16: return int16(0) case types.Int32: return int32(0) case types.Int64: return int64(0) case types.Uint: return uint(0) case types.Uint8: return uint8(0) case types.Uint16: return uint16(0) case types.Uint32: return uint32(0) case types.Uint64: return uint64(0) case types.Uintptr: return uintptr(0) case types.Float32: return float32(0) case types.Float64: return float64(0) case types.Complex64: return complex64(0) case types.Complex128: return complex128(0) case types.String: return "" case types.UnsafePointer: return unsafe.Pointer(nil) default: panic(fmt.Sprint("zero for unexpected type:", t)) } case *types.Pointer: return (*value)(nil) case *types.Array: a := make(array, t.Len()) for i := range a { a[i] = zero(t.Elem()) } return a case *types.Named: return zero(t.Underlying()) case *types.Interface: return iface{} // nil type, methodset and value case *types.Slice: return []value(nil) case *types.Struct: s := make(structure, t.NumFields()) for i := range s { s[i] = zero(t.Field(i).Type()) } return s case *types.Tuple: if t.Len() == 1 { return zero(t.At(0).Type()) } s := make(tuple, t.Len()) for i := range s { s[i] = zero(t.At(i).Type()) } return s case *types.Chan: return chan value(nil) case *types.Map: if usesBuiltinMap(t.Key()) { return map[value]value(nil) } return (*hashmap)(nil) case *types.Signature: return (*ssa.Function)(nil) } panic(fmt.Sprint("zero: unexpected ", t)) }
func equalType(x, y types.Type) error { if reflect.TypeOf(x) != reflect.TypeOf(y) { return fmt.Errorf("unequal kinds: %T vs %T", x, y) } switch x := x.(type) { case *types.Interface: y := y.(*types.Interface) // TODO(gri): enable separate emission of Embedded interfaces // and ExplicitMethods then use this logic. // if x.NumEmbeddeds() != y.NumEmbeddeds() { // return fmt.Errorf("unequal number of embedded interfaces: %d vs %d", // x.NumEmbeddeds(), y.NumEmbeddeds()) // } // for i := 0; i < x.NumEmbeddeds(); i++ { // xi := x.Embedded(i) // yi := y.Embedded(i) // if xi.String() != yi.String() { // return fmt.Errorf("mismatched %th embedded interface: %s vs %s", // i, xi, yi) // } // } // if x.NumExplicitMethods() != y.NumExplicitMethods() { // return fmt.Errorf("unequal methods: %d vs %d", // x.NumExplicitMethods(), y.NumExplicitMethods()) // } // for i := 0; i < x.NumExplicitMethods(); i++ { // xm := x.ExplicitMethod(i) // ym := y.ExplicitMethod(i) // if xm.Name() != ym.Name() { // return fmt.Errorf("mismatched %th method: %s vs %s", i, xm, ym) // } // if err := equalType(xm.Type(), ym.Type()); err != nil { // return fmt.Errorf("mismatched %s method: %s", xm.Name(), err) // } // } if x.NumMethods() != y.NumMethods() { return fmt.Errorf("unequal methods: %d vs %d", x.NumMethods(), y.NumMethods()) } for i := 0; i < x.NumMethods(); i++ { xm := x.Method(i) ym := y.Method(i) if xm.Name() != ym.Name() { return fmt.Errorf("mismatched %dth method: %s vs %s", i, xm, ym) } if err := equalType(xm.Type(), ym.Type()); err != nil { return fmt.Errorf("mismatched %s method: %s", xm.Name(), err) } } case *types.Array: y := y.(*types.Array) if x.Len() != y.Len() { return fmt.Errorf("unequal array lengths: %d vs %d", x.Len(), y.Len()) } if err := equalType(x.Elem(), y.Elem()); err != nil { return fmt.Errorf("array elements: %s", err) } case *types.Basic: y := y.(*types.Basic) if x.Kind() != y.Kind() { return fmt.Errorf("unequal basic types: %s vs %s", x, y) } case *types.Chan: y := y.(*types.Chan) if x.Dir() != y.Dir() { return fmt.Errorf("unequal channel directions: %d vs %d", x.Dir(), y.Dir()) } if err := equalType(x.Elem(), y.Elem()); err != nil { return fmt.Errorf("channel elements: %s", err) } case *types.Map: y := y.(*types.Map) if err := equalType(x.Key(), y.Key()); err != nil { return fmt.Errorf("map keys: %s", err) } if err := equalType(x.Elem(), y.Elem()); err != nil { return fmt.Errorf("map values: %s", err) } case *types.Named: y := y.(*types.Named) if x.String() != y.String() { return fmt.Errorf("unequal named types: %s vs %s", x, y) } case *types.Pointer: y := y.(*types.Pointer) if err := equalType(x.Elem(), y.Elem()); err != nil { return fmt.Errorf("pointer elements: %s", err) } case *types.Signature: y := y.(*types.Signature) if err := equalType(x.Params(), y.Params()); err != nil { return fmt.Errorf("parameters: %s", err) } if err := equalType(x.Results(), y.Results()); err != nil { return fmt.Errorf("results: %s", err) } if x.Variadic() != y.Variadic() { return fmt.Errorf("unequal varidicity: %t vs %t", x.Variadic(), y.Variadic()) } if (x.Recv() != nil) != (y.Recv() != nil) { return fmt.Errorf("unequal receivers: %s vs %s", x.Recv(), y.Recv()) } if x.Recv() != nil { // TODO(adonovan): fix: this assertion fires for interface methods. // The type of the receiver of an interface method is a named type // if the Package was loaded from export data, or an unnamed (interface) // type if the Package was produced by type-checking ASTs. // if err := equalType(x.Recv().Type(), y.Recv().Type()); err != nil { // return fmt.Errorf("receiver: %s", err) // } } case *types.Slice: y := y.(*types.Slice) if err := equalType(x.Elem(), y.Elem()); err != nil { return fmt.Errorf("slice elements: %s", err) } case *types.Struct: y := y.(*types.Struct) if x.NumFields() != y.NumFields() { return fmt.Errorf("unequal struct fields: %d vs %d", x.NumFields(), y.NumFields()) } for i := 0; i < x.NumFields(); i++ { xf := x.Field(i) yf := y.Field(i) if xf.Name() != yf.Name() { return fmt.Errorf("mismatched fields: %s vs %s", xf, yf) } if err := equalType(xf.Type(), yf.Type()); err != nil { return fmt.Errorf("struct field %s: %s", xf.Name(), err) } if x.Tag(i) != y.Tag(i) { return fmt.Errorf("struct field %s has unequal tags: %q vs %q", xf.Name(), x.Tag(i), y.Tag(i)) } } case *types.Tuple: y := y.(*types.Tuple) if x.Len() != y.Len() { return fmt.Errorf("unequal tuple lengths: %d vs %d", x.Len(), y.Len()) } for i := 0; i < x.Len(); i++ { if err := equalType(x.At(i).Type(), y.At(i).Type()); err != nil { return fmt.Errorf("tuple element %d: %s", i, err) } } } return nil }
// hashFor computes the hash of t. func (h Hasher) hashFor(t types.Type) uint32 { // See Identical for rationale. switch t := t.(type) { case *types.Basic: return uint32(t.Kind()) case *types.Array: return 9043 + 2*uint32(t.Len()) + 3*h.Hash(t.Elem()) case *types.Slice: return 9049 + 2*h.Hash(t.Elem()) case *types.Struct: var hash uint32 = 9059 for i, n := 0, t.NumFields(); i < n; i++ { f := t.Field(i) if f.Anonymous() { hash += 8861 } hash += hashString(t.Tag(i)) hash += hashString(f.Name()) // (ignore f.Pkg) hash += h.Hash(f.Type()) } return hash case *types.Pointer: return 9067 + 2*h.Hash(t.Elem()) case *types.Signature: var hash uint32 = 9091 if t.Variadic() { hash *= 8863 } return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results()) case *types.Interface: var hash uint32 = 9103 for i, n := 0, t.NumMethods(); i < n; i++ { // See go/types.identicalMethods for rationale. // Method order is not significant. // Ignore m.Pkg(). m := t.Method(i) hash += 3*hashString(m.Name()) + 5*h.Hash(m.Type()) } return hash case *types.Map: return 9109 + 2*h.Hash(t.Key()) + 3*h.Hash(t.Elem()) case *types.Chan: return 9127 + 2*uint32(t.Dir()) + 3*h.Hash(t.Elem()) case *types.Named: // Not safe with a copying GC; objects may move. return uint32(reflect.ValueOf(t.Obj()).Pointer()) case *types.Tuple: return h.hashTuple(t) } panic(t) }
func reflectKind(t types.Type) reflect.Kind { switch t := t.(type) { case *types.Named: return reflectKind(t.Underlying()) case *types.Basic: switch t.Kind() { case types.Bool: return reflect.Bool case types.Int: return reflect.Int case types.Int8: return reflect.Int8 case types.Int16: return reflect.Int16 case types.Int32: return reflect.Int32 case types.Int64: return reflect.Int64 case types.Uint: return reflect.Uint case types.Uint8: return reflect.Uint8 case types.Uint16: return reflect.Uint16 case types.Uint32: return reflect.Uint32 case types.Uint64: return reflect.Uint64 case types.Uintptr: return reflect.Uintptr case types.Float32: return reflect.Float32 case types.Float64: return reflect.Float64 case types.Complex64: return reflect.Complex64 case types.Complex128: return reflect.Complex128 case types.String: return reflect.String case types.UnsafePointer: return reflect.UnsafePointer } case *types.Array: return reflect.Array case *types.Chan: return reflect.Chan case *types.Signature: return reflect.Func case *types.Interface: return reflect.Interface case *types.Map: return reflect.Map case *types.Pointer: return reflect.Ptr case *types.Slice: return reflect.Slice case *types.Struct: return reflect.Struct } panic(fmt.Sprint("unexpected type: ", t)) }