// 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 }
// 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 (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 dump(path string, typ types.Type, st reflect.StructTag) IObj { named, _ := typ.(*types.Named) if named != nil { typ = typ.Underlying() } if strings.Split(st.Get("json"), ",")[0] == "" { if _, ok := typ.(*types.Struct); !ok { if _, ok := typ.(*types.Pointer); !ok { return nil } } } switch u := typ.(type) { case *types.Struct: return Struct(path, st, u, named) case *types.Map: return Map(path, st, u, named) case *types.Slice: return Slice(path, st, u) case *types.Pointer: return Pointer(path, st, u) case *types.Basic: return Basic(path, st, u, named) default: panic("unsupported") } }
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 (fr *frame) makeInterface(llv llvm.Value, vty types.Type, iface types.Type) *govalue { if _, ok := vty.Underlying().(*types.Pointer); !ok { ptr := fr.createTypeMalloc(vty) fr.builder.CreateStore(llv, ptr) llv = ptr } return fr.makeInterfaceFromPointer(llv, vty, iface) }
// Reads the value from the given interface type, assuming that the // interface holds a value of the correct type. func (fr *frame) getInterfaceValue(v *govalue, ty types.Type) *govalue { val := fr.builder.CreateExtractValue(v.value, 1, "") if _, ok := ty.Underlying().(*types.Pointer); !ok { typedval := fr.builder.CreateBitCast(val, llvm.PointerType(fr.types.ToLLVM(ty), 0), "") val = fr.builder.CreateLoad(typedval, "") } return newValue(val, ty) }
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 catchReferencedTypes(et types.Type) { id := LogTypeUse(et) _, seen := catchReferencedTypesSeen[id] if seen { return } catchReferencedTypesSeen[id] = true // check that we have all the required methods? /* for t := 1; t < NextTypeID; t++ { // make sure we do this in a consistent order for _, k := range TypesEncountered.Keys() { if TypesEncountered.At(k).(int) == t { switch k.(type) { case *types.Interface: if types.Implements(et,k.(*types.Interface)) { // TODO call missing method? } } } } } */ //LogTypeUse(types.NewPointer(et)) switch et.(type) { case *types.Named: catchReferencedTypes(et.Underlying()) for m := 0; m < et.(*types.Named).NumMethods(); m++ { catchReferencedTypes(et.(*types.Named).Method(m).Type()) } case *types.Array: catchReferencedTypes(et.(*types.Array).Elem()) //catchReferencedTypes(types.NewSlice(et.(*types.Array).Elem())) case *types.Pointer: catchReferencedTypes(et.(*types.Pointer).Elem()) case *types.Slice: catchReferencedTypes(et.(*types.Slice).Elem()) case *types.Struct: for f := 0; f < et.(*types.Struct).NumFields(); f++ { if et.(*types.Struct).Field(f).IsField() { catchReferencedTypes(et.(*types.Struct).Field(f).Type()) } } case *types.Map: catchReferencedTypes(et.(*types.Map).Key()) catchReferencedTypes(et.(*types.Map).Elem()) case *types.Signature: for i := 0; i < et.(*types.Signature).Params().Len(); i++ { catchReferencedTypes(et.(*types.Signature).Params().At(i).Type()) } for o := 0; o < et.(*types.Signature).Results().Len(); o++ { catchReferencedTypes(et.(*types.Signature).Results().At(o).Type()) } case *types.Chan: catchReferencedTypes(et.(*types.Chan).Elem()) } }
func (fr *frame) makeInterfaceFromPointer(vptr llvm.Value, vty types.Type, iface types.Type) *govalue { i8ptr := llvm.PointerType(llvm.Int8Type(), 0) llv := fr.builder.CreateBitCast(vptr, i8ptr, "") value := llvm.Undef(fr.types.ToLLVM(iface)) itab := fr.types.getItabPointer(vty, iface.Underlying().(*types.Interface)) value = fr.builder.CreateInsertValue(value, itab, 0, "") value = fr.builder.CreateInsertValue(value, llv, 1, "") return newValue(value, iface) }
// If cond is true, reads the value from the given interface type, otherwise // returns a nil value. func (fr *frame) getInterfaceValueOrNull(cond llvm.Value, v *govalue, ty types.Type) *govalue { val := fr.builder.CreateExtractValue(v.value, 1, "") if _, ok := ty.Underlying().(*types.Pointer); ok { val = fr.builder.CreateSelect(cond, val, llvm.ConstNull(val.Type()), "") } else { val = fr.loadOrNull(cond, val, ty).value } return newValue(val, ty) }
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 }
// 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)) }
// TypeChainString returns the full type chain as a string. func TypeChainString(t types.Type) string { out := fmt.Sprintf("%s", t) for { if t == t.Underlying() { break } else { t = t.Underlying() } out += fmt.Sprintf(" -> %s", t) } return out }
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 }
func (fr *frame) interfaceTypeAssert(val *govalue, ty types.Type) *govalue { if _, ok := ty.Underlying().(*types.Interface); ok { return fr.changeInterface(val, ty, true) } else { valtytd := fr.types.ToRuntime(val.Type()) valtd := fr.getInterfaceTypeDescriptor(val) tytd := fr.types.ToRuntime(ty) fr.runtime.checkInterfaceType.call(fr, valtd, tytd, valtytd) return fr.getInterfaceValue(val, ty) } }
// 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 }
// 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 }
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, exact.MakeBool(false)) case isNumeric(t): return c.newConst(ty, exact.MakeInt64(0)) case isString(t): return c.newConst(ty, exact.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 }
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 (c *funcContext) zeroValue(ty types.Type) string { if typesutil.IsJsObject(ty) { return "null" } switch t := ty.Underlying().(type) { case *types.Basic: switch { case is64Bit(t) || isComplex(t): return fmt.Sprintf("new %s(0, 0)", c.typeName(ty)) case isBoolean(t): return "false" case isNumeric(t), t.Kind() == types.UnsafePointer: return "0" case isString(t): return `""` case t.Kind() == types.UntypedNil: panic("Zero value for untyped nil.") default: panic("Unhandled type") } case *types.Array: return fmt.Sprintf("%s.zero()", c.typeName(ty)) case *types.Signature: return "$throwNilPointerError" case *types.Slice: return fmt.Sprintf("%s.nil", c.typeName(ty)) case *types.Struct: return fmt.Sprintf("new %s.ptr()", c.typeName(ty)) case *types.Map: return "false" case *types.Interface: return "$ifaceNil" } return fmt.Sprintf("%s.nil", c.typeName(ty)) }
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 }
func (g *javaGen) genRead(resName, seqName string, T types.Type) { switch T := T.(type) { case *types.Pointer: // TODO(crawshaw): test *int // TODO(crawshaw): test **Generator switch T := T.Elem().(type) { case *types.Named: o := T.Obj() if o.Pkg() != g.pkg { g.errorf("type %s not defined in package %s", T, g.pkg) return } g.Printf("%s = new %s(%s.readRef());\n", resName, o.Name(), seqName) default: g.errorf("unsupported type %s", T) } case *types.Named: switch T.Underlying().(type) { case *types.Interface, *types.Pointer: o := T.Obj() if o.Pkg() != g.pkg { g.errorf("type %s not defined in package %s", T, g.pkg) return } g.Printf("%s = new %s.Proxy(%s.readRef());\n", resName, o.Name(), seqName) default: g.errorf("unsupported, direct named type %s", T) } default: g.Printf("%s = %s.read%s();\n", resName, seqName, seqType(T)) } }
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) }
// 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) }
// zeroValue emits to f code to produce a zero value of type t, // and returns it. // func zeroValue(f *Function, t types.Type) Value { switch t.Underlying().(type) { case *types.Struct, *types.Array: return emitLoad(f, f.addLocal(t, token.NoPos)) default: return zeroConst(t) } }
func (sym *symtab) addMethod(pkg *types.Package, obj types.Object, t types.Type, kind symkind, id, n string) { fn := types.ObjectString(obj, nil) kind |= skFunc sym.syms[fn] = &symbol{ gopkg: pkg, goobj: obj, gotyp: t, kind: kind, id: id, goname: n, cgoname: "cgo_func_" + id, cpyname: "cpy_func_" + id, } sig := t.Underlying().(*types.Signature) sym.processTuple(sig.Results()) sym.processTuple(sig.Params()) }
func (c *funcContext) translateAssign(lhs ast.Expr, rhs string, typ types.Type, define bool) string { lhs = astutil.RemoveParens(lhs) if isBlank(lhs) { panic("translateAssign with blank lhs") } isReflectValue := false if named, ok := typ.(*types.Named); ok && named.Obj().Pkg() != nil && named.Obj().Pkg().Path() == "reflect" && named.Obj().Name() == "Value" { isReflectValue = true } if !isReflectValue { // this is a performance hack, but it is safe since reflect.Value has no exported fields and the reflect package does not violate this assumption switch typ.Underlying().(type) { case *types.Array, *types.Struct: if define { return fmt.Sprintf("%s = $clone(%s, %s);", c.translateExpr(lhs), rhs, c.typeName(typ)) } return fmt.Sprintf("$copy(%s, %s, %s);", c.translateExpr(lhs), rhs, c.typeName(typ)) } } switch l := lhs.(type) { case *ast.Ident: o := c.p.Defs[l] if o == nil { o = c.p.Uses[l] } return fmt.Sprintf("%s = %s;", c.objectName(o), rhs) case *ast.SelectorExpr: sel, ok := c.p.Selections[l] if !ok { // qualified identifier return fmt.Sprintf("%s = %s;", c.objectName(c.p.Uses[l.Sel]), rhs) } fields, jsTag := c.translateSelection(sel, l.Pos()) if jsTag != "" { return fmt.Sprintf("%s.%s.%s = %s;", c.translateExpr(l.X), strings.Join(fields, "."), jsTag, c.externalize(rhs, sel.Type())) } return fmt.Sprintf("%s.%s = %s;", c.translateExpr(l.X), strings.Join(fields, "."), rhs) case *ast.StarExpr: return fmt.Sprintf("%s.$set(%s);", c.translateExpr(l.X), rhs) case *ast.IndexExpr: switch t := c.p.Types[l.X].Type.Underlying().(type) { case *types.Array, *types.Pointer: pattern := rangeCheck("%1e[%2f] = %3s", c.p.Types[l.Index].Value != nil, true) if _, ok := t.(*types.Pointer); ok { // check pointer for nix (attribute getter causes a panic) pattern = `%1e.nilCheck, ` + pattern } return c.formatExpr(pattern, l.X, l.Index, rhs).String() + ";" case *types.Slice: return c.formatExpr(rangeCheck("%1e.$array[%1e.$offset + %2f] = %3s", c.p.Types[l.Index].Value != nil, false), l.X, l.Index, rhs).String() + ";" default: panic(fmt.Sprintf("Unhandled lhs type: %T\n", t)) } default: panic(fmt.Sprintf("Unhandled lhs type: %T\n", l)) } }
// IntuitiveMethodSet returns the intuitive method set of a type, T. // // The result contains MethodSet(T) and additionally, if T is a // concrete type, methods belonging to *T if there is no identically // named method on T itself. This corresponds to user intuition about // method sets; this function is intended only for user interfaces. // // The order of the result is as for types.MethodSet(T). // func IntuitiveMethodSet(T types.Type, msets *MethodSetCache) []*types.Selection { var result []*types.Selection mset := msets.MethodSet(T) if _, ok := T.Underlying().(*types.Interface); ok { for i, n := 0, mset.Len(); i < n; i++ { result = append(result, mset.At(i)) } } else { pmset := msets.MethodSet(types.NewPointer(T)) for i, n := 0, pmset.Len(); i < n; i++ { meth := pmset.At(i) if m := mset.Lookup(meth.Obj().Pkg(), meth.Obj().Name()); m != nil { meth = m } result = append(result, meth) } } return result }