1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package inline
// This file defines various common helpers.
import (
"go/ast"
"go/token"
"go/types"
"reflect"
"strings"
"cuelang.org/go/internal/golangorgx/tools/typeparams"
)
func is[T any](x any) bool {
_, ok := x.(T)
return ok
}
// TODO(adonovan): use go1.21's slices.Clone.
func clone[T any](slice []T) []T { return append([]T{}, slice...) }
// TODO(adonovan): use go1.21's slices.Index.
func index[T comparable](slice []T, x T) int {
for i, elem := range slice {
if elem == x {
return i
}
}
return -1
}
func btoi(b bool) int {
if b {
return 1
} else {
return 0
}
}
func offsetOf(fset *token.FileSet, pos token.Pos) int {
return fset.PositionFor(pos, false).Offset
}
// objectKind returns an object's kind (e.g. var, func, const, typename).
func objectKind(obj types.Object) string {
return strings.TrimPrefix(strings.ToLower(reflect.TypeOf(obj).String()), "*types.")
}
// within reports whether pos is within the half-open interval [n.Pos, n.End).
func within(pos token.Pos, n ast.Node) bool {
return n.Pos() <= pos && pos < n.End()
}
// trivialConversion reports whether it is safe to omit the implicit
// value-to-variable conversion that occurs in argument passing or
// result return. The only case currently allowed is converting from
// untyped constant to its default type (e.g. 0 to int).
//
// The reason for this check is that converting from A to B to C may
// yield a different result than converting A directly to C: consider
// 0 to int32 to any.
func trivialConversion(val types.Type, obj *types.Var) bool {
return types.Identical(types.Default(val), obj.Type())
}
func checkInfoFields(info *types.Info) {
assert(info.Defs != nil, "types.Info.Defs is nil")
assert(info.Implicits != nil, "types.Info.Implicits is nil")
assert(info.Scopes != nil, "types.Info.Scopes is nil")
assert(info.Selections != nil, "types.Info.Selections is nil")
assert(info.Types != nil, "types.Info.Types is nil")
assert(info.Uses != nil, "types.Info.Uses is nil")
}
func funcHasTypeParams(decl *ast.FuncDecl) bool {
// generic function?
if decl.Type.TypeParams != nil {
return true
}
// method on generic type?
if decl.Recv != nil {
t := decl.Recv.List[0].Type
if u, ok := t.(*ast.StarExpr); ok {
t = u.X
}
return is[*ast.IndexExpr](t) || is[*ast.IndexListExpr](t)
}
return false
}
// intersects reports whether the maps' key sets intersect.
func intersects[K comparable, T1, T2 any](x map[K]T1, y map[K]T2) bool {
if len(x) > len(y) {
return intersects(y, x)
}
for k := range x {
if _, ok := y[k]; ok {
return true
}
}
return false
}
// convert returns syntax for the conversion T(x).
func convert(T, x ast.Expr) *ast.CallExpr {
// The formatter generally adds parens as needed,
// but before go1.22 it had a bug (#63362) for
// channel types that requires this workaround.
if ch, ok := T.(*ast.ChanType); ok && ch.Dir == ast.RECV {
T = &ast.ParenExpr{X: T}
}
return &ast.CallExpr{
Fun: T,
Args: []ast.Expr{x},
}
}
// isPointer reports whether t is a pointer type.
func isPointer(t types.Type) bool { return t != deref(t) }
// indirectSelection is like seln.Indirect() without bug #8353.
func indirectSelection(seln *types.Selection) bool {
// Work around bug #8353 in Selection.Indirect when Kind=MethodVal.
if seln.Kind() == types.MethodVal {
tArg, indirect := effectiveReceiver(seln)
if indirect {
return true
}
tParam := seln.Obj().Type().Underlying().(*types.Signature).Recv().Type()
return isPointer(tArg) && !isPointer(tParam) // implicit *
}
return seln.Indirect()
}
// effectiveReceiver returns the effective type of the method
// receiver after all implicit field selections (but not implicit * or
// & operations) have been applied.
//
// The boolean indicates whether any implicit field selection was indirect.
func effectiveReceiver(seln *types.Selection) (types.Type, bool) {
assert(seln.Kind() == types.MethodVal, "not MethodVal")
t := seln.Recv()
indices := seln.Index()
indirect := false
for _, index := range indices[:len(indices)-1] {
if tElem := deref(t); tElem != t {
indirect = true
t = tElem
}
t = typeparams.CoreType(t).(*types.Struct).Field(index).Type()
}
return t, indirect
}
|