// 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 sizeof(t types.Type) uint { switch t := t.(type) { case *types.Tuple: // TODO: usage of reflect most likely wrong! // uint(reflect.TypeOf(t).Elem().Size()) panic("Tuples are unsupported") case *types.Basic: return sizeBasic(t.Kind()) case *types.Pointer: return sizePtr() case *types.Slice: return sizeSlice(t) case *types.Array: return sizeArray(t) case *types.Named: if sse2, ok := sse2Info(t); ok { return sse2.size } else if info, ok := simdInfo(t); ok { return info.size } else { panic(ice(fmt.Sprintf("unknown named type \"%v\"", t.String()))) } } panic(ice(fmt.Sprintf("unknown type: %v", t))) }
func signed(t types.Type) bool { switch t := t.(type) { case *types.Basic: return signedBasic(t.Kind()) } panic(ice(fmt.Sprintf("unknown type: %v", t))) }
func isInt(t types.Type) bool { if t, ok := t.(*types.Basic); ok { switch t.Kind() { case types.Int, types.Int8, types.Int16, types.Int32, types.Int64: return true } } return false }
func cgoTypeName(typ types.Type) string { switch typ := typ.(type) { case *types.Basic: kind := typ.Kind() o, ok := typedescr[kind] if ok { return o.cgotype } } return typ.String() }
// 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" } }
// seqType returns a string that can be used for reading and writing a // type using the seq library. func seqType(t types.Type) string { if isErrorType(t) { return "UTF16" } switch t := t.(type) { case *types.Basic: switch t.Kind() { 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: // 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 "UTF16" default: // Should be caught earlier in processing. panic(fmt.Sprintf("unsupported return type: %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)) } default: panic(fmt.Sprintf("unsupported seqType: %s / %T", t, t)) } }
// 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, types.Float32, types.Float64: return "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" } }
func reflectType(t types.Type) reflect.Type { switch t := t.(type) { case *types.Tuple: // TODO case *types.Basic: return reflectBasic(t.Kind()) case *types.Pointer: return reflect.PtrTo(reflectType(t.Elem())) case *types.Slice: return reflect.SliceOf(reflectType(t.Elem())) case *types.Array: return reflect.ArrayOf(int(t.Len()), reflectType(t.Elem())) case *types.Named: if st, ok := simdInfo(t); ok { return st.t } if sse2, ok := sse2Info(t); ok { return sse2.t } } ice(fmt.Sprintf("error unknown type:\"%v\"", t)) panic("") }
func (tm *llvmTypeMap) getBackendType(t types.Type) backendType { switch t := t.(type) { case *types.Named: return tm.getBackendType(t.Underlying()) case *types.Basic: switch t.Kind() { case types.Bool, types.Uint8: return &intBType{1, false} case types.Int8: return &intBType{1, true} case types.Uint16: return &intBType{2, false} case types.Int16: return &intBType{2, true} case types.Uint32: return &intBType{4, false} case types.Int32: return &intBType{4, true} case types.Uint64: return &intBType{8, false} case types.Int64: return &intBType{8, true} case types.Uint, types.Uintptr: return &intBType{tm.target.PointerSize(), false} case types.Int: return &intBType{tm.target.PointerSize(), true} case types.Float32: return &floatBType{false} case types.Float64: return &floatBType{true} case types.UnsafePointer: return &ptrBType{} case types.Complex64: f32 := &floatBType{false} return &structBType{[]backendType{f32, f32}} case types.Complex128: f64 := &floatBType{true} return &structBType{[]backendType{f64, f64}} case types.String: return &structBType{[]backendType{&ptrBType{}, &intBType{tm.target.PointerSize(), false}}} } case *types.Struct: var fields []backendType for i := 0; i != t.NumFields(); i++ { f := t.Field(i) fields = append(fields, tm.getBackendType(f.Type())) } return &structBType{fields} case *types.Pointer, *types.Signature, *types.Map, *types.Chan: return &ptrBType{} case *types.Interface: i8ptr := &ptrBType{} return &structBType{[]backendType{i8ptr, i8ptr}} case *types.Slice: return tm.sliceBackendType() case *types.Array: return &arrayBType{uint64(t.Len()), tm.getBackendType(t.Elem())} } panic("unhandled type: " + t.String()) }
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 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" } }
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)) }
// 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. // But (see issue 6259) that's not easy to verify, so instead we see // if its method set contains a Format function. We could do better, // even now, but we don't need to be 100% accurate. Wait for 6259 to // be fixed instead. TODO. if f.hasMethod(typ, "Format") { 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) || 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: // If the static type of the argument is empty interface, there's little we can do. // Example: // func f(x interface{}) { fmt.Printf("%s", x) } // Whether x is valid for %s depends on the type of the argument to f. One day // we will be able to do better. For now, we assume that empty interface is OK // but non-empty interfaces, with Stringer and Error handled above, are errors. return typ.NumMethods() == 0 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 isBasicKind(t types.Type, basickind types.BasicKind) bool { if t, ok := t.(*types.Basic); ok { return t.Kind() == basickind } return false }
// 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 "UTF16" } switch t := t.(type) { case *types.Basic: switch t.Kind() { 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 "UTF16" 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)) } }
// 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) }
// 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)) }