-
Notifications
You must be signed in to change notification settings - Fork 291
/
util.go
160 lines (139 loc) · 4.3 KB
/
util.go
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
}