Update go version
This commit is contained in:
171
vendor/golang.org/x/tools/go/ssa/builder.go
generated
vendored
171
vendor/golang.org/x/tools/go/ssa/builder.go
generated
vendored
@@ -85,6 +85,7 @@ import (
|
||||
"slices"
|
||||
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
@@ -100,6 +101,7 @@ var (
|
||||
// Type constants.
|
||||
tBool = types.Typ[types.Bool]
|
||||
tByte = types.Typ[types.Byte]
|
||||
tRune = types.Universe.Lookup("rune").Type() // prints as "rune" (Typ[Rune] is same as Int32)
|
||||
tInt = types.Typ[types.Int]
|
||||
tInvalid = types.Typ[types.Invalid]
|
||||
tString = types.Typ[types.String]
|
||||
@@ -123,7 +125,7 @@ var (
|
||||
// The ssa:deferstack intrinsic returns the current function's defer stack.
|
||||
vDeferStack = &Builtin{
|
||||
name: "ssa:deferstack",
|
||||
sig: types.NewSignatureType(nil, nil, nil, nil, types.NewTuple(anonVar(tDeferStack)), false),
|
||||
sig: types.NewSignatureType(nil, nil, nil, nil, typesinternal.TupleOf(tDeferStack), false),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -582,33 +584,6 @@ func (b *builder) assign(fn *Function, loc lvalue, e ast.Expr, isZero bool, sb *
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := loc.(*address); ok {
|
||||
if isNonTypeParamInterface(loc.typ()) {
|
||||
// e.g. var x interface{} = T{...}
|
||||
// Can't in-place initialize an interface value.
|
||||
// Fall back to copying.
|
||||
} else {
|
||||
// x = T{...} or x := T{...}
|
||||
addr := loc.address(fn)
|
||||
if sb != nil {
|
||||
b.compLit(fn, addr, e, isZero, sb)
|
||||
} else {
|
||||
var sb storebuf
|
||||
b.compLit(fn, addr, e, isZero, &sb)
|
||||
sb.emit(fn)
|
||||
}
|
||||
|
||||
// Subtle: emit debug ref for aggregate types only;
|
||||
// slice and map are handled by store ops in compLit.
|
||||
switch typeparams.CoreType(loc.typ()).(type) {
|
||||
case *types.Struct, *types.Array:
|
||||
emitDebugRef(fn, e, addr, true)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// simple case: just copy
|
||||
@@ -824,8 +799,8 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
|
||||
}
|
||||
callee := v.(*Function) // (func)
|
||||
if callee.typeparams.Len() > 0 {
|
||||
targs := fn.subst.types(instanceArgs(fn.info, e))
|
||||
callee = callee.instance(targs, b)
|
||||
targs := fn.subtargs(e)
|
||||
callee = callee.instance(nil, targs, b)
|
||||
}
|
||||
return callee
|
||||
}
|
||||
@@ -846,15 +821,16 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
|
||||
case types.MethodExpr:
|
||||
// (*T).f or T.f, the method f from the method-set of type T.
|
||||
// The result is a "thunk".
|
||||
thunk := createThunk(fn.Prog, sel)
|
||||
targs := fn.subtargs(e.Sel)
|
||||
thunk := createThunk(fn.Prog, sel, targs)
|
||||
b.enqueue(thunk)
|
||||
return emitConv(fn, thunk, fn.typ(tv.Type))
|
||||
return thunk
|
||||
|
||||
case types.MethodVal:
|
||||
// e.f where e is an expression and f is a method.
|
||||
// The result is a "bound".
|
||||
obj := sel.obj.(*types.Func)
|
||||
rt := fn.typ(recvType(obj))
|
||||
m := sel.obj.(*types.Func)
|
||||
rt := fn.typ(recvType(m))
|
||||
wantAddr := isPointer(rt)
|
||||
escaping := true
|
||||
v := b.receiver(fn, e.X, wantAddr, escaping, sel)
|
||||
@@ -885,19 +861,25 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
|
||||
emitTypeAssert(fn, v, rt, e.Sel.Pos())
|
||||
}
|
||||
}
|
||||
if targs := receiverTypeArgs(obj); len(targs) > 0 {
|
||||
// obj is generic.
|
||||
obj = fn.Prog.canon.instantiateMethod(obj, fn.subst.types(targs), fn.Prog.ctxt)
|
||||
|
||||
if rtargs := fn.subrtargs(m); len(rtargs) > 0 {
|
||||
m = fn.Prog.canon.instantiateMethod(m, rtargs, fn.Prog.ctxt)
|
||||
}
|
||||
bound := createBound(fn.Prog, obj)
|
||||
|
||||
targs := fn.subtargs(e.Sel)
|
||||
bound := createBound(fn.Prog, m, targs)
|
||||
b.enqueue(bound)
|
||||
|
||||
// The assignment may widen a type parameter to its
|
||||
// interface bound (case #3 of go.dev/issue.78110).
|
||||
v = emitConv(fn, v, bound.FreeVars[0].Type())
|
||||
|
||||
c := &MakeClosure{
|
||||
Fn: bound,
|
||||
Bindings: []Value{v},
|
||||
}
|
||||
c.setPos(e.Sel.Pos())
|
||||
c.setType(fn.typ(tv.Type))
|
||||
c.setType(bound.Signature)
|
||||
return fn.emit(c)
|
||||
|
||||
case types.FieldVal:
|
||||
@@ -1010,8 +992,15 @@ func (b *builder) receiver(fn *Function, e ast.Expr, wantAddr, escaping bool, se
|
||||
func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) {
|
||||
c.pos = e.Lparen
|
||||
|
||||
// Is this a method call?
|
||||
if selector, ok := ast.Unparen(e.Fun).(*ast.SelectorExpr); ok {
|
||||
// Is this a (possibly generic) method call?
|
||||
m := ast.Unparen(e.Fun)
|
||||
switch e := m.(type) {
|
||||
case *ast.IndexExpr:
|
||||
m = e.X
|
||||
case *ast.IndexListExpr:
|
||||
m = e.X
|
||||
}
|
||||
if selector, ok := m.(*ast.SelectorExpr); ok {
|
||||
sel := fn.selection(selector)
|
||||
if sel != nil && sel.kind == types.MethodVal {
|
||||
obj := sel.obj.(*types.Func)
|
||||
@@ -1026,7 +1015,8 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) {
|
||||
c.Method = obj
|
||||
} else {
|
||||
// "Call"-mode call.
|
||||
c.Value = fn.Prog.objectMethod(obj, b)
|
||||
targs := fn.subtargs(selector.Sel)
|
||||
c.Value = fn.Prog.objectMethod(obj, targs, b)
|
||||
c.Args = append(c.Args, v)
|
||||
}
|
||||
return
|
||||
@@ -1270,7 +1260,7 @@ func (b *builder) arrayLen(fn *Function, elts []ast.Expr) int64 {
|
||||
// x := T{a: 1}
|
||||
// x = T{a: x.a}
|
||||
//
|
||||
// all the reads must occur before all the writes. Thus all stores to
|
||||
// all the reads must occur before all the writes. Thus all stores to
|
||||
// loc are emitted to the storebuf sb for later execution.
|
||||
//
|
||||
// A CompositeLit may have pointer type only in the recursive (nested)
|
||||
@@ -1287,28 +1277,35 @@ func (b *builder) compLit(fn *Function, addr Value, e *ast.CompositeLit, isZero
|
||||
sb.store(&address{addr, e.Lbrace, nil}, zeroConst(zt))
|
||||
isZero = true
|
||||
}
|
||||
var fIndices []int
|
||||
for i, e := range e.Elts {
|
||||
fieldIndex := i
|
||||
pos := e.Pos()
|
||||
if kv, ok := e.(*ast.KeyValueExpr); ok {
|
||||
var (
|
||||
pos token.Pos
|
||||
fType types.Type
|
||||
)
|
||||
|
||||
if kv, ok := e.(*ast.KeyValueExpr); ok { // tagged field
|
||||
fname := kv.Key.(*ast.Ident).Name
|
||||
for i, n := 0, t.NumFields(); i < n; i++ {
|
||||
sf := t.Field(i)
|
||||
if sf.Name() == fname {
|
||||
fieldIndex = i
|
||||
pos = kv.Colon
|
||||
e = kv.Value
|
||||
break
|
||||
}
|
||||
}
|
||||
obj, index, _ := types.LookupFieldOrMethod(t, true, fn.declaredPackage().Pkg, fname)
|
||||
fIndices = append(fIndices[:0], index...)
|
||||
pos = kv.Colon
|
||||
e = kv.Value
|
||||
fType = obj.Type()
|
||||
} else { // untagged field
|
||||
fIndices = append(fIndices[:0], i)
|
||||
pos = e.Pos()
|
||||
fType = t.Field(i).Type()
|
||||
}
|
||||
sf := t.Field(fieldIndex)
|
||||
|
||||
last := len(fIndices) - 1
|
||||
v := emitImplicitSelections(fn, addr, fIndices[:last], pos)
|
||||
|
||||
faddr := &FieldAddr{
|
||||
X: addr,
|
||||
Field: fieldIndex,
|
||||
X: v,
|
||||
Field: fIndices[last],
|
||||
}
|
||||
faddr.setPos(pos)
|
||||
faddr.setType(types.NewPointer(sf.Type()))
|
||||
faddr.setType(types.NewPointer(fType))
|
||||
fn.emit(faddr)
|
||||
b.assign(fn, &address{addr: faddr, pos: pos, expr: e}, e, isZero, sb)
|
||||
}
|
||||
@@ -1467,13 +1464,14 @@ func (b *builder) switchStmt(fn *Function, s *ast.SwitchStmt, label *lblock) {
|
||||
var nextCond *BasicBlock
|
||||
for _, cond := range cc.List {
|
||||
nextCond = fn.newBasicBlock("switch.next")
|
||||
// TODO(adonovan): opt: when tag==vTrue, we'd
|
||||
// get better code if we use b.cond(cond)
|
||||
// instead of BinOp(EQL, tag, b.expr(cond))
|
||||
// followed by If. Don't forget conversions
|
||||
// though.
|
||||
cond := emitCompare(fn, token.EQL, tag, b.expr(fn, cond), cond.Pos())
|
||||
emitIf(fn, cond, body, nextCond)
|
||||
// For boolean switches, emit short-circuit control flow,
|
||||
// just like an if/else-chain.
|
||||
if tag == vTrue && !isNonTypeParamInterface(fn.info.Types[cond].Type) {
|
||||
b.cond(fn, cond, body, nextCond)
|
||||
} else {
|
||||
c := emitCompare(fn, token.EQL, tag, b.expr(fn, cond), cond.Pos())
|
||||
emitIf(fn, c, body, nextCond)
|
||||
}
|
||||
fn.currentBlock = nextCond
|
||||
}
|
||||
fn.currentBlock = body
|
||||
@@ -1722,7 +1720,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
|
||||
for _, st := range states {
|
||||
if st.Dir == types.RecvOnly {
|
||||
chtyp := typeparams.CoreType(fn.typ(st.Chan.Type())).(*types.Chan)
|
||||
vars = append(vars, anonVar(chtyp.Elem()))
|
||||
vars = append(vars, newVar("", chtyp.Elem()))
|
||||
}
|
||||
}
|
||||
sel.setType(types.NewTuple(vars...))
|
||||
@@ -2149,13 +2147,6 @@ func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token.
|
||||
// done: (target of break)
|
||||
//
|
||||
|
||||
if tk == nil {
|
||||
tk = tInvalid
|
||||
}
|
||||
if tv == nil {
|
||||
tv = tInvalid
|
||||
}
|
||||
|
||||
rng := &Range{X: x}
|
||||
rng.setPos(pos)
|
||||
rng.setType(tRangeIter)
|
||||
@@ -2165,14 +2156,29 @@ func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token.
|
||||
emitJump(fn, loop)
|
||||
fn.currentBlock = loop
|
||||
|
||||
var ak, av types.Type
|
||||
isString := false
|
||||
if m, ok := typeparams.CoreType(x.Type()).(*types.Map); ok {
|
||||
ak, av = m.Key(), m.Elem()
|
||||
} else {
|
||||
isString = true
|
||||
ak, av = tInt, tRune
|
||||
}
|
||||
if tk == nil {
|
||||
ak = tInvalid
|
||||
}
|
||||
if tv == nil {
|
||||
av = tInvalid
|
||||
}
|
||||
|
||||
okv := &Next{
|
||||
Iter: it,
|
||||
IsString: isBasic(typeparams.CoreType(x.Type())),
|
||||
IsString: isString,
|
||||
}
|
||||
okv.setType(types.NewTuple(
|
||||
varOk,
|
||||
newVar("k", tk),
|
||||
newVar("v", tv),
|
||||
newVar("k", ak),
|
||||
newVar("v", av),
|
||||
))
|
||||
fn.emit(okv)
|
||||
|
||||
@@ -2181,11 +2187,14 @@ func (b *builder) rangeIter(fn *Function, x Value, tk, tv types.Type, pos token.
|
||||
emitIf(fn, emitExtract(fn, okv, 0), body, done)
|
||||
fn.currentBlock = body
|
||||
|
||||
if tk != tInvalid {
|
||||
k = emitExtract(fn, okv, 1)
|
||||
// The assignment may widen a map or string
|
||||
// key/value to a variable's interface type
|
||||
// (cases #1 and #2 of go.dev/issue/78110).
|
||||
if tk != nil {
|
||||
k = emitConv(fn, emitExtract(fn, okv, 1), tk)
|
||||
}
|
||||
if tv != tInvalid {
|
||||
v = emitExtract(fn, okv, 2)
|
||||
if tv != nil {
|
||||
v = emitConv(fn, emitExtract(fn, okv, 2), tv)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
4
vendor/golang.org/x/tools/go/ssa/const.go
generated
vendored
4
vendor/golang.org/x/tools/go/ssa/const.go
generated
vendored
@@ -131,7 +131,9 @@ func nillable(t types.Type) bool {
|
||||
return u != nil && nillable(u)
|
||||
})
|
||||
}
|
||||
switch t.Underlying().(type) {
|
||||
switch t := t.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
return t.Kind() == types.UnsafePointer
|
||||
case *types.Pointer, *types.Slice, *types.Chan, *types.Map, *types.Signature:
|
||||
return true
|
||||
case *types.Interface:
|
||||
|
||||
54
vendor/golang.org/x/tools/go/ssa/create.go
generated
vendored
54
vendor/golang.org/x/tools/go/ssa/create.go
generated
vendored
@@ -15,7 +15,6 @@ import (
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/tools/internal/ssainternal"
|
||||
"golang.org/x/tools/internal/versions"
|
||||
)
|
||||
|
||||
@@ -116,33 +115,26 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node, goversion
|
||||
func createFunction(prog *Program, obj *types.Func, name string, syntax ast.Node, info *types.Info, goversion string) *Function {
|
||||
sig := obj.Type().(*types.Signature)
|
||||
|
||||
// Collect type parameters.
|
||||
var tparams *types.TypeParamList
|
||||
if rtparams := sig.RecvTypeParams(); rtparams.Len() > 0 {
|
||||
tparams = rtparams // method of generic type
|
||||
} else if sigparams := sig.TypeParams(); sigparams.Len() > 0 {
|
||||
tparams = sigparams // generic function
|
||||
}
|
||||
|
||||
/* declared function/method (from syntax or export data) */
|
||||
fn := &Function{
|
||||
name: name,
|
||||
object: obj,
|
||||
Signature: sig,
|
||||
build: (*builder).buildFromSyntax,
|
||||
syntax: syntax,
|
||||
info: info,
|
||||
goversion: goversion,
|
||||
pos: obj.Pos(),
|
||||
Pkg: nil, // may be set by caller
|
||||
Prog: prog,
|
||||
typeparams: tparams,
|
||||
name: name,
|
||||
object: obj,
|
||||
Signature: sig,
|
||||
build: (*builder).buildFromSyntax,
|
||||
syntax: syntax,
|
||||
info: info,
|
||||
goversion: goversion,
|
||||
pos: obj.Pos(),
|
||||
Pkg: nil, // may be set by caller
|
||||
Prog: prog,
|
||||
recvtypeparams: sig.RecvTypeParams(),
|
||||
typeparams: sig.TypeParams(),
|
||||
}
|
||||
if fn.syntax == nil {
|
||||
fn.Synthetic = "from type information"
|
||||
fn.build = (*builder).buildParamsOnly
|
||||
}
|
||||
if tparams.Len() > 0 {
|
||||
if fn.hasTypeParams() {
|
||||
fn.generic = new(generic)
|
||||
}
|
||||
return fn
|
||||
@@ -314,19 +306,13 @@ func (prog *Program) ImportedPackage(path string) *Package {
|
||||
return prog.imported[path]
|
||||
}
|
||||
|
||||
// setNoReturn sets the predicate used by the SSA builder to decide
|
||||
// whether a call to the specified named function cannot return,
|
||||
// allowing the builder to prune control-flow edges following the
|
||||
// call, thus improving the precision of downstream analysis.
|
||||
// SetNoReturn sets the predicate used when building the ssa.Program
|
||||
// prog that reports whether a given function cannot return.
|
||||
// This may be used to prune spurious control flow edges
|
||||
// after (e.g.) log.Fatal, improving the precision of analyses.
|
||||
//
|
||||
// TODO(adonovan): add (*Program).SetNoReturn to the public API.
|
||||
func (prog *Program) setNoReturn(noReturn func(*types.Func) bool) {
|
||||
// A typical implementation is the [ctrlflow.CFGs.NoReturn] method from
|
||||
// [golang.org/x/tools/go/analysis/passes/ctrlflow].
|
||||
func (prog *Program) SetNoReturn(noReturn func(*types.Func) bool) {
|
||||
prog.noReturn = noReturn
|
||||
}
|
||||
|
||||
func init() {
|
||||
// SetNoReturn exposes Program.setNoReturn to the buildssa analyzer.
|
||||
ssainternal.SetNoReturn = func(prog any, noReturn func(*types.Func) bool) {
|
||||
prog.(*Program).setNoReturn(noReturn)
|
||||
}
|
||||
}
|
||||
|
||||
2
vendor/golang.org/x/tools/go/ssa/emit.go
generated
vendored
2
vendor/golang.org/x/tools/go/ssa/emit.go
generated
vendored
@@ -248,7 +248,7 @@ func emitConv(f *Function, val Value, typ types.Type) Value {
|
||||
// Record the types of operands to MakeInterface, if
|
||||
// non-parameterized, as they are the set of runtime types.
|
||||
t := val.Type()
|
||||
if f.typeparams.Len() == 0 || !f.Prog.isParameterized(t) {
|
||||
if !f.Prog.isParameterized(t) {
|
||||
addMakeInterfaceType(f.Prog, t)
|
||||
}
|
||||
|
||||
|
||||
57
vendor/golang.org/x/tools/go/ssa/instantiate.go
generated
vendored
57
vendor/golang.org/x/tools/go/ssa/instantiate.go
generated
vendored
@@ -19,13 +19,13 @@ type generic struct {
|
||||
}
|
||||
|
||||
// instance returns a Function that is the instantiation of generic
|
||||
// origin function fn with the type arguments targs.
|
||||
// origin function fn with the type arguments rtargs and targs.
|
||||
//
|
||||
// Any created instance is added to cr.
|
||||
//
|
||||
// Acquires fn.generic.instancesMu.
|
||||
func (fn *Function) instance(targs []types.Type, b *builder) *Function {
|
||||
key := fn.Prog.canon.List(targs)
|
||||
func (fn *Function) instance(rtargs, targs []types.Type, b *builder) *Function {
|
||||
key := fn.Prog.canon.List(slices.Concat(rtargs, targs))
|
||||
|
||||
gen := fn.generic
|
||||
|
||||
@@ -33,7 +33,7 @@ func (fn *Function) instance(targs []types.Type, b *builder) *Function {
|
||||
defer gen.instancesMu.Unlock()
|
||||
inst, ok := gen.instances[key]
|
||||
if !ok {
|
||||
inst = createInstance(fn, targs)
|
||||
inst = createInstance(fn, rtargs, targs)
|
||||
inst.buildshared = b.shared()
|
||||
b.enqueue(inst)
|
||||
|
||||
@@ -48,20 +48,46 @@ func (fn *Function) instance(targs []types.Type, b *builder) *Function {
|
||||
}
|
||||
|
||||
// createInstance returns the instantiation of generic function fn using targs.
|
||||
// If fn is a method on a generic type, fn's receiver type will be instantiated
|
||||
// using rtargs.
|
||||
//
|
||||
// Requires fn.generic.instancesMu.
|
||||
func createInstance(fn *Function, targs []types.Type) *Function {
|
||||
func createInstance(fn *Function, rtargs, targs []types.Type) *Function {
|
||||
prog := fn.Prog
|
||||
|
||||
// Compute signature.
|
||||
var sig *types.Signature
|
||||
var obj *types.Func
|
||||
if recv := fn.Signature.Recv(); recv != nil {
|
||||
// method
|
||||
obj = prog.canon.instantiateMethod(fn.object, targs, prog.ctxt)
|
||||
sig = obj.Type().(*types.Signature)
|
||||
// method, len(rtargs) > 0 || len(targs) > 0
|
||||
if len(rtargs) > 0 {
|
||||
// possibly generic method on generic type
|
||||
obj = prog.canon.instantiateMethod(fn.object, rtargs, prog.ctxt)
|
||||
} else {
|
||||
// generic method on non-generic type
|
||||
obj = fn.object // instantiation does not exist yet
|
||||
}
|
||||
if len(targs) > 0 {
|
||||
// generic method
|
||||
instSig, err := types.Instantiate(prog.ctxt, obj.Signature(), targs, false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
instance, ok := instSig.(*types.Signature)
|
||||
if !ok {
|
||||
panic("Instantiate of a Signature returned a non-signature")
|
||||
}
|
||||
// Do not canonicalize generic methods, because the receiver is not
|
||||
// part of a Signature's type identity. For example,
|
||||
// (*G[int]).m[int] and (G[int]).n[int] may be identical types even
|
||||
// though their receiver types differ.
|
||||
sig = instance
|
||||
} else {
|
||||
// non-generic method on generic type
|
||||
sig = obj.Signature()
|
||||
}
|
||||
} else {
|
||||
// function
|
||||
// function, len(rtargs) == 0 && len(targs) > 0
|
||||
instSig, err := types.Instantiate(prog.ctxt, fn.Signature, targs, false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -80,10 +106,10 @@ func createInstance(fn *Function, targs []types.Type) *Function {
|
||||
subst *subster
|
||||
build buildFunc
|
||||
)
|
||||
if prog.mode&InstantiateGenerics != 0 && !prog.isParameterized(targs...) {
|
||||
if prog.mode&InstantiateGenerics != 0 && !prog.isParameterized(slices.Concat(rtargs, targs)...) {
|
||||
synthetic = fmt.Sprintf("instance of %s", fn.Name())
|
||||
if fn.syntax != nil {
|
||||
subst = makeSubster(prog.ctxt, obj, fn.typeparams, targs)
|
||||
subst = makeSubster(prog.ctxt, obj, fn.recvtypeparams, rtargs, fn.typeparams, targs)
|
||||
build = (*builder).buildFromSyntax
|
||||
} else {
|
||||
build = (*builder).buildParamsOnly
|
||||
@@ -93,9 +119,14 @@ func createInstance(fn *Function, targs []types.Type) *Function {
|
||||
build = (*builder).buildInstantiationWrapper
|
||||
}
|
||||
|
||||
name := fn.Name()
|
||||
if len(targs) > 0 {
|
||||
name = fmt.Sprintf("%s%s", name, targstr(targs)) // may not be unique
|
||||
}
|
||||
|
||||
/* generic instance or instantiation wrapper */
|
||||
return &Function{
|
||||
name: fmt.Sprintf("%s%s", fn.Name(), targs), // may not be unique
|
||||
name: name,
|
||||
object: obj,
|
||||
Signature: sig,
|
||||
Synthetic: synthetic,
|
||||
@@ -107,6 +138,8 @@ func createInstance(fn *Function, targs []types.Type) *Function {
|
||||
pos: obj.Pos(),
|
||||
Pkg: nil,
|
||||
Prog: fn.Prog,
|
||||
recvtypeparams: fn.recvtypeparams, // share with origin
|
||||
recvtypeargs: rtargs,
|
||||
typeparams: fn.typeparams, // share with origin
|
||||
typeargs: targs,
|
||||
subst: subst,
|
||||
|
||||
35
vendor/golang.org/x/tools/go/ssa/methods.go
generated
vendored
35
vendor/golang.org/x/tools/go/ssa/methods.go
generated
vendored
@@ -32,8 +32,8 @@ func (prog *Program) MethodValue(sel *types.Selection) *Function {
|
||||
return nil // interface method or type parameter
|
||||
}
|
||||
|
||||
if prog.isParameterized(T) {
|
||||
return nil // generic method
|
||||
if prog.isParameterized(T, sel.Type()) {
|
||||
return nil // method on generic type or generic method
|
||||
}
|
||||
|
||||
if prog.mode&LogSource != 0 {
|
||||
@@ -61,11 +61,11 @@ func (prog *Program) MethodValue(sel *types.Selection) *Function {
|
||||
needsPromotion := len(sel.Index()) > 1
|
||||
needsIndirection := !isPointer(recvType(obj)) && isPointer(T)
|
||||
if needsPromotion || needsIndirection {
|
||||
fn = createWrapper(prog, toSelection(sel))
|
||||
fn = createWrapper(prog, toSelection(sel), nil)
|
||||
fn.buildshared = b.shared()
|
||||
b.enqueue(fn)
|
||||
} else {
|
||||
fn = prog.objectMethod(obj, &b)
|
||||
fn = prog.objectMethod(obj, nil, &b)
|
||||
}
|
||||
if fn.Signature.Recv() == nil {
|
||||
panic(fn)
|
||||
@@ -91,25 +91,22 @@ func (prog *Program) MethodValue(sel *types.Selection) *Function {
|
||||
// objectMethod panics if the function is not a method.
|
||||
//
|
||||
// Acquires prog.objectMethodsMu.
|
||||
func (prog *Program) objectMethod(obj *types.Func, b *builder) *Function {
|
||||
func (prog *Program) objectMethod(obj *types.Func, targs []types.Type, b *builder) *Function {
|
||||
sig := obj.Type().(*types.Signature)
|
||||
if sig.Recv() == nil {
|
||||
panic("not a method: " + obj.String())
|
||||
}
|
||||
|
||||
// Instantiation of generic?
|
||||
if orig := obj.Origin(); orig != obj || len(targs) > 0 {
|
||||
return prog.objectMethod(orig, nil, b).instance(receiverTypeArgs(obj), targs, b)
|
||||
}
|
||||
|
||||
// Belongs to a created package?
|
||||
if fn := prog.FuncValue(obj); fn != nil {
|
||||
return fn
|
||||
}
|
||||
|
||||
// Instantiation of generic?
|
||||
if originObj := obj.Origin(); originObj != obj {
|
||||
origin := prog.objectMethod(originObj, b)
|
||||
assert(origin.typeparams.Len() > 0, "origin is not generic")
|
||||
targs := receiverTypeArgs(obj)
|
||||
return origin.instance(targs, b)
|
||||
}
|
||||
|
||||
// Consult/update cache of methods created from types.Func.
|
||||
prog.objectMethodsMu.Lock()
|
||||
defer prog.objectMethodsMu.Unlock()
|
||||
@@ -170,10 +167,18 @@ func (prog *Program) RuntimeTypes() []types.Type {
|
||||
// eliminates the need to eagerly compute all the element
|
||||
// types during SSA building.
|
||||
var runtimeTypes []types.Type
|
||||
add := func(t types.Type) { runtimeTypes = append(runtimeTypes, t) }
|
||||
var set typeutil.Map // for de-duping identical types
|
||||
for t := range prog.makeInterfaceTypes {
|
||||
typesinternal.ForEachElement(&set, &prog.MethodSets, t, add)
|
||||
typesinternal.ForEachElement(prog.MethodSets.MethodSet, t, func(t types.Type, access bool) bool {
|
||||
if !access {
|
||||
return false // inaccessible to reflection
|
||||
}
|
||||
seen, _ := set.Set(t, true).(bool)
|
||||
if !seen {
|
||||
runtimeTypes = append(runtimeTypes, t)
|
||||
}
|
||||
return seen
|
||||
})
|
||||
}
|
||||
|
||||
return runtimeTypes
|
||||
|
||||
53
vendor/golang.org/x/tools/go/ssa/sanity.go
generated
vendored
53
vendor/golang.org/x/tools/go/ssa/sanity.go
generated
vendored
@@ -16,6 +16,8 @@ import (
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
)
|
||||
|
||||
type sanity struct {
|
||||
@@ -154,12 +156,17 @@ func (s *sanity) checkInstr(idx int, instr Instruction) {
|
||||
case *Lookup:
|
||||
case *MakeChan:
|
||||
case *MakeClosure:
|
||||
numFree := len(instr.Fn.(*Function).FreeVars)
|
||||
numBind := len(instr.Bindings)
|
||||
if numFree != numBind {
|
||||
fn := instr.Fn.(*Function)
|
||||
if numFree, numBind := len(fn.FreeVars), len(instr.Bindings); numFree != numBind {
|
||||
s.errorf("MakeClosure has %d Bindings for function %s with %d free vars",
|
||||
numBind, instr.Fn, numFree)
|
||||
|
||||
} else {
|
||||
for i, fv := range fn.FreeVars {
|
||||
if !types.Identical(instr.Bindings[i].Type(), fv.Type()) {
|
||||
s.errorf("MakeClosure binding %d for %s has type %s, expected %s",
|
||||
i, fv.Name(), instr.Bindings[i].Type(), fv.Type())
|
||||
}
|
||||
}
|
||||
}
|
||||
if recv := instr.Type().(*types.Signature).Recv(); recv != nil {
|
||||
s.errorf("MakeClosure's type includes receiver %s", recv.Type())
|
||||
@@ -170,12 +177,42 @@ func (s *sanity) checkInstr(idx int, instr Instruction) {
|
||||
case *MakeSlice:
|
||||
case *MapUpdate:
|
||||
case *Next:
|
||||
rng, ok := instr.Iter.(*Range)
|
||||
if !ok {
|
||||
s.errorf("Next: Iter is %T, not *Range", instr.Iter)
|
||||
}
|
||||
if rng.Type() != tRangeIter {
|
||||
s.errorf("Next: Iter has type %s, expected %s", rng.Type(), tRangeIter)
|
||||
}
|
||||
var ek, ev types.Type
|
||||
switch xt := typeparams.CoreType(rng.X.Type()).(type) {
|
||||
case *types.Basic:
|
||||
if types.Default(xt) != tString {
|
||||
s.errorf("Next: basic operand of Next.Iter (Range) is %s, want string or untyped string", xt)
|
||||
}
|
||||
ek, ev = tInt, tRune
|
||||
case *types.Map:
|
||||
ek, ev = xt.Key(), xt.Elem()
|
||||
}
|
||||
|
||||
res := instr.Type().(*types.Tuple) // (ok bool, k K, v V), but K or V may be invalid if unused
|
||||
if !types.Identical(res.At(1).Type(), ek) && res.At(1).Type() != tInvalid {
|
||||
s.errorf("Next: key type %s does not match map key type %s", res.At(1).Type(), ek)
|
||||
}
|
||||
if !types.Identical(res.At(2).Type(), ev) && res.At(2).Type() != tInvalid {
|
||||
s.errorf("Next: value type %s does not match map value type %s", res.At(2).Type(), ev)
|
||||
}
|
||||
|
||||
case *Range:
|
||||
case *RunDefers:
|
||||
case *Select:
|
||||
case *Send:
|
||||
case *Slice:
|
||||
case *Store:
|
||||
if !types.Identical(instr.Val.Type(), typeparams.CoreType(instr.Addr.Type()).(*types.Pointer).Elem()) {
|
||||
s.errorf("Store: value type %s does not match address type %s",
|
||||
instr.Val.Type(), instr.Addr.Type())
|
||||
}
|
||||
case *TypeAssert:
|
||||
case *UnOp:
|
||||
case *DebugRef:
|
||||
@@ -417,7 +454,7 @@ func (s *sanity) checkFunctionParams() {
|
||||
}
|
||||
|
||||
if !types.Identical(sigType, param.Type()) {
|
||||
s.errorf("expect type %s in signature but got type %s in param %d", param.Type(), sigType, i)
|
||||
s.errorf("expect type %s in signature but got type %s in param %d", sigType, param.Type(), i)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -492,16 +529,16 @@ func (s *sanity) checkFunction(fn *Function) bool {
|
||||
strings.HasSuffix(fn.name, "Error") ||
|
||||
strings.HasPrefix(fn.Synthetic, "instance ") ||
|
||||
strings.HasPrefix(fn.Synthetic, "instantiation ") ||
|
||||
(fn.parent != nil && len(fn.typeargs) > 0) /* anon fun in instance */ {
|
||||
fn.parent != nil && fn.parent.hasTypeArgs() /* anon fun in instance */ {
|
||||
// ok
|
||||
} else {
|
||||
s.errorf("nil Pkg")
|
||||
}
|
||||
}
|
||||
if src, syn := fn.Synthetic == "", fn.Syntax() != nil; src != syn {
|
||||
if len(fn.typeargs) > 0 && fn.Prog.mode&InstantiateGenerics != 0 {
|
||||
if fn.hasTypeArgs() && fn.Prog.mode&InstantiateGenerics != 0 {
|
||||
// ok (instantiation with InstantiateGenerics on)
|
||||
} else if fn.topLevelOrigin != nil && len(fn.typeargs) > 0 {
|
||||
} else if fn.hasTypeArgs() && fn.topLevelOrigin != nil {
|
||||
// ok (we always have the syntax set for instantiation)
|
||||
} else if _, rng := fn.syntax.(*ast.RangeStmt); rng && fn.Synthetic == "range-over-func yield" {
|
||||
// ok (range-func-yields are both synthetic and keep syntax)
|
||||
|
||||
109
vendor/golang.org/x/tools/go/ssa/ssa.go
generated
vendored
109
vendor/golang.org/x/tools/go/ssa/ssa.go
generated
vendored
@@ -13,7 +13,11 @@ import (
|
||||
"go/constant"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
@@ -364,8 +368,10 @@ type Function struct {
|
||||
referrers []Instruction // referring instructions (iff Parent() != nil)
|
||||
anonIdx int32 // position of a nested function in parent's AnonFuncs. fn.Parent()!=nil => fn.Parent().AnonFunc[fn.anonIdx] == fn.
|
||||
|
||||
typeparams *types.TypeParamList // type parameters of this function. typeparams.Len() > 0 => generic or instance of generic function
|
||||
typeargs []types.Type // type arguments that instantiated typeparams. len(typeargs) > 0 => instance of generic function
|
||||
recvtypeparams *types.TypeParamList // receiver type parameters of this function. recvtypeparams.Len() > 0 => method on generic or instance of generic type
|
||||
recvtypeargs []types.Type // type arguments that instantiated recvtypeparams. len(recvtypeargs) > 0 => method on instance of generic type
|
||||
typeparams *types.TypeParamList // type parameters of this function. typeparams.Len() > 0 => generic or instance of generic function or method
|
||||
typeargs []types.Type // type arguments that instantiated typeparams. len(typeargs) > 0 => instance of generic function or method
|
||||
topLevelOrigin *Function // the origin function if this is an instance of a source function. nil if Parent()!=nil.
|
||||
generic *generic // instances of this function, if generic
|
||||
|
||||
@@ -1577,18 +1583,73 @@ func (v *Function) Referrers() *[]Instruction {
|
||||
|
||||
// TypeParams are the function's type parameters if generic or the
|
||||
// type parameters that were instantiated if fn is an instantiation.
|
||||
//
|
||||
// Specifically, the resulting list behaves like:
|
||||
//
|
||||
// func f // []
|
||||
// func f[P] // [P]
|
||||
// func (T) m // []
|
||||
// func (T) m[P] // [P]
|
||||
// func (T[P]) m // [P]
|
||||
// func (T[P]) m[Q] // [P (index=0), Q (index=0)]
|
||||
//
|
||||
// Note that receiver type parameters precede other type parameters.
|
||||
// Also, type parameters may have the same index if they come from
|
||||
// different source type parameter lists.
|
||||
func (fn *Function) TypeParams() *types.TypeParamList {
|
||||
return fn.typeparams
|
||||
return consTypeParamLists(fn.recvtypeparams, fn.typeparams)
|
||||
}
|
||||
|
||||
func consTypeParamLists(l, r *types.TypeParamList) *types.TypeParamList {
|
||||
if l.Len() == 0 {
|
||||
return r
|
||||
}
|
||||
if r.Len() == 0 {
|
||||
return l
|
||||
}
|
||||
|
||||
tpars := make([]*types.TypeParam, l.Len()+r.Len())
|
||||
for i := range l.Len() {
|
||||
tpars[i] = l.At(i)
|
||||
}
|
||||
for i := range r.Len() {
|
||||
tpars[i+l.Len()] = r.At(i)
|
||||
}
|
||||
// This logic unsafely assumes (and asserts) that the layout of the
|
||||
// TypeParamList is identical to that of a slice of TypeParams. This
|
||||
// is a hack while we work on getting a constructor for TypeParamList
|
||||
// approved (see go.dev/issue/79603).
|
||||
t := reflect.TypeFor[types.TypeParamList]()
|
||||
if t.NumField() != 1 {
|
||||
panic("TypeParamList has unexpected fields")
|
||||
}
|
||||
if f := t.Field(0); f.Offset != 0 || f.Type != reflect.TypeFor[[]*types.TypeParam]() {
|
||||
panic("TypeParamList field is not []*TypeParam")
|
||||
}
|
||||
return (*types.TypeParamList)(unsafe.Pointer(&tpars))
|
||||
}
|
||||
|
||||
// TypeArgs are the types that TypeParams() were instantiated by to create fn
|
||||
// from fn.Origin().
|
||||
func (fn *Function) TypeArgs() []types.Type { return fn.typeargs }
|
||||
//
|
||||
// Specifically, the resulting slice behaves like:
|
||||
//
|
||||
// f // []
|
||||
// f[int] // [int]
|
||||
// T.m // []
|
||||
// T.m[int] // [int]
|
||||
// T[int].m // [int]
|
||||
// T[int].m[uint] // [int, uint]
|
||||
//
|
||||
// Note that receiver type arguments precede other type arguments.
|
||||
func (fn *Function) TypeArgs() []types.Type {
|
||||
return slices.Concat(fn.recvtypeargs, fn.typeargs)
|
||||
}
|
||||
|
||||
// Origin returns the generic function from which fn was instantiated,
|
||||
// or nil if fn is not an instantiation.
|
||||
func (fn *Function) Origin() *Function {
|
||||
if fn.parent != nil && len(fn.typeargs) > 0 {
|
||||
if fn.parent != nil && fn.parent.hasTypeArgs() {
|
||||
// Nested functions are BUILT at a different time than their instances.
|
||||
// Build declared package if not yet BUILT. This is not an expected use
|
||||
// case, but is simple and robust.
|
||||
@@ -1597,12 +1658,48 @@ func (fn *Function) Origin() *Function {
|
||||
return origin(fn)
|
||||
}
|
||||
|
||||
// hasTypeParams returns whether fn has any type parameters
|
||||
func (fn *Function) hasTypeParams() bool {
|
||||
return fn.recvtypeparams.Len()+fn.typeparams.Len() > 0
|
||||
}
|
||||
|
||||
// hasTypeArgs returns whether fn has any type arguments
|
||||
func (fn *Function) hasTypeArgs() bool {
|
||||
return len(fn.recvtypeargs)+len(fn.typeargs) > 0
|
||||
}
|
||||
|
||||
// subrtargs returns fn's receiver type parameters substituted with receiver type arguments
|
||||
func (fn *Function) subrtargs(m *types.Func) []types.Type {
|
||||
return fn.subst.types(receiverTypeArgs(m))
|
||||
}
|
||||
|
||||
// subtargs returns fn's type parameters substituted with (possibly implied) type arguments
|
||||
func (fn *Function) subtargs(id *ast.Ident) []types.Type {
|
||||
return fn.subst.types(instanceArgs(fn.info, id))
|
||||
}
|
||||
|
||||
// targstr returns a comma-separated string of the types in targs
|
||||
func targstr(targs []types.Type) string {
|
||||
var sb strings.Builder
|
||||
if len(targs) > 0 {
|
||||
sb.WriteString("[")
|
||||
for i := range targs {
|
||||
if i > 0 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
sb.WriteString(targs[i].String())
|
||||
}
|
||||
sb.WriteString("]")
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// origin is the function that fn is an instantiation of. Returns nil if fn is
|
||||
// not an instantiation.
|
||||
//
|
||||
// Precondition: fn and the origin function are done building.
|
||||
func origin(fn *Function) *Function {
|
||||
if fn.parent != nil && len(fn.typeargs) > 0 {
|
||||
if fn.parent != nil && fn.parent.hasTypeArgs() {
|
||||
return origin(fn.parent).AnonFuncs[fn.anonIdx]
|
||||
}
|
||||
return fn.topLevelOrigin
|
||||
|
||||
13
vendor/golang.org/x/tools/go/ssa/ssautil/visit.go
generated
vendored
13
vendor/golang.org/x/tools/go/ssa/ssautil/visit.go
generated
vendored
@@ -74,8 +74,11 @@ func AllFunctions(prog *ssa.Program) map[*ssa.Function]bool {
|
||||
methodsOf := func(T types.Type) {
|
||||
if !types.IsInterface(T) {
|
||||
mset := prog.MethodSets.MethodSet(T)
|
||||
for method := range mset.Methods() {
|
||||
function(prog.MethodValue(method))
|
||||
for sel := range mset.Methods() {
|
||||
// Skip generic methods.
|
||||
if sel.Obj().(*types.Func).Signature().TypeParams() == nil {
|
||||
function(prog.MethodValue(sel))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,6 +107,7 @@ func AllFunctions(prog *ssa.Program) map[*ssa.Function]bool {
|
||||
// Consider only named types.
|
||||
// (Ignore aliases and unsafe.Pointer.)
|
||||
if named, ok := t.Type().(*types.Named); ok {
|
||||
// Skip generic types.
|
||||
if named.TypeParams() == nil {
|
||||
methodsOf(named) // T
|
||||
methodsOf(types.NewPointer(named)) // *T
|
||||
@@ -117,6 +121,11 @@ func AllFunctions(prog *ssa.Program) map[*ssa.Function]bool {
|
||||
switch mem := mem.(type) {
|
||||
case *ssa.Function:
|
||||
// Visit all package-level declared functions.
|
||||
//
|
||||
// (This may include generic functions, which is
|
||||
// inconsistent with the treatment of methods:
|
||||
// we skip both generic methods,
|
||||
// and methods of generic types.)
|
||||
function(mem)
|
||||
|
||||
case *ssa.Type:
|
||||
|
||||
33
vendor/golang.org/x/tools/go/ssa/subst.go
generated
vendored
33
vendor/golang.org/x/tools/go/ssa/subst.go
generated
vendored
@@ -5,6 +5,7 @@
|
||||
package ssa
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/go/types/typeutil"
|
||||
@@ -56,18 +57,25 @@ type subster struct {
|
||||
// TODO(taking): consider adding Pos
|
||||
}
|
||||
|
||||
// Returns a subster that replaces tparams[i] with targs[i]. Uses ctxt as a cache.
|
||||
// targs should not contain any types in tparams.
|
||||
// Returns a subster that replaces rtparams[i] with rtargs[i] and tparams[i] with targs[i].
|
||||
// Uses ctxt as a cache. rtargs and targs should not contain any types in rtparams or tparams.
|
||||
// fn is the generic function for which we are substituting.
|
||||
func makeSubster(ctxt *types.Context, fn *types.Func, tparams *types.TypeParamList, targs []types.Type) *subster {
|
||||
assert(tparams.Len() == len(targs), "makeSubster argument count must match")
|
||||
func makeSubster(ctxt *types.Context, fn *types.Func, rtparams *types.TypeParamList, rtargs []types.Type, tparams *types.TypeParamList, targs []types.Type) *subster {
|
||||
got := len(rtargs) + len(targs)
|
||||
want := rtparams.Len() + tparams.Len()
|
||||
if got != want {
|
||||
panic(fmt.Sprintf("makeSubster argument count must match: got %d; want %d", got, want))
|
||||
}
|
||||
|
||||
subst := &subster{
|
||||
replacements: make(map[*types.TypeParam]types.Type, tparams.Len()),
|
||||
replacements: make(map[*types.TypeParam]types.Type, want),
|
||||
cache: make(map[types.Type]types.Type),
|
||||
origin: fn.Origin(),
|
||||
ctxt: ctxt,
|
||||
}
|
||||
for i := 0; i < rtparams.Len(); i++ {
|
||||
subst.replacements[rtparams.At(i)] = rtargs[i]
|
||||
}
|
||||
for i := 0; i < tparams.Len(); i++ {
|
||||
subst.replacements[tparams.At(i)] = targs[i]
|
||||
}
|
||||
@@ -319,10 +327,10 @@ func (subst *subster) interface_(iface *types.Interface) *types.Interface {
|
||||
|
||||
func (subst *subster) alias(t *types.Alias) types.Type {
|
||||
// See subster.named. This follows the same strategy.
|
||||
tparams := aliases.TypeParams(t)
|
||||
targs := aliases.TypeArgs(t)
|
||||
tparams := t.TypeParams()
|
||||
targs := t.TypeArgs()
|
||||
tname := t.Obj()
|
||||
torigin := aliases.Origin(t)
|
||||
torigin := t.Origin()
|
||||
|
||||
if !declaredWithin(tname, subst.origin) {
|
||||
// t is declared outside of the function origin. So t is a package level type alias.
|
||||
@@ -361,15 +369,10 @@ func (subst *subster) alias(t *types.Alias) types.Type {
|
||||
}
|
||||
|
||||
// Substitute rhs.
|
||||
rhs := subst.typ(aliases.Rhs(t))
|
||||
rhs := subst.typ(t.Rhs())
|
||||
|
||||
// Create the fresh alias.
|
||||
//
|
||||
// Until 1.27, the result of aliases.NewAlias(...).Type() cannot guarantee it is a *types.Alias.
|
||||
// However, as t is an *alias.Alias and t is well-typed, then aliases must have been enabled.
|
||||
// Follow this decision, and always enable aliases here.
|
||||
const enabled = true
|
||||
obj := aliases.NewAlias(enabled, tname.Pos(), tname.Pkg(), tname.Name(), rhs, newTParams)
|
||||
obj := aliases.New(tname.Pos(), tname.Pkg(), tname.Name(), rhs, newTParams)
|
||||
|
||||
// Substitute into all of the constraints after they are created.
|
||||
for i, ntp := range newTParams {
|
||||
|
||||
10
vendor/golang.org/x/tools/go/ssa/util.go
generated
vendored
10
vendor/golang.org/x/tools/go/ssa/util.go
generated
vendored
@@ -181,19 +181,13 @@ func newVar(name string, typ types.Type) *types.Var {
|
||||
return types.NewParam(token.NoPos, nil, name, typ)
|
||||
}
|
||||
|
||||
// anonVar creates an anonymous 'var' for use in a types.Tuple.
|
||||
func anonVar(typ types.Type) *types.Var {
|
||||
return newVar("", typ)
|
||||
}
|
||||
|
||||
var lenResults = types.NewTuple(anonVar(tInt))
|
||||
var lenResults = typesinternal.TupleOf(tInt)
|
||||
|
||||
// makeLen returns the len builtin specialized to type func(T)int.
|
||||
func makeLen(T types.Type) *Builtin {
|
||||
lenParams := types.NewTuple(anonVar(T))
|
||||
return &Builtin{
|
||||
name: "len",
|
||||
sig: types.NewSignatureType(nil, nil, nil, lenParams, lenResults, false),
|
||||
sig: types.NewSignatureType(nil, nil, nil, typesinternal.TupleOf(T), lenResults, false),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
47
vendor/golang.org/x/tools/go/ssa/wrappers.go
generated
vendored
47
vendor/golang.org/x/tools/go/ssa/wrappers.go
generated
vendored
@@ -26,6 +26,7 @@ import (
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/internal/typeparams"
|
||||
"golang.org/x/tools/internal/typesinternal"
|
||||
)
|
||||
|
||||
// -- wrappers -----------------------------------------------------------
|
||||
@@ -40,14 +41,14 @@ import (
|
||||
// following axes of variation when making changes:
|
||||
// - optional receiver indirection
|
||||
// - optional implicit field selections
|
||||
// - optional method type arguments
|
||||
// - meth.Obj() may denote a concrete or an interface method
|
||||
// - the result may be a thunk or a wrapper.
|
||||
func createWrapper(prog *Program, sel *selection) *Function {
|
||||
obj := sel.obj.(*types.Func) // the declared function
|
||||
sig := sel.typ.(*types.Signature) // type of this wrapper
|
||||
func createWrapper(prog *Program, sel *selection, targs []types.Type) *Function {
|
||||
obj := sel.obj.(*types.Func) // the declared function
|
||||
name, sig := maybeInstance(prog, obj.Name(), sel.typ.(*types.Signature), targs)
|
||||
|
||||
var recv *types.Var // wrapper's receiver or thunk's params[0]
|
||||
name := obj.Name()
|
||||
var description string
|
||||
if sel.kind == types.MethodExpr {
|
||||
name += "$thunk"
|
||||
@@ -58,7 +59,7 @@ func createWrapper(prog *Program, sel *selection) *Function {
|
||||
recv = sig.Recv()
|
||||
}
|
||||
|
||||
description = fmt.Sprintf("%s for %s", description, sel.obj)
|
||||
description = fmt.Sprintf("%s for %s", description, obj)
|
||||
if prog.mode&LogSource != 0 {
|
||||
defer logStack("create %s to (%s)", description, recv.Type())()
|
||||
}
|
||||
@@ -71,6 +72,7 @@ func createWrapper(prog *Program, sel *selection) *Function {
|
||||
Synthetic: description,
|
||||
Prog: prog,
|
||||
pos: obj.Pos(),
|
||||
typeargs: targs,
|
||||
// wrappers have no syntax
|
||||
build: (*builder).buildWrapper,
|
||||
syntax: nil,
|
||||
@@ -79,6 +81,20 @@ func createWrapper(prog *Program, sel *selection) *Function {
|
||||
}
|
||||
}
|
||||
|
||||
// maybeInstance returns name and sig instantiated to reflect any type arguments in targs.
|
||||
func maybeInstance(prog *Program, name string, sig *types.Signature, targs []types.Type) (string, *types.Signature) {
|
||||
if len(targs) > 0 {
|
||||
name = fmt.Sprintf("%s%s", name, targstr(targs))
|
||||
instSig, err := types.Instantiate(prog.ctxt, sig, targs, false)
|
||||
if err != nil {
|
||||
// validate was false, we should never get an error
|
||||
panic(err)
|
||||
}
|
||||
sig = prog.canon.Type(instSig).(*types.Signature)
|
||||
}
|
||||
return name, sig
|
||||
}
|
||||
|
||||
// buildWrapper builds fn.Body for a method wrapper.
|
||||
func (b *builder) buildWrapper(fn *Function) {
|
||||
var recv *types.Var // wrapper's receiver or thunk's params[0]
|
||||
@@ -103,10 +119,12 @@ func (b *builder) buildWrapper(fn *Function) {
|
||||
// For simple indirection wrappers, perform an informative nil-check:
|
||||
// "value method (T).f called using nil *T pointer"
|
||||
if len(indices) == 1 && !isPointer(recvType(fn.object)) {
|
||||
params := typesinternal.TupleOf(fn.method.recv, tString, tString)
|
||||
results := typesinternal.TupleOf(fn.method.recv)
|
||||
var c Call
|
||||
c.Call.Value = &Builtin{
|
||||
name: "ssa:wrapnilchk",
|
||||
sig: types.NewSignatureType(nil, nil, nil, types.NewTuple(anonVar(fn.method.recv), anonVar(tString), anonVar(tString)), types.NewTuple(anonVar(fn.method.recv)), false),
|
||||
sig: types.NewSignatureType(nil, nil, nil, params, results, false),
|
||||
}
|
||||
c.Call.Args = []Value{
|
||||
v,
|
||||
@@ -137,7 +155,7 @@ func (b *builder) buildWrapper(fn *Function) {
|
||||
if !isPointer(r) {
|
||||
v = emitLoad(fn, v)
|
||||
}
|
||||
c.Call.Value = fn.Prog.objectMethod(fn.object, b)
|
||||
c.Call.Value = fn.Prog.objectMethod(fn.object, fn.typeargs, b)
|
||||
c.Call.Args = append(c.Call.Args, v)
|
||||
} else {
|
||||
c.Call.Method = fn.object
|
||||
@@ -184,19 +202,22 @@ func createParams(fn *Function, start int) {
|
||||
// Unlike createWrapper, createBound need perform no indirection or field
|
||||
// selections because that can be done before the closure is
|
||||
// constructed.
|
||||
func createBound(prog *Program, obj *types.Func) *Function {
|
||||
func createBound(prog *Program, obj *types.Func, targs []types.Type) *Function {
|
||||
description := fmt.Sprintf("bound method wrapper for %s", obj)
|
||||
if prog.mode&LogSource != 0 {
|
||||
defer logStack("%s", description)()
|
||||
}
|
||||
name, sig := maybeInstance(prog, obj.Name(), obj.Type().(*types.Signature), targs)
|
||||
|
||||
/* bound method wrapper */
|
||||
fn := &Function{
|
||||
name: obj.Name() + "$bound",
|
||||
name: name + "$bound",
|
||||
object: obj,
|
||||
Signature: changeRecv(obj.Type().(*types.Signature), nil), // drop receiver
|
||||
Signature: changeRecv(sig, nil), // drop receiver
|
||||
Synthetic: description,
|
||||
Prog: prog,
|
||||
pos: obj.Pos(),
|
||||
typeargs: targs,
|
||||
// wrappers have no syntax
|
||||
build: (*builder).buildBound,
|
||||
syntax: nil,
|
||||
@@ -215,7 +236,7 @@ func (b *builder) buildBound(fn *Function) {
|
||||
|
||||
recv := fn.FreeVars[0]
|
||||
if !types.IsInterface(recvType(fn.object)) { // concrete
|
||||
c.Call.Value = fn.Prog.objectMethod(fn.object, b)
|
||||
c.Call.Value = fn.Prog.objectMethod(fn.object, fn.typeargs, b)
|
||||
c.Call.Args = []Value{recv}
|
||||
} else {
|
||||
c.Call.Method = fn.object
|
||||
@@ -246,12 +267,12 @@ func (b *builder) buildBound(fn *Function) {
|
||||
// f is a synthetic wrapper defined as if by:
|
||||
//
|
||||
// f := func(t T) { return t.meth() }
|
||||
func createThunk(prog *Program, sel *selection) *Function {
|
||||
func createThunk(prog *Program, sel *selection, targs []types.Type) *Function {
|
||||
if sel.kind != types.MethodExpr {
|
||||
panic(sel)
|
||||
}
|
||||
|
||||
fn := createWrapper(prog, sel)
|
||||
fn := createWrapper(prog, sel, targs)
|
||||
if fn.Signature.Recv() != nil {
|
||||
panic(fn) // unexpected receiver
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user