github.com/gopherjs/gopherjs@v1.19.0-beta1.0.20240506212314-27071a8796e4/compiler/typesutil/typesutil.go (about) 1 package typesutil 2 3 import ( 4 "fmt" 5 "go/types" 6 ) 7 8 func IsJsPackage(pkg *types.Package) bool { 9 return pkg != nil && pkg.Path() == "github.com/gopherjs/gopherjs/js" 10 } 11 12 func IsJsObject(t types.Type) bool { 13 ptr, isPtr := t.(*types.Pointer) 14 if !isPtr { 15 return false 16 } 17 named, isNamed := ptr.Elem().(*types.Named) 18 return isNamed && IsJsPackage(named.Obj().Pkg()) && named.Obj().Name() == "Object" 19 } 20 21 // RecvType returns a named type of a method receiver, or nil if it's not a method. 22 // 23 // For methods on a pointer receiver, the underlying named type is returned. 24 func RecvType(sig *types.Signature) *types.Named { 25 recv := sig.Recv() 26 if recv == nil { 27 return nil 28 } 29 30 typ := recv.Type() 31 if ptrType, ok := typ.(*types.Pointer); ok { 32 typ = ptrType.Elem() 33 } 34 35 return typ.(*types.Named) 36 } 37 38 // RecvAsFirstArg takes a method signature and returns a function 39 // signature with receiver as the first parameter. 40 func RecvAsFirstArg(sig *types.Signature) *types.Signature { 41 params := make([]*types.Var, 0, 1+sig.Params().Len()) 42 params = append(params, sig.Recv()) 43 for i := 0; i < sig.Params().Len(); i++ { 44 params = append(params, sig.Params().At(i)) 45 } 46 return types.NewSignatureType(nil, nil, nil, types.NewTuple(params...), sig.Results(), sig.Variadic()) 47 } 48 49 // Selection is a common interface for go/types.Selection and our custom-constructed 50 // method and field selections. 51 type Selection interface { 52 Kind() types.SelectionKind 53 Recv() types.Type 54 Index() []int 55 Obj() types.Object 56 Type() types.Type 57 } 58 59 // NewSelection creates a new selection. 60 func NewSelection(kind types.SelectionKind, recv types.Type, index []int, obj types.Object, typ types.Type) Selection { 61 return &selectionImpl{ 62 kind: kind, 63 recv: recv, 64 index: index, 65 obj: obj, 66 typ: typ, 67 } 68 } 69 70 type selectionImpl struct { 71 kind types.SelectionKind 72 recv types.Type 73 index []int 74 obj types.Object 75 typ types.Type 76 } 77 78 func (sel *selectionImpl) Kind() types.SelectionKind { return sel.kind } 79 func (sel *selectionImpl) Recv() types.Type { return sel.recv } 80 func (sel *selectionImpl) Index() []int { return sel.index } 81 func (sel *selectionImpl) Obj() types.Object { return sel.obj } 82 func (sel *selectionImpl) Type() types.Type { return sel.typ } 83 84 func fieldsOf(s *types.Struct) []*types.Var { 85 fields := make([]*types.Var, s.NumFields()) 86 for i := 0; i < s.NumFields(); i++ { 87 fields[i] = s.Field(i) 88 } 89 return fields 90 } 91 92 // OffsetOf returns byte offset of a struct field specified by the provided 93 // selection. 94 // 95 // Adapted from go/types.Config.offsetof(). 96 func OffsetOf(sizes types.Sizes, sel Selection) int64 { 97 if sel.Kind() != types.FieldVal { 98 panic(fmt.Errorf("byte offsets are only defined for struct fields")) 99 } 100 typ := sel.Recv() 101 var o int64 102 for _, idx := range sel.Index() { 103 s := typ.Underlying().(*types.Struct) 104 o += sizes.Offsetsof(fieldsOf(s))[idx] 105 typ = s.Field(idx).Type() 106 } 107 108 return o 109 }