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) } }
// lockPath returns a typePath describing the location of a lock value // contained in typ. If there is no contained lock, it returns nil. func lockPath(tpkg *types.Package, typ types.Type) typePath { if typ == nil { return nil } // We're only interested in the case in which the underlying // type is a struct. (Interfaces and pointers are safe to copy.) styp, ok := typ.Underlying().(*types.Struct) if !ok { return nil } // We're looking for cases in which a reference to this type // can be locked, but a value cannot. This differentiates // embedded interfaces from embedded values. if plock := types.NewMethodSet(types.NewPointer(typ)).Lookup(tpkg, "Lock"); plock != nil { if lock := types.NewMethodSet(typ).Lookup(tpkg, "Lock"); lock == nil { return []types.Type{typ} } } nfields := styp.NumFields() for i := 0; i < nfields; i++ { ftyp := styp.Field(i).Type() subpath := lockPath(tpkg, ftyp) if subpath != nil { return append(subpath, typ) } } return nil }
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" } }
func (f Field) UnderlyingTarget() fieldser { var t types.Type switch v := f.v.Type().(type) { case elemer: t = v.Elem() case *types.Named: t = v } if _, ok := t.(underlyinger); !ok { return nil } u := t.(underlyinger).Underlying() switch t := u.(type) { case *types.Struct: return fields{ g: f.gen, target: t, } case *types.Pointer: return fields{ g: f.gen, target: t.Elem().(*types.Named).Underlying().(*types.Struct), } } return nil }
func needWrapType(typ types.Type) bool { switch typ := typ.(type) { case *types.Basic: return false case *types.Struct: return true case *types.Named: switch ut := typ.Underlying().(type) { case *types.Basic: return false default: return needWrapType(ut) } case *types.Array: return true case *types.Map: return true case *types.Slice: return true case *types.Interface: wrap := true if typ.Underlying() == universe.syms["error"].GoType().Underlying() { wrap = false } return wrap case *types.Signature: return true case *types.Pointer: return needWrapType(typ.Elem()) } return false }
func (g *goGen) genWrite(valName, seqName string, T types.Type) { if isErrorType(T) { g.Printf("if %s == nil {\n", valName) g.Printf(" %s.WriteString(\"\");\n", seqName) g.Printf("} else {\n") g.Printf(" %s.WriteString(%s.Error());\n", seqName, valName) g.Printf("}\n") return } switch T := T.(type) { case *types.Pointer: // TODO(crawshaw): test *int // TODO(crawshaw): test **Generator switch T := T.Elem().(type) { case *types.Named: obj := T.Obj() if obj.Pkg() != g.pkg { g.errorf("type %s not defined in package %s", T, g.pkg) return } g.Printf("%s.WriteGoRef(%s)\n", seqName, valName) default: g.errorf("unsupported type %s", T) } case *types.Named: switch u := T.Underlying().(type) { case *types.Interface, *types.Pointer: g.Printf("%s.WriteGoRef(%s)\n", seqName, valName) default: g.errorf("unsupported, direct named type %s: %s", T, u) } default: g.Printf("%s.Write%s(%s);\n", seqName, seqType(T), valName) } }
func (f *File) validVarDeclType(typ types.Type) *Error { if e := f.validResultType(typ); e != nil { switch typ.(type) { default: return e case *types.Interface: return f.validVarDeclType(typ.Underlying()) case *types.Named: named, ok := typ.(*types.Named) if !ok { panic("ERROR can't cast to named type") } tname := named.Obj() /*i := Int(0) simdInt := reflect.TypeOf(i) var i4 Int4 simdInt4 := reflect.TypeOf(i4) switch tname.Name() { default:*/ return &Error{errors.New(fmt.Sprintf("invalid type (%v)", tname.Name())), 0} /*case simdInt.Name(): return nil case simdInt4.Name(): return nil }*/ } } return nil }
// MethodSet returns the method set of type T. It is thread-safe. // // If cache is nil, this function is equivalent to types.NewMethodSet(T). // Utility functions can thus expose an optional *MethodSetCache // parameter to clients that care about performance. // func (cache *MethodSetCache) MethodSet(T types.Type) *types.MethodSet { if cache == nil { return types.NewMethodSet(T) } cache.mu.Lock() defer cache.mu.Unlock() switch T := T.(type) { case *types.Named: return cache.lookupNamed(T).value case *types.Pointer: if N, ok := T.Elem().(*types.Named); ok { return cache.lookupNamed(N).pointer } } // all other types // (The map uses pointer equivalence, not type identity.) mset := cache.others[T] if mset == nil { mset = types.NewMethodSet(T) if cache.others == nil { cache.others = make(map[types.Type]*types.MethodSet) } cache.others[T] = mset } return mset }
func (sym *symtab) addInterfaceType(pkg *types.Package, obj types.Object, t types.Type, kind symkind, id, n string) { fn := sym.typename(t, nil) typ := t.Underlying().(*types.Interface) kind |= skInterface // special handling of 'error' if isErrorType(typ) { return } sym.syms[fn] = &symbol{ gopkg: pkg, goobj: obj, gotyp: t, kind: kind, id: id, goname: n, cgoname: "cgo_type_" + id, cpyname: "cpy_type_" + id, pyfmt: "O&", pybuf: "P", pysig: "object", c2py: "cgopy_cnv_c2py_" + id, py2c: "cgopy_cnv_py2c_" + id, pychk: fmt.Sprintf("cpy_func_%[1]s_check(%%s)", id), } }
func (x array) hash(t types.Type) int { h := 0 tElt := t.Underlying().(*types.Array).Elem() for _, xi := range x { h += hash(tElt, xi) } return h }
func encodeType(t types.Type) Type { t = t.Underlying() switch t.(type) { case *types.Basic: b := t.(*types.Basic) untyped := (b.Info() & types.IsUntyped) != 0 return NewBasic(basicKindString(b), untyped) case *types.Pointer: p := t.(*types.Pointer) pt := encodeType(p.Elem()) return NewPointer(pt) case *types.Array: a := t.(*types.Array) at := encodeType(a.Elem()) return NewArray(at, a.Len()) case *types.Slice: s := t.(*types.Slice) st := encodeType(s.Elem()) return NewSlice(st) case *types.Signature: sig := t.(*types.Signature) v := sig.Recv() var vt *Type if v != nil { t := encodeType(v.Type()) vt = &t } return NewSignature( sig.Variadic(), vt, tupleToSlice(sig.Params()), tupleToSlice(sig.Results())) case *types.Named: n := t.(*types.Named) return NewNamed( n.Obj().Pkg().Name(), n.Obj().Name(), n.Underlying()) case *types.Interface: i := t.(*types.Interface) if i.Empty() { return NewInterface() } else { return NewUnsupported("Interfaces") } case *types.Tuple: return NewUnsupported("Tuples") case *types.Map: return NewUnsupported("Maps") case *types.Chan: return NewUnsupported("Channels") case *types.Struct: return NewUnsupported("Structs") default: return NewUnsupported(t.String()) } }
// indirect(typ) assumes that typ is a pointer type, // or named alias thereof, and returns its base type. // Panic ensures if it is not a pointer. // func indirectType(ptr types.Type) types.Type { if v, ok := underlyingType(ptr).(*types.Pointer); ok { return v.Base } // When debugging it is convenient to comment out this line // and let it continue to print the (illegal) SSA form. panic("indirect() of non-pointer type: " + ptr.String()) return nil }
func (x array) eq(t types.Type, _y interface{}) bool { y := _y.(array) tElt := t.Underlying().(*types.Array).Elem() for i, xi := range x { if !equals(tElt, xi, y[i]) { return false } } return true }
func (x structure) hash(t types.Type) int { tStruct := t.Underlying().(*types.Struct) h := 0 for i, n := 0, tStruct.NumFields(); i < n; i++ { if f := tStruct.Field(i); !f.Anonymous() { h += hash(f.Type(), x[i]) } } return h }
func makeImplementsType(T types.Type, fset *token.FileSet) serial.ImplementsType { var pos token.Pos if nt, ok := deref(T).(*types.Named); ok { // implementsResult.t may be non-named pos = nt.Obj().Pos() } return serial.ImplementsType{ Name: T.String(), Pos: fset.Position(pos).String(), Kind: typeKind(T), } }
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) } }
// usesBuiltinMap returns true if the built-in hash function and // equivalence relation for type t are consistent with those of the // interpreter's representation of type t. Such types are: all basic // types (bool, numbers, string), pointers and channels. // // usesBuiltinMap returns false for types that require a custom map // implementation: interfaces, arrays and structs. // // Panic ensues if t is an invalid map key type: function, map or slice. func usesBuiltinMap(t types.Type) bool { switch t := t.(type) { case *types.Basic, *types.Chan, *types.Pointer: return true case *types.Named: return usesBuiltinMap(t.Underlying()) case *types.Interface, *types.Array, *types.Struct: return false } panic(fmt.Sprintf("invalid map key type: %T", t)) }
// CanHaveDynamicTypes reports whether the type T can "hold" dynamic types, // i.e. is an interface (incl. reflect.Type) or a reflect.Value. // func CanHaveDynamicTypes(T types.Type) bool { switch T := T.(type) { case *types.Named: if obj := T.Obj(); obj.Name() == "Value" && obj.Pkg().Path() == "reflect" { return true // reflect.Value } return CanHaveDynamicTypes(T.Underlying()) case *types.Interface: return true } return false }
func (x structure) eq(t types.Type, _y interface{}) bool { y := _y.(structure) tStruct := t.Underlying().(*types.Struct) for i, n := 0, tStruct.NumFields(); i < n; i++ { if f := tStruct.Field(i); !f.Anonymous() { if !equals(f.Type(), x[i], y[i]) { return false } } } return true }
// 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" } }
func newVar(p *Package, typ types.Type, objname, name, doc string) *Var { sym := p.syms.symtype(typ) if sym == nil { panic(fmt.Errorf("could not find symbol for type [%s]!", typ.String())) } return &Var{ pkg: p, sym: sym, id: p.Name() + "_" + objname, doc: doc, name: name, } }
// CanPoint reports whether the type T is pointerlike, // for the purposes of this analysis. func CanPoint(T types.Type) bool { switch T := T.(type) { case *types.Named: if obj := T.Obj(); obj.Name() == "Value" && obj.Pkg().Path() == "reflect" { return true // treat reflect.Value like interface{} } return CanPoint(T.Underlying()) case *types.Pointer, *types.Interface, *types.Map, *types.Chan, *types.Signature, *types.Slice: return true } return false // array struct tuple builtin basic }
// getTypeStruct will take a type and the package scope, and return the // (innermost) struct if the type is considered a RR type (currently defined as // those structs beginning with a RR_Header, could be redefined as implementing // the RR interface). The bool return value indicates if embedded structs were // resolved. func getTypeStruct(t types.Type, scope *types.Scope) (*types.Struct, bool) { st, ok := t.Underlying().(*types.Struct) if !ok { return nil, false } if st.Field(0).Type() == scope.Lookup("RR_Header").Type() { return st, false } if st.Field(0).Anonymous() { st, _ := getTypeStruct(st.Field(0).Type(), scope) return st, true } return nil, false }
func isExported(t types.Type) bool { if isErrorType(t) { return true } switch t := t.(type) { case *types.Basic: return true case *types.Named: return t.Obj().Exported() case *types.Pointer: return isExported(t.Elem()) default: return true } }
func describeType(qpos *queryPos, path []ast.Node) (*describeTypeResult, error) { var description string var t types.Type switch n := path[0].(type) { case *ast.Ident: t = qpos.info.TypeOf(n) switch t := t.(type) { case *types.Basic: description = "reference to built-in " case *types.Named: isDef := t.Obj().Pos() == n.Pos() // see caveats at isDef above if isDef { description = "definition of " } else if _, ok := qpos.info.ObjectOf(n).(*types.Alias); ok { description = "alias of " } else { description = "reference to " } } case ast.Expr: t = qpos.info.TypeOf(n) default: // Unreachable? return nil, fmt.Errorf("unexpected AST for type: %T", n) } description = description + "type " + qpos.typeString(t) // Show sizes for structs and named types (it's fairly obvious for others). switch t.(type) { case *types.Named, *types.Struct: szs := types.StdSizes{WordSize: 8, MaxAlign: 8} // assume amd64 description = fmt.Sprintf("%s (size %d, align %d)", description, szs.Sizeof(t), szs.Alignof(t)) } return &describeTypeResult{ qpos: qpos, node: path[0], description: description, typ: t, methods: accessibleMethods(t, qpos.info.Pkg), fields: accessibleFields(t, qpos.info.Pkg), }, nil }
func (c *funcContext) translateImplicitConversion(expr ast.Expr, desiredType types.Type) *expression { if desiredType == nil { return c.translateExpr(expr) } exprType := c.p.TypeOf(expr) if types.Identical(exprType, desiredType) { return c.translateExpr(expr) } basicExprType, isBasicExpr := exprType.Underlying().(*types.Basic) if isBasicExpr && basicExprType.Kind() == types.UntypedNil { return c.formatExpr("%e", c.zeroValue(desiredType)) } switch desiredType.Underlying().(type) { case *types.Slice: return c.formatExpr("$subslice(new %1s(%2e.$array), %2e.$offset, %2e.$offset + %2e.$length)", c.typeName(desiredType), expr) case *types.Interface: if typesutil.IsJsObject(exprType) { // wrap JS object into js.Object struct when converting to interface return c.formatExpr("new $jsObjectPtr(%e)", expr) } if isWrapped(exprType) { return c.formatExpr("new %s(%e)", c.typeName(exprType), expr) } if _, isStruct := exprType.Underlying().(*types.Struct); isStruct { return c.formatExpr("new %1e.constructor.elem(%1e)", expr) } } return c.translateExpr(expr) }
func (c *funcContext) zeroValue(ty types.Type) ast.Expr { switch t := ty.Underlying().(type) { case *types.Basic: switch { case isBoolean(t): return c.newConst(ty, constant.MakeBool(false)) case isNumeric(t): return c.newConst(ty, constant.MakeInt64(0)) case isString(t): return c.newConst(ty, constant.MakeString("")) case t.Kind() == types.UnsafePointer: // fall through to "nil" case t.Kind() == types.UntypedNil: panic("Zero value for untyped nil.") default: panic(fmt.Sprintf("Unhandled basic type: %v\n", t)) } case *types.Array, *types.Struct: return c.setType(&ast.CompositeLit{}, ty) case *types.Chan, *types.Interface, *types.Map, *types.Signature, *types.Slice, *types.Pointer: // fall through to "nil" default: panic(fmt.Sprintf("Unhandled type: %T\n", t)) } id := c.newIdent("nil", ty) c.p.Uses[id] = nilObj return id }
// eqnil returns the comparison x == y using the equivalence relation // appropriate for type t. // If t is a reference type, at most one of x or y may be a nil value // of that type. // func eqnil(t types.Type, x, y value) bool { switch t.Underlying().(type) { case *types.Map, *types.Signature, *types.Slice: // Since these types don't support comparison, // one of the operands must be a literal nil. switch x := x.(type) { case *hashmap: return (x != nil) == (y.(*hashmap) != nil) case map[value]value: return (x != nil) == (y.(map[value]value) != nil) case *ssa.Function: switch y := y.(type) { case *ssa.Function: return (x != nil) == (y != nil) case *closure: return true } case *closure: return (x != nil) == (y.(*ssa.Function) != nil) case []value: return (x != nil) == (y.([]value) != nil) } panic(fmt.Sprintf("eqnil(%s): illegal dynamic type: %T", t, x)) } return equals(t, x, y) }
func (s *gcSizes) Alignof(T types.Type) int64 { // NOTE: On amd64, complex64 is 8 byte aligned, // even though float32 is only 4 byte aligned. // For arrays and structs, alignment is defined in terms // of alignment of the elements and fields, respectively. switch t := T.Underlying().(type) { case *types.Array: // spec: "For a variable x of array type: unsafe.Alignof(x) // is the same as unsafe.Alignof(x[0]), but at least 1." return s.Alignof(t.Elem()) case *types.Struct: // spec: "For a variable x of struct type: unsafe.Alignof(x) // is the largest of the values unsafe.Alignof(x.f) for each // field f of x, but at least 1." max := int64(1) for i, nf := 0, t.NumFields(); i < nf; i++ { if a := s.Alignof(t.Field(i).Type()); a > max { max = a } } return max } a := s.Sizeof(T) // may be 0 // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1." if a < 1 { return 1 } if a > s.MaxAlign { return s.MaxAlign } return a }