Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / go / ssa / emit.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/go/ssa/emit.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/go/ssa/emit.go
new file mode 100644 (file)
index 0000000..13fe2aa
--- /dev/null
@@ -0,0 +1,468 @@
+// Copyright 2013 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 ssa
+
+// Helpers for emitting SSA instructions.
+
+import (
+       "fmt"
+       "go/ast"
+       "go/token"
+       "go/types"
+)
+
+// emitNew emits to f a new (heap Alloc) instruction allocating an
+// object of type typ.  pos is the optional source location.
+//
+func emitNew(f *Function, typ types.Type, pos token.Pos) *Alloc {
+       v := &Alloc{Heap: true}
+       v.setType(types.NewPointer(typ))
+       v.setPos(pos)
+       f.emit(v)
+       return v
+}
+
+// emitLoad emits to f an instruction to load the address addr into a
+// new temporary, and returns the value so defined.
+//
+func emitLoad(f *Function, addr Value) *UnOp {
+       v := &UnOp{Op: token.MUL, X: addr}
+       v.setType(deref(addr.Type()))
+       f.emit(v)
+       return v
+}
+
+// emitDebugRef emits to f a DebugRef pseudo-instruction associating
+// expression e with value v.
+//
+func emitDebugRef(f *Function, e ast.Expr, v Value, isAddr bool) {
+       if !f.debugInfo() {
+               return // debugging not enabled
+       }
+       if v == nil || e == nil {
+               panic("nil")
+       }
+       var obj types.Object
+       e = unparen(e)
+       if id, ok := e.(*ast.Ident); ok {
+               if isBlankIdent(id) {
+                       return
+               }
+               obj = f.Pkg.objectOf(id)
+               switch obj.(type) {
+               case *types.Nil, *types.Const, *types.Builtin:
+                       return
+               }
+       }
+       f.emit(&DebugRef{
+               X:      v,
+               Expr:   e,
+               IsAddr: isAddr,
+               object: obj,
+       })
+}
+
+// emitArith emits to f code to compute the binary operation op(x, y)
+// where op is an eager shift, logical or arithmetic operation.
+// (Use emitCompare() for comparisons and Builder.logicalBinop() for
+// non-eager operations.)
+//
+func emitArith(f *Function, op token.Token, x, y Value, t types.Type, pos token.Pos) Value {
+       switch op {
+       case token.SHL, token.SHR:
+               x = emitConv(f, x, t)
+               // y may be signed or an 'untyped' constant.
+               // TODO(adonovan): whence signed values?
+               if b, ok := y.Type().Underlying().(*types.Basic); ok && b.Info()&types.IsUnsigned == 0 {
+                       y = emitConv(f, y, types.Typ[types.Uint64])
+               }
+
+       case token.ADD, token.SUB, token.MUL, token.QUO, token.REM, token.AND, token.OR, token.XOR, token.AND_NOT:
+               x = emitConv(f, x, t)
+               y = emitConv(f, y, t)
+
+       default:
+               panic("illegal op in emitArith: " + op.String())
+
+       }
+       v := &BinOp{
+               Op: op,
+               X:  x,
+               Y:  y,
+       }
+       v.setPos(pos)
+       v.setType(t)
+       return f.emit(v)
+}
+
+// emitCompare emits to f code compute the boolean result of
+// comparison comparison 'x op y'.
+//
+func emitCompare(f *Function, op token.Token, x, y Value, pos token.Pos) Value {
+       xt := x.Type().Underlying()
+       yt := y.Type().Underlying()
+
+       // Special case to optimise a tagless SwitchStmt so that
+       // these are equivalent
+       //   switch { case e: ...}
+       //   switch true { case e: ... }
+       //   if e==true { ... }
+       // even in the case when e's type is an interface.
+       // TODO(adonovan): opt: generalise to x==true, false!=y, etc.
+       if x == vTrue && op == token.EQL {
+               if yt, ok := yt.(*types.Basic); ok && yt.Info()&types.IsBoolean != 0 {
+                       return y
+               }
+       }
+
+       if types.Identical(xt, yt) {
+               // no conversion necessary
+       } else if _, ok := xt.(*types.Interface); ok {
+               y = emitConv(f, y, x.Type())
+       } else if _, ok := yt.(*types.Interface); ok {
+               x = emitConv(f, x, y.Type())
+       } else if _, ok := x.(*Const); ok {
+               x = emitConv(f, x, y.Type())
+       } else if _, ok := y.(*Const); ok {
+               y = emitConv(f, y, x.Type())
+       } else {
+               // other cases, e.g. channels.  No-op.
+       }
+
+       v := &BinOp{
+               Op: op,
+               X:  x,
+               Y:  y,
+       }
+       v.setPos(pos)
+       v.setType(tBool)
+       return f.emit(v)
+}
+
+// isValuePreserving returns true if a conversion from ut_src to
+// ut_dst is value-preserving, i.e. just a change of type.
+// Precondition: neither argument is a named type.
+//
+func isValuePreserving(ut_src, ut_dst types.Type) bool {
+       // Identical underlying types?
+       if structTypesIdentical(ut_dst, ut_src) {
+               return true
+       }
+
+       switch ut_dst.(type) {
+       case *types.Chan:
+               // Conversion between channel types?
+               _, ok := ut_src.(*types.Chan)
+               return ok
+
+       case *types.Pointer:
+               // Conversion between pointers with identical base types?
+               _, ok := ut_src.(*types.Pointer)
+               return ok
+       }
+       return false
+}
+
+// emitConv emits to f code to convert Value val to exactly type typ,
+// and returns the converted value.  Implicit conversions are required
+// by language assignability rules in assignments, parameter passing,
+// etc.  Conversions cannot fail dynamically.
+//
+func emitConv(f *Function, val Value, typ types.Type) Value {
+       t_src := val.Type()
+
+       // Identical types?  Conversion is a no-op.
+       if types.Identical(t_src, typ) {
+               return val
+       }
+
+       ut_dst := typ.Underlying()
+       ut_src := t_src.Underlying()
+
+       // Just a change of type, but not value or representation?
+       if isValuePreserving(ut_src, ut_dst) {
+               c := &ChangeType{X: val}
+               c.setType(typ)
+               return f.emit(c)
+       }
+
+       // Conversion to, or construction of a value of, an interface type?
+       if _, ok := ut_dst.(*types.Interface); ok {
+               // Assignment from one interface type to another?
+               if _, ok := ut_src.(*types.Interface); ok {
+                       c := &ChangeInterface{X: val}
+                       c.setType(typ)
+                       return f.emit(c)
+               }
+
+               // Untyped nil constant?  Return interface-typed nil constant.
+               if ut_src == tUntypedNil {
+                       return nilConst(typ)
+               }
+
+               // Convert (non-nil) "untyped" literals to their default type.
+               if t, ok := ut_src.(*types.Basic); ok && t.Info()&types.IsUntyped != 0 {
+                       val = emitConv(f, val, types.Default(ut_src))
+               }
+
+               f.Pkg.Prog.needMethodsOf(val.Type())
+               mi := &MakeInterface{X: val}
+               mi.setType(typ)
+               return f.emit(mi)
+       }
+
+       // Conversion of a compile-time constant value?
+       if c, ok := val.(*Const); ok {
+               if _, ok := ut_dst.(*types.Basic); ok || c.IsNil() {
+                       // Conversion of a compile-time constant to
+                       // another constant type results in a new
+                       // constant of the destination type and
+                       // (initially) the same abstract value.
+                       // We don't truncate the value yet.
+                       return NewConst(c.Value, typ)
+               }
+
+               // We're converting from constant to non-constant type,
+               // e.g. string -> []byte/[]rune.
+       }
+
+       // A representation-changing conversion?
+       // At least one of {ut_src,ut_dst} must be *Basic.
+       // (The other may be []byte or []rune.)
+       _, ok1 := ut_src.(*types.Basic)
+       _, ok2 := ut_dst.(*types.Basic)
+       if ok1 || ok2 {
+               c := &Convert{X: val}
+               c.setType(typ)
+               return f.emit(c)
+       }
+
+       panic(fmt.Sprintf("in %s: cannot convert %s (%s) to %s", f, val, val.Type(), typ))
+}
+
+// emitStore emits to f an instruction to store value val at location
+// addr, applying implicit conversions as required by assignability rules.
+//
+func emitStore(f *Function, addr, val Value, pos token.Pos) *Store {
+       s := &Store{
+               Addr: addr,
+               Val:  emitConv(f, val, deref(addr.Type())),
+               pos:  pos,
+       }
+       f.emit(s)
+       return s
+}
+
+// emitJump emits to f a jump to target, and updates the control-flow graph.
+// Postcondition: f.currentBlock is nil.
+//
+func emitJump(f *Function, target *BasicBlock) {
+       b := f.currentBlock
+       b.emit(new(Jump))
+       addEdge(b, target)
+       f.currentBlock = nil
+}
+
+// emitIf emits to f a conditional jump to tblock or fblock based on
+// cond, and updates the control-flow graph.
+// Postcondition: f.currentBlock is nil.
+//
+func emitIf(f *Function, cond Value, tblock, fblock *BasicBlock) {
+       b := f.currentBlock
+       b.emit(&If{Cond: cond})
+       addEdge(b, tblock)
+       addEdge(b, fblock)
+       f.currentBlock = nil
+}
+
+// emitExtract emits to f an instruction to extract the index'th
+// component of tuple.  It returns the extracted value.
+//
+func emitExtract(f *Function, tuple Value, index int) Value {
+       e := &Extract{Tuple: tuple, Index: index}
+       e.setType(tuple.Type().(*types.Tuple).At(index).Type())
+       return f.emit(e)
+}
+
+// emitTypeAssert emits to f a type assertion value := x.(t) and
+// returns the value.  x.Type() must be an interface.
+//
+func emitTypeAssert(f *Function, x Value, t types.Type, pos token.Pos) Value {
+       a := &TypeAssert{X: x, AssertedType: t}
+       a.setPos(pos)
+       a.setType(t)
+       return f.emit(a)
+}
+
+// emitTypeTest emits to f a type test value,ok := x.(t) and returns
+// a (value, ok) tuple.  x.Type() must be an interface.
+//
+func emitTypeTest(f *Function, x Value, t types.Type, pos token.Pos) Value {
+       a := &TypeAssert{
+               X:            x,
+               AssertedType: t,
+               CommaOk:      true,
+       }
+       a.setPos(pos)
+       a.setType(types.NewTuple(
+               newVar("value", t),
+               varOk,
+       ))
+       return f.emit(a)
+}
+
+// emitTailCall emits to f a function call in tail position.  The
+// caller is responsible for all fields of 'call' except its type.
+// Intended for wrapper methods.
+// Precondition: f does/will not use deferred procedure calls.
+// Postcondition: f.currentBlock is nil.
+//
+func emitTailCall(f *Function, call *Call) {
+       tresults := f.Signature.Results()
+       nr := tresults.Len()
+       if nr == 1 {
+               call.typ = tresults.At(0).Type()
+       } else {
+               call.typ = tresults
+       }
+       tuple := f.emit(call)
+       var ret Return
+       switch nr {
+       case 0:
+               // no-op
+       case 1:
+               ret.Results = []Value{tuple}
+       default:
+               for i := 0; i < nr; i++ {
+                       v := emitExtract(f, tuple, i)
+                       // TODO(adonovan): in principle, this is required:
+                       //   v = emitConv(f, o.Type, f.Signature.Results[i].Type)
+                       // but in practice emitTailCall is only used when
+                       // the types exactly match.
+                       ret.Results = append(ret.Results, v)
+               }
+       }
+       f.emit(&ret)
+       f.currentBlock = nil
+}
+
+// emitImplicitSelections emits to f code to apply the sequence of
+// implicit field selections specified by indices to base value v, and
+// returns the selected value.
+//
+// If v is the address of a struct, the result will be the address of
+// a field; if it is the value of a struct, the result will be the
+// value of a field.
+//
+func emitImplicitSelections(f *Function, v Value, indices []int) Value {
+       for _, index := range indices {
+               fld := deref(v.Type()).Underlying().(*types.Struct).Field(index)
+
+               if isPointer(v.Type()) {
+                       instr := &FieldAddr{
+                               X:     v,
+                               Field: index,
+                       }
+                       instr.setType(types.NewPointer(fld.Type()))
+                       v = f.emit(instr)
+                       // Load the field's value iff indirectly embedded.
+                       if isPointer(fld.Type()) {
+                               v = emitLoad(f, v)
+                       }
+               } else {
+                       instr := &Field{
+                               X:     v,
+                               Field: index,
+                       }
+                       instr.setType(fld.Type())
+                       v = f.emit(instr)
+               }
+       }
+       return v
+}
+
+// emitFieldSelection emits to f code to select the index'th field of v.
+//
+// If wantAddr, the input must be a pointer-to-struct and the result
+// will be the field's address; otherwise the result will be the
+// field's value.
+// Ident id is used for position and debug info.
+//
+func emitFieldSelection(f *Function, v Value, index int, wantAddr bool, id *ast.Ident) Value {
+       fld := deref(v.Type()).Underlying().(*types.Struct).Field(index)
+       if isPointer(v.Type()) {
+               instr := &FieldAddr{
+                       X:     v,
+                       Field: index,
+               }
+               instr.setPos(id.Pos())
+               instr.setType(types.NewPointer(fld.Type()))
+               v = f.emit(instr)
+               // Load the field's value iff we don't want its address.
+               if !wantAddr {
+                       v = emitLoad(f, v)
+               }
+       } else {
+               instr := &Field{
+                       X:     v,
+                       Field: index,
+               }
+               instr.setPos(id.Pos())
+               instr.setType(fld.Type())
+               v = f.emit(instr)
+       }
+       emitDebugRef(f, id, v, wantAddr)
+       return v
+}
+
+// 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)
+       }
+}
+
+// createRecoverBlock emits to f a block of code to return after a
+// recovered panic, and sets f.Recover to it.
+//
+// If f's result parameters are named, the code loads and returns
+// their current values, otherwise it returns the zero values of their
+// type.
+//
+// Idempotent.
+//
+func createRecoverBlock(f *Function) {
+       if f.Recover != nil {
+               return // already created
+       }
+       saved := f.currentBlock
+
+       f.Recover = f.newBasicBlock("recover")
+       f.currentBlock = f.Recover
+
+       var results []Value
+       if f.namedResults != nil {
+               // Reload NRPs to form value tuple.
+               for _, r := range f.namedResults {
+                       results = append(results, emitLoad(f, r))
+               }
+       } else {
+               R := f.Signature.Results()
+               for i, n := 0, R.Len(); i < n; i++ {
+                       T := R.At(i).Type()
+
+                       // Return zero value of each result type.
+                       results = append(results, zeroValue(f, T))
+               }
+       }
+       f.emit(&Return{Results: results})
+
+       f.currentBlock = saved
+}