mirror of
https://github.com/golang/go
synced 2024-11-19 03:44:40 -07:00
cmd/compile: shrink gc.Type in half
Many of Type's fields are etype-specific. This CL organizes them into their own auxiliary types, duplicating a few fields as necessary, and adds an Extra field to hold them. It also sorts the remaining fields for better struct packing. It also improves documentation for most fields. This reduces the size of Type at the cost of some extra allocations. There's no CPU impact; memory impact below. It also makes the natural structure of Type clearer. Passes toolstash -cmp on all architectures. Ideas for future work in this vein: (1) Width and Align probably only need to be stored for Struct and Array types. The refactoring to accomplish this would hopefully also eliminate TFUNCARGS and TCHANARGS entirely. (2) Maplineno is sparsely used and could probably better be stored in a separate map[*Type]int32, with mapqueue updated to store both a Node and a line number. (3) The Printed field may be removable once the old (non-binary) importer/exported has been removed. (4) StructType's fields field could be changed from *[]*Field to []*Field, which would remove a common allocation. (5) I believe that Type.Nod can be moved to ForwardType. Separate CL. name old alloc/op new alloc/op delta Template 57.9MB ± 0% 55.9MB ± 0% -3.43% (p=0.000 n=50+50) Unicode 38.3MB ± 0% 37.8MB ± 0% -1.39% (p=0.000 n=50+50) GoTypes 185MB ± 0% 180MB ± 0% -2.56% (p=0.000 n=50+50) Compiler 824MB ± 0% 806MB ± 0% -2.19% (p=0.000 n=50+50) name old allocs/op new allocs/op delta Template 486k ± 0% 497k ± 0% +2.25% (p=0.000 n=50+50) Unicode 377k ± 0% 379k ± 0% +0.55% (p=0.000 n=50+50) GoTypes 1.39M ± 0% 1.42M ± 0% +1.63% (p=0.000 n=50+50) Compiler 5.52M ± 0% 5.57M ± 0% +0.84% (p=0.000 n=47+50) Change-Id: I828488eeb74902b013d5ae4cf844de0b6c0dfc87 Reviewed-on: https://go-review.googlesource.com/21611 Reviewed-by: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
a25e368f44
commit
f38f43d029
@ -198,11 +198,11 @@ func dowidth(t *Type) {
|
||||
|
||||
// make fake type to check later to
|
||||
// trigger channel argument check.
|
||||
t1 := typWrapper(TCHANARGS, t)
|
||||
t1 := typChanArgs(t)
|
||||
checkwidth(t1)
|
||||
|
||||
case TCHANARGS:
|
||||
t1 := t.Wrapped()
|
||||
t1 := t.ChanArgs()
|
||||
dowidth(t1) // just in case
|
||||
if t1.Elem().Width >= 1<<16 {
|
||||
Yyerror("channel element type too large (>64kB)")
|
||||
@ -271,18 +271,18 @@ func dowidth(t *Type) {
|
||||
// make fake type to check later to
|
||||
// trigger function argument computation.
|
||||
case TFUNC:
|
||||
t1 := typWrapper(TFUNCARGS, t)
|
||||
t1 := typFuncArgs(t)
|
||||
checkwidth(t1)
|
||||
w = int64(Widthptr) // width of func type is pointer
|
||||
|
||||
// function is 3 cated structures;
|
||||
// compute their widths as side-effect.
|
||||
case TFUNCARGS:
|
||||
t1 := t.Wrapped()
|
||||
t1 := t.FuncArgs()
|
||||
w = widstruct(t1, t1.Recvs(), 0, 0)
|
||||
w = widstruct(t1, t1.Params(), w, Widthreg)
|
||||
w = widstruct(t1, t1.Results(), w, Widthreg)
|
||||
t1.Argwid = w
|
||||
t1.Extra.(*FuncType).Argwid = w
|
||||
if w%int64(Widthreg) != 0 {
|
||||
Warn("bad type %v %d\n", t1, w)
|
||||
}
|
||||
@ -386,7 +386,7 @@ func Argsize(t *Type) int {
|
||||
}
|
||||
}
|
||||
|
||||
w = (w + int64(Widthptr) - 1) &^ (int64(Widthptr) - 1)
|
||||
w = Rnd(w, int64(Widthptr))
|
||||
if int64(int(w)) != w {
|
||||
Fatalf("argsize too big")
|
||||
}
|
||||
|
@ -602,7 +602,7 @@ func (p *exporter) typ(t *Type) {
|
||||
case TDDDFIELD:
|
||||
// see p.param use of TDDDFIELD
|
||||
p.tag(dddTag)
|
||||
p.typ(t.Wrapped())
|
||||
p.typ(t.DDDField())
|
||||
|
||||
case TSTRUCT:
|
||||
p.tag(structTag)
|
||||
@ -768,7 +768,7 @@ func (p *exporter) param(q *Field, n int, numbered bool) {
|
||||
t := q.Type
|
||||
if q.Isddd {
|
||||
// create a fake type to encode ... just for the p.typ call
|
||||
t = typWrapper(TDDDFIELD, t.Elem())
|
||||
t = typDDDField(t.Elem())
|
||||
}
|
||||
p.typ(t)
|
||||
if n > 0 {
|
||||
|
@ -359,16 +359,20 @@ func (p *importer) typ() *Type {
|
||||
|
||||
case arrayTag, sliceTag:
|
||||
t = p.newtyp(TARRAY)
|
||||
var bound int64
|
||||
if i == arrayTag {
|
||||
t.SetNumElem(p.int64())
|
||||
} else {
|
||||
t.SetNumElem(sliceBound)
|
||||
bound = p.int64()
|
||||
}
|
||||
elem := p.typ()
|
||||
if i == arrayTag {
|
||||
t.Extra = &ArrayType{Elem: elem, Bound: bound}
|
||||
} else {
|
||||
t.Extra = SliceType{Elem: elem}
|
||||
}
|
||||
t.Type = p.typ()
|
||||
|
||||
case dddTag:
|
||||
t = p.newtyp(TDDDFIELD)
|
||||
t.Type = p.typ()
|
||||
t.Extra = DDDFieldType{T: p.typ()}
|
||||
|
||||
case structTag:
|
||||
t = p.newtyp(TSTRUCT)
|
||||
@ -376,7 +380,7 @@ func (p *importer) typ() *Type {
|
||||
|
||||
case pointerTag:
|
||||
t = p.newtyp(Tptr)
|
||||
t.Type = p.typ()
|
||||
t.Extra = PtrType{Elem: p.typ()}
|
||||
|
||||
case signatureTag:
|
||||
t = p.newtyp(TFUNC)
|
||||
@ -393,13 +397,15 @@ func (p *importer) typ() *Type {
|
||||
|
||||
case mapTag:
|
||||
t = p.newtyp(TMAP)
|
||||
t.Down = p.typ() // key
|
||||
t.Type = p.typ() // val
|
||||
mt := t.MapType()
|
||||
mt.Key = p.typ()
|
||||
mt.Val = p.typ()
|
||||
|
||||
case chanTag:
|
||||
t = p.newtyp(TCHAN)
|
||||
t.Chan = ChanDir(p.int())
|
||||
t.Type = p.typ()
|
||||
ct := t.ChanType()
|
||||
ct.Dir = ChanDir(p.int())
|
||||
ct.Elem = p.typ()
|
||||
|
||||
default:
|
||||
Fatalf("importer: unexpected type (tag = %d)", i)
|
||||
@ -444,7 +450,7 @@ func (p *importer) field() *Node {
|
||||
// anonymous field - typ must be T or *T and T must be a type name
|
||||
s := typ.Sym
|
||||
if s == nil && typ.IsPtr() {
|
||||
s = typ.Type.Sym // deref
|
||||
s = typ.Elem().Sym // deref
|
||||
}
|
||||
pkg := importpkg
|
||||
if sym != nil {
|
||||
@ -531,7 +537,7 @@ func (p *importer) param(named bool) *Node {
|
||||
isddd := false
|
||||
if typ.Etype == TDDDFIELD {
|
||||
// TDDDFIELD indicates wrapped ... slice type
|
||||
typ = typSlice(typ.Wrapped())
|
||||
typ = typSlice(typ.DDDField())
|
||||
isddd = true
|
||||
}
|
||||
|
||||
|
@ -743,8 +743,8 @@ func checkembeddedtype(t *Type) {
|
||||
|
||||
if t.IsPtr() {
|
||||
Yyerror("embedded type cannot be a pointer")
|
||||
} else if t.Etype == TFORW && t.Embedlineno == 0 {
|
||||
t.Embedlineno = lineno
|
||||
} else if t.Etype == TFORW && t.ForwardType().Embedlineno == 0 {
|
||||
t.ForwardType().Embedlineno = lineno
|
||||
}
|
||||
}
|
||||
|
||||
@ -855,7 +855,7 @@ func tostruct0(t *Type, l []*Node) {
|
||||
|
||||
func tofunargs(l []*Node) *Type {
|
||||
t := typ(TSTRUCT)
|
||||
t.Funarg = true
|
||||
t.StructType().Funarg = true
|
||||
|
||||
fields := make([]*Field, len(l))
|
||||
for i, n := range l {
|
||||
@ -1061,11 +1061,11 @@ func functype0(t *Type, this *Node, in, out []*Node) {
|
||||
t.Broke = true
|
||||
}
|
||||
|
||||
t.Outnamed = false
|
||||
t.FuncType().Outnamed = false
|
||||
if len(out) > 0 && out[0].Left != nil && out[0].Left.Orig != nil {
|
||||
s := out[0].Left.Orig.Sym
|
||||
if s != nil && (s.Name[0] != '~' || s.Name[1] != 'r') { // ~r%d is the name invented for an unnamed result
|
||||
t.Outnamed = true
|
||||
t.FuncType().Outnamed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -592,7 +592,7 @@ func dumpasmhdr() {
|
||||
|
||||
case OTYPE:
|
||||
t := n.Type
|
||||
if !t.IsStruct() || t.Map != nil || t.IsFuncArgStruct() {
|
||||
if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() {
|
||||
break
|
||||
}
|
||||
fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width))
|
||||
|
@ -671,19 +671,20 @@ func typefmt(t *Type, flag FmtFlag) string {
|
||||
return buf.String()
|
||||
|
||||
case TSTRUCT:
|
||||
if t.Map != nil {
|
||||
if m := t.StructType().Map; m != nil {
|
||||
mt := m.MapType()
|
||||
// Format the bucket struct for map[x]y as map.bucket[x]y.
|
||||
// This avoids a recursive print that generates very long names.
|
||||
if t.Map.Bucket == t {
|
||||
return "map.bucket[" + t.Map.Key().String() + "]" + t.Map.Val().String()
|
||||
if mt.Bucket == t {
|
||||
return "map.bucket[" + m.Key().String() + "]" + m.Val().String()
|
||||
}
|
||||
|
||||
if t.Map.Hmap == t {
|
||||
return "map.hdr[" + t.Map.Key().String() + "]" + t.Map.Val().String()
|
||||
if mt.Hmap == t {
|
||||
return "map.hdr[" + m.Key().String() + "]" + m.Val().String()
|
||||
}
|
||||
|
||||
if t.Map.Hiter == t {
|
||||
return "map.iter[" + t.Map.Key().String() + "]" + t.Map.Val().String()
|
||||
if mt.Hiter == t {
|
||||
return "map.iter[" + m.Key().String() + "]" + m.Val().String()
|
||||
}
|
||||
|
||||
Yyerror("unknown internal map type")
|
||||
@ -735,7 +736,7 @@ func typefmt(t *Type, flag FmtFlag) string {
|
||||
if fmtmode == FExp {
|
||||
Fatalf("cannot use TDDDFIELD with old exporter")
|
||||
}
|
||||
return fmt.Sprintf("%v <%v> %v", Econv(t.Etype), t.Sym, t.Wrapped())
|
||||
return fmt.Sprintf("%v <%v> %v", Econv(t.Etype), t.Sym, t.DDDField())
|
||||
}
|
||||
|
||||
if fmtmode == FExp {
|
||||
|
@ -375,7 +375,7 @@ func compile(fn *Node) {
|
||||
// set up domain for labels
|
||||
clearlabels()
|
||||
|
||||
if Curfn.Type.Outnamed {
|
||||
if Curfn.Type.FuncType().Outnamed {
|
||||
// add clearing of the output parameters
|
||||
for _, t := range Curfn.Type.Results().Fields().Slice() {
|
||||
if t.Nname != nil {
|
||||
|
@ -10,6 +10,14 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func typeWithoutPointers() *Type {
|
||||
return &Type{Etype: TSTRUCT, Extra: &StructType{Haspointers: 1}} // haspointers -> false
|
||||
}
|
||||
|
||||
func typeWithPointers() *Type {
|
||||
return &Type{Etype: TSTRUCT, Extra: &StructType{Haspointers: 2}} // haspointers -> true
|
||||
}
|
||||
|
||||
// Test all code paths for cmpstackvarlt.
|
||||
func TestCmpstackvar(t *testing.T) {
|
||||
testdata := []struct {
|
||||
@ -62,13 +70,13 @@ func TestCmpstackvar(t *testing.T) {
|
||||
false,
|
||||
},
|
||||
{
|
||||
Node{Class: PAUTO, Type: &Type{Haspointers: 1}}, // haspointers -> false
|
||||
Node{Class: PAUTO, Type: &Type{Haspointers: 2}}, // haspointers -> true
|
||||
Node{Class: PAUTO, Type: typeWithoutPointers()},
|
||||
Node{Class: PAUTO, Type: typeWithPointers()},
|
||||
false,
|
||||
},
|
||||
{
|
||||
Node{Class: PAUTO, Type: &Type{Haspointers: 2}}, // haspointers -> true
|
||||
Node{Class: PAUTO, Type: &Type{Haspointers: 1}}, // haspointers -> false
|
||||
Node{Class: PAUTO, Type: typeWithPointers()},
|
||||
Node{Class: PAUTO, Type: typeWithoutPointers()},
|
||||
true,
|
||||
},
|
||||
{
|
||||
@ -127,7 +135,7 @@ func TestStackvarSort(t *testing.T) {
|
||||
{Class: PFUNC, Xoffset: 10, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
|
||||
{Class: PFUNC, Xoffset: 20, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
|
||||
{Class: PAUTO, Used: true, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
|
||||
{Class: PAUTO, Type: &Type{Haspointers: 1}, Name: &Name{}, Sym: &Sym{}}, // haspointers -> false
|
||||
{Class: PAUTO, Type: typeWithoutPointers(), Name: &Name{}, Sym: &Sym{}},
|
||||
{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
|
||||
{Class: PAUTO, Type: &Type{}, Name: &Name{Needzero: true}, Sym: &Sym{}},
|
||||
{Class: PAUTO, Type: &Type{Width: 1}, Name: &Name{}, Sym: &Sym{}},
|
||||
@ -148,7 +156,7 @@ func TestStackvarSort(t *testing.T) {
|
||||
{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
|
||||
{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "abc"}},
|
||||
{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "xyz"}},
|
||||
{Class: PAUTO, Type: &Type{Haspointers: 1}, Name: &Name{}, Sym: &Sym{}}, // haspointers -> false
|
||||
{Class: PAUTO, Type: typeWithoutPointers(), Name: &Name{}, Sym: &Sym{}},
|
||||
}
|
||||
// haspointers updates Type.Haspointers as a side effect, so
|
||||
// exercise this function on all inputs so that reflect.DeepEqual
|
||||
|
@ -86,8 +86,8 @@ func makefield(name string, t *Type) *Field {
|
||||
}
|
||||
|
||||
func mapbucket(t *Type) *Type {
|
||||
if t.Bucket != nil {
|
||||
return t.Bucket
|
||||
if t.MapType().Bucket != nil {
|
||||
return t.MapType().Bucket
|
||||
}
|
||||
|
||||
bucket := typ(TSTRUCT)
|
||||
@ -157,17 +157,17 @@ func mapbucket(t *Type) *Type {
|
||||
Yyerror("bad math in mapbucket for %v", t)
|
||||
}
|
||||
|
||||
t.Bucket = bucket
|
||||
t.MapType().Bucket = bucket
|
||||
|
||||
bucket.Map = t
|
||||
bucket.StructType().Map = t
|
||||
return bucket
|
||||
}
|
||||
|
||||
// Builds a type representing a Hmap structure for the given map type.
|
||||
// Make sure this stays in sync with ../../../../runtime/hashmap.go!
|
||||
func hmap(t *Type) *Type {
|
||||
if t.Hmap != nil {
|
||||
return t.Hmap
|
||||
if t.MapType().Hmap != nil {
|
||||
return t.MapType().Hmap
|
||||
}
|
||||
|
||||
bucket := mapbucket(t)
|
||||
@ -186,14 +186,14 @@ func hmap(t *Type) *Type {
|
||||
h.Local = t.Local
|
||||
h.SetFields(field[:])
|
||||
dowidth(h)
|
||||
t.Hmap = h
|
||||
h.Map = t
|
||||
t.MapType().Hmap = h
|
||||
h.StructType().Map = t
|
||||
return h
|
||||
}
|
||||
|
||||
func hiter(t *Type) *Type {
|
||||
if t.Hiter != nil {
|
||||
return t.Hiter
|
||||
if t.MapType().Hiter != nil {
|
||||
return t.MapType().Hiter
|
||||
}
|
||||
|
||||
// build a struct:
|
||||
@ -234,8 +234,8 @@ func hiter(t *Type) *Type {
|
||||
if i.Width != int64(12*Widthptr) {
|
||||
Yyerror("hash_iter size not correct %d %d", i.Width, 12*Widthptr)
|
||||
}
|
||||
t.Hiter = i
|
||||
i.Map = t
|
||||
t.MapType().Hiter = i
|
||||
i.StructType().Map = t
|
||||
return i
|
||||
}
|
||||
|
||||
@ -664,67 +664,47 @@ var kinds = []int{
|
||||
}
|
||||
|
||||
func haspointers(t *Type) bool {
|
||||
if t.Haspointers != 0 {
|
||||
return t.Haspointers-1 != 0
|
||||
}
|
||||
|
||||
var ret bool
|
||||
switch t.Etype {
|
||||
case TINT,
|
||||
TUINT,
|
||||
TINT8,
|
||||
TUINT8,
|
||||
TINT16,
|
||||
TUINT16,
|
||||
TINT32,
|
||||
TUINT32,
|
||||
TINT64,
|
||||
TUINT64,
|
||||
TUINTPTR,
|
||||
TFLOAT32,
|
||||
TFLOAT64,
|
||||
TCOMPLEX64,
|
||||
TCOMPLEX128,
|
||||
TBOOL:
|
||||
ret = false
|
||||
case TINT, TUINT, TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64,
|
||||
TUINT64, TUINTPTR, TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, TBOOL:
|
||||
return false
|
||||
|
||||
case TARRAY:
|
||||
if t.IsSlice() {
|
||||
ret = true
|
||||
break
|
||||
return true
|
||||
}
|
||||
|
||||
if t.NumElem() == 0 { // empty array
|
||||
ret = false
|
||||
break
|
||||
at := t.Extra.(*ArrayType)
|
||||
if at.Haspointers != 0 {
|
||||
return at.Haspointers-1 != 0
|
||||
}
|
||||
|
||||
ret = haspointers(t.Elem())
|
||||
ret := false
|
||||
if t.NumElem() != 0 { // non-empty array
|
||||
ret = haspointers(t.Elem())
|
||||
}
|
||||
|
||||
at.Haspointers = 1 + uint8(obj.Bool2int(ret))
|
||||
return ret
|
||||
|
||||
case TSTRUCT:
|
||||
ret = false
|
||||
st := t.StructType()
|
||||
if st.Haspointers != 0 {
|
||||
return st.Haspointers-1 != 0
|
||||
}
|
||||
|
||||
ret := false
|
||||
for _, t1 := range t.Fields().Slice() {
|
||||
if haspointers(t1.Type) {
|
||||
ret = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
case TSTRING,
|
||||
TPTR32,
|
||||
TPTR64,
|
||||
TUNSAFEPTR,
|
||||
TINTER,
|
||||
TCHAN,
|
||||
TMAP,
|
||||
TFUNC:
|
||||
fallthrough
|
||||
default:
|
||||
ret = true
|
||||
st.Haspointers = 1 + uint8(obj.Bool2int(ret))
|
||||
return ret
|
||||
}
|
||||
|
||||
t.Haspointers = 1 + uint8(obj.Bool2int(ret))
|
||||
return ret
|
||||
return true
|
||||
}
|
||||
|
||||
// typeptrdata returns the length in bytes of the prefix of t
|
||||
|
@ -27,7 +27,21 @@ func TestSizeof(t *testing.T) {
|
||||
{Name{}, 52, 80},
|
||||
{Node{}, 92, 144},
|
||||
{Sym{}, 60, 112},
|
||||
{Type{}, 116, 184},
|
||||
{Type{}, 56, 88},
|
||||
{MapType{}, 20, 40},
|
||||
{ForwardType{}, 16, 32},
|
||||
{FuncType{}, 28, 48},
|
||||
{StructType{}, 12, 24},
|
||||
{InterType{}, 4, 8},
|
||||
{ChanType{}, 8, 16},
|
||||
{ArrayType{}, 16, 24},
|
||||
{InterMethType{}, 4, 8},
|
||||
{DDDFieldType{}, 4, 8},
|
||||
{FuncArgsType{}, 4, 8},
|
||||
{ChanArgsType{}, 4, 8},
|
||||
{PtrType{}, 4, 8},
|
||||
{SliceType{}, 4, 8},
|
||||
{DDDArrayType{}, 4, 8},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
@ -4218,7 +4218,7 @@ func (e *ssaExport) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.Local
|
||||
|
||||
func (e *ssaExport) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
|
||||
n := name.N.(*Node)
|
||||
ptrType := Ptrto(n.Type.Type)
|
||||
ptrType := Ptrto(n.Type.Elem())
|
||||
lenType := Types[TINT]
|
||||
if n.Class == PAUTO && !n.Addrtaken {
|
||||
// Split this slice up into three separate variables.
|
||||
|
@ -122,55 +122,174 @@ var (
|
||||
|
||||
// A Type represents a Go type.
|
||||
type Type struct {
|
||||
Etype EType
|
||||
Noalg bool
|
||||
Chan ChanDir
|
||||
Trecur uint8 // to detect loops
|
||||
Printed bool
|
||||
Funarg bool // TSTRUCT only: whether this struct represents function parameters
|
||||
Local bool // created in this file
|
||||
Deferwidth bool
|
||||
Broke bool // broken type definition.
|
||||
Align uint8
|
||||
Haspointers uint8 // 0 unknown, 1 no, 2 yes
|
||||
Outnamed bool // on TFUNC
|
||||
// Extra contains extra etype-specific fields.
|
||||
// As an optimization, those etype-specific structs which contain exactly
|
||||
// one pointer-shaped field are stored as values rather than pointers when possible.
|
||||
//
|
||||
// TMAP: *MapType
|
||||
// TFORW: *ForwardType
|
||||
// TFUNC: *FuncType
|
||||
// TINTERMETHOD: InterMethType
|
||||
// TSTRUCT: *StructType
|
||||
// TINTER: *InterType
|
||||
// TDDDFIELD: DDDFieldType
|
||||
// TFUNCARGS: FuncArgsType
|
||||
// TCHANARGS: ChanArgsType
|
||||
// TCHAN: *ChanType
|
||||
// TPTR32, TPTR64: PtrType
|
||||
// TARRAY: *ArrayType, SliceType, or DDDArrayType
|
||||
Extra interface{}
|
||||
|
||||
Nod *Node // canonical OTYPE node
|
||||
Orig *Type // original type (type literal or predefined type)
|
||||
// Width is the width of this Type in bytes.
|
||||
Width int64
|
||||
|
||||
methods Fields
|
||||
allMethods Fields
|
||||
|
||||
Sym *Sym
|
||||
Vargen int32 // unique name for OTYPE/ONAME
|
||||
Lineno int32
|
||||
Nod *Node // canonical OTYPE node
|
||||
Orig *Type // original type (type literal or predefined type)
|
||||
|
||||
nname *Node
|
||||
Sym *Sym // symbol containing name, for named types
|
||||
Vargen int32 // unique name for OTYPE/ONAME
|
||||
Lineno int32 // line at which this type was declared, implicitly or explicitly
|
||||
|
||||
Maplineno int32 // first use of this type as a map key
|
||||
|
||||
Etype EType // kind of type
|
||||
Noalg bool // suppress hash and eq algorithm generation
|
||||
Trecur uint8 // to detect loops
|
||||
Printed bool // prevent duplicate export printing
|
||||
Local bool // created in this file
|
||||
Deferwidth bool
|
||||
Broke bool // broken type definition.
|
||||
Align uint8 // the required alignment of this type, in bytes
|
||||
}
|
||||
|
||||
// MapType contains Type fields specific to maps.
|
||||
type MapType struct {
|
||||
Key *Type // Key type
|
||||
Val *Type // Val (elem) type
|
||||
|
||||
Bucket *Type // internal struct type representing a hash bucket
|
||||
Hmap *Type // internal struct type representing the Hmap (map header object)
|
||||
Hiter *Type // internal struct type representing hash iterator state
|
||||
}
|
||||
|
||||
// MapType returns t's extra map-specific fields.
|
||||
func (t *Type) MapType() *MapType {
|
||||
t.wantEtype(TMAP)
|
||||
return t.Extra.(*MapType)
|
||||
}
|
||||
|
||||
// ForwardType contains Type fields specific to forward types.
|
||||
type ForwardType struct {
|
||||
Copyto []*Node // where to copy the eventual value to
|
||||
Embedlineno int32 // first use of this type as an embedded type
|
||||
}
|
||||
|
||||
// ForwardType returns t's extra forward-type-specific fields.
|
||||
func (t *Type) ForwardType() *ForwardType {
|
||||
t.wantEtype(TFORW)
|
||||
return t.Extra.(*ForwardType)
|
||||
}
|
||||
|
||||
// FuncType contains Type fields specific to func types.
|
||||
type FuncType struct {
|
||||
Receiver *Type // function receiver
|
||||
Results *Type // function results
|
||||
Params *Type // function params
|
||||
|
||||
Nname *Node
|
||||
|
||||
// Argwid is the total width of the function receiver, params, and results.
|
||||
// It gets calculated via a temporary TFUNCARGS type.
|
||||
// Note that TFUNC's Width is Widthptr.
|
||||
Argwid int64
|
||||
|
||||
// most nodes
|
||||
Type *Type // element type for TARRAY, TCHAN, TMAP, TPTRxx
|
||||
Width int64
|
||||
Outnamed bool
|
||||
}
|
||||
|
||||
// TSTRUCT
|
||||
// FuncType returns t's extra func-specific fields.
|
||||
func (t *Type) FuncType() *FuncType {
|
||||
t.wantEtype(TFUNC)
|
||||
return t.Extra.(*FuncType)
|
||||
}
|
||||
|
||||
// InterMethType contains Type fields specific to interface method psuedo-types.
|
||||
type InterMethType struct {
|
||||
Nname *Node
|
||||
}
|
||||
|
||||
// StructType contains Type fields specific to struct types.
|
||||
type StructType struct {
|
||||
fields Fields
|
||||
|
||||
Down *Type // key type in TMAP; next struct in Funarg TSTRUCT
|
||||
// Maps have three associated internal structs (see struct MapType).
|
||||
// Map links such structs back to their map type.
|
||||
Map *Type
|
||||
|
||||
// TARRAY
|
||||
Bound int64 // negative is slice
|
||||
Funarg bool // whether this struct represents function parameters
|
||||
Haspointers uint8 // 0 unknown, 1 no, 2 yes
|
||||
}
|
||||
|
||||
// TMAP
|
||||
Bucket *Type // internal type representing a hash bucket
|
||||
Hmap *Type // internal type representing a Hmap (map header object)
|
||||
Hiter *Type // internal type representing hash iterator state
|
||||
Map *Type // link from the above 3 internal types back to the map type.
|
||||
// StructType returns t's extra struct-specific fields.
|
||||
func (t *Type) StructType() *StructType {
|
||||
t.wantEtype(TSTRUCT)
|
||||
return t.Extra.(*StructType)
|
||||
}
|
||||
|
||||
Maplineno int32 // first use of TFORW as map key
|
||||
Embedlineno int32 // first use of TFORW as embedded type
|
||||
// InterType contains Type fields specific to interface types.
|
||||
type InterType struct {
|
||||
fields Fields
|
||||
}
|
||||
|
||||
// for TFORW, where to copy the eventual value to
|
||||
Copyto []*Node
|
||||
// PtrType contains Type fields specific to pointer types.
|
||||
type PtrType struct {
|
||||
Elem *Type // element type
|
||||
}
|
||||
|
||||
// DDDFieldType contains Type fields specific to TDDDFIELD types.
|
||||
type DDDFieldType struct {
|
||||
T *Type // reference to a slice type for ... args
|
||||
}
|
||||
|
||||
// ChanArgsType contains Type fields specific to TCHANARGS types.
|
||||
type ChanArgsType struct {
|
||||
T *Type // reference to a chan type whose elements need a width check
|
||||
}
|
||||
|
||||
// // FuncArgsType contains Type fields specific to TFUNCARGS types.
|
||||
type FuncArgsType struct {
|
||||
T *Type // reference to a func type whose elements need a width check
|
||||
}
|
||||
|
||||
// ChanType contains Type fields specific to channel types.
|
||||
type ChanType struct {
|
||||
Elem *Type // element type
|
||||
Dir ChanDir // channel direction
|
||||
}
|
||||
|
||||
// ChanType returns t's extra channel-specific fields.
|
||||
func (t *Type) ChanType() *ChanType {
|
||||
t.wantEtype(TCHAN)
|
||||
return t.Extra.(*ChanType)
|
||||
}
|
||||
|
||||
// ArrayType contains Type fields specific to array types with known lengths.
|
||||
type ArrayType struct {
|
||||
Elem *Type // element type
|
||||
Bound int64 // number of elements; always >= 0; do not use with sliceBound or dddBound
|
||||
Haspointers uint8 // 0 unknown, 1 no, 2 yes
|
||||
}
|
||||
|
||||
// SliceType contains Type fields specific to slice types.
|
||||
type SliceType struct {
|
||||
Elem *Type // element type
|
||||
}
|
||||
|
||||
// DDDArrayType contains Type fields specific to ddd array types.
|
||||
type DDDArrayType struct {
|
||||
Elem *Type // element type
|
||||
}
|
||||
|
||||
// A Field represents a field in a struct or a method in an interface or
|
||||
@ -252,38 +371,61 @@ func typ(et EType) *Type {
|
||||
Lineno: lineno,
|
||||
}
|
||||
t.Orig = t
|
||||
// TODO(josharian): lazily initialize some of these?
|
||||
switch t.Etype {
|
||||
case TMAP:
|
||||
t.Extra = new(MapType)
|
||||
case TFORW:
|
||||
t.Extra = new(ForwardType)
|
||||
case TFUNC:
|
||||
t.Extra = new(FuncType)
|
||||
case TINTERMETH:
|
||||
t.Extra = InterMethType{}
|
||||
case TSTRUCT:
|
||||
t.Extra = new(StructType)
|
||||
case TINTER:
|
||||
t.Extra = new(InterType)
|
||||
case TPTR32, TPTR64:
|
||||
t.Extra = PtrType{}
|
||||
case TCHANARGS:
|
||||
t.Extra = ChanArgsType{}
|
||||
case TFUNCARGS:
|
||||
t.Extra = FuncArgsType{}
|
||||
case TDDDFIELD:
|
||||
t.Extra = DDDFieldType{}
|
||||
case TCHAN:
|
||||
t.Extra = new(ChanType)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// typArray returns a new fixed-length array Type.
|
||||
func typArray(elem *Type, bound int64) *Type {
|
||||
t := typ(TARRAY)
|
||||
t.Type = elem
|
||||
t.Bound = bound
|
||||
t.Extra = &ArrayType{Elem: elem, Bound: bound}
|
||||
return t
|
||||
}
|
||||
|
||||
// typSlice returns a new slice Type.
|
||||
func typSlice(elem *Type) *Type {
|
||||
t := typ(TARRAY)
|
||||
t.Type = elem
|
||||
t.Bound = sliceBound
|
||||
t.Extra = SliceType{Elem: elem}
|
||||
return t
|
||||
}
|
||||
|
||||
// typDDDArray returns a new [...]T array Type.
|
||||
func typDDDArray(elem *Type) *Type {
|
||||
t := typ(TARRAY)
|
||||
t.Type = elem
|
||||
t.Bound = dddBound
|
||||
t.Extra = DDDArrayType{Elem: elem}
|
||||
return t
|
||||
}
|
||||
|
||||
// typChan returns a new chan Type with direction dir.
|
||||
func typChan(elem *Type, dir ChanDir) *Type {
|
||||
t := typ(TCHAN)
|
||||
t.Type = elem
|
||||
t.Chan = dir
|
||||
ct := t.ChanType()
|
||||
ct.Elem = elem
|
||||
ct.Dir = dir
|
||||
return t
|
||||
}
|
||||
|
||||
@ -294,29 +436,39 @@ func typMap(k, v *Type) *Type {
|
||||
}
|
||||
|
||||
t := typ(TMAP)
|
||||
t.Down = k
|
||||
t.Type = v
|
||||
mt := t.MapType()
|
||||
mt.Key = k
|
||||
mt.Val = v
|
||||
return t
|
||||
}
|
||||
|
||||
// typPtr returns a new pointer type pointing to t.
|
||||
func typPtr(elem *Type) *Type {
|
||||
t := typ(Tptr)
|
||||
t.Type = elem
|
||||
t.Extra = PtrType{Elem: elem}
|
||||
t.Width = int64(Widthptr)
|
||||
t.Align = uint8(Widthptr)
|
||||
return t
|
||||
}
|
||||
|
||||
// typWrapper returns a new wrapper psuedo-type.
|
||||
func typWrapper(et EType, wrapped *Type) *Type {
|
||||
switch et {
|
||||
case TCHANARGS, TFUNCARGS, TDDDFIELD:
|
||||
default:
|
||||
Fatalf("typWrapper bad etype %s", et)
|
||||
}
|
||||
t := typ(et)
|
||||
t.Type = wrapped
|
||||
// typDDDField returns a new TDDDFIELD type for slice type s.
|
||||
func typDDDField(s *Type) *Type {
|
||||
t := typ(TDDDFIELD)
|
||||
t.Extra = DDDFieldType{T: s}
|
||||
return t
|
||||
}
|
||||
|
||||
// typChanArgs returns a new TCHANARGS type for channel type c.
|
||||
func typChanArgs(c *Type) *Type {
|
||||
t := typ(TCHANARGS)
|
||||
t.Extra = ChanArgsType{T: c}
|
||||
return t
|
||||
}
|
||||
|
||||
// typFuncArgs returns a new TFUNCARGS type for func type f.
|
||||
func typFuncArgs(f *Type) *Type {
|
||||
t := typ(TFUNCARGS)
|
||||
t.Extra = FuncArgsType{T: f}
|
||||
return t
|
||||
}
|
||||
|
||||
@ -362,20 +514,43 @@ func substAny(t *Type, types *[]*Type) *Type {
|
||||
t = (*types)[0]
|
||||
*types = (*types)[1:]
|
||||
|
||||
case TPTR32, TPTR64, TCHAN, TARRAY:
|
||||
elem := substAny(t.Type, types)
|
||||
if elem != t.Type {
|
||||
case TPTR32, TPTR64:
|
||||
elem := substAny(t.Elem(), types)
|
||||
if elem != t.Elem() {
|
||||
t = t.Copy()
|
||||
t.Type = elem
|
||||
t.Extra = PtrType{Elem: elem}
|
||||
}
|
||||
|
||||
case TARRAY:
|
||||
elem := substAny(t.Elem(), types)
|
||||
if elem != t.Elem() {
|
||||
t = t.Copy()
|
||||
switch x := t.Extra.(type) {
|
||||
case *ArrayType:
|
||||
x.Elem = elem
|
||||
case SliceType:
|
||||
t.Extra = SliceType{Elem: elem}
|
||||
case DDDArrayType:
|
||||
t.Extra = DDDArrayType{Elem: elem}
|
||||
default:
|
||||
Fatalf("substAny bad array elem type %T %v", x, t)
|
||||
}
|
||||
}
|
||||
|
||||
case TCHAN:
|
||||
elem := substAny(t.Elem(), types)
|
||||
if elem != t.Elem() {
|
||||
t = t.Copy()
|
||||
t.Extra.(*ChanType).Elem = elem
|
||||
}
|
||||
|
||||
case TMAP:
|
||||
key := substAny(t.Down, types)
|
||||
val := substAny(t.Type, types)
|
||||
if key != t.Down || val != t.Type {
|
||||
key := substAny(t.Key(), types)
|
||||
val := substAny(t.Val(), types)
|
||||
if key != t.Key() || val != t.Val() {
|
||||
t = t.Copy()
|
||||
t.Down = key
|
||||
t.Type = val
|
||||
t.Extra.(*MapType).Key = key
|
||||
t.Extra.(*MapType).Val = val
|
||||
}
|
||||
|
||||
case TFUNC:
|
||||
@ -426,6 +601,32 @@ func (t *Type) Copy() *Type {
|
||||
return nil
|
||||
}
|
||||
nt := *t
|
||||
// copy any *T Extra fields, to avoid aliasing
|
||||
switch t.Etype {
|
||||
case TMAP:
|
||||
x := *t.Extra.(*MapType)
|
||||
nt.Extra = &x
|
||||
case TFORW:
|
||||
x := *t.Extra.(*ForwardType)
|
||||
nt.Extra = &x
|
||||
case TFUNC:
|
||||
x := *t.Extra.(*FuncType)
|
||||
nt.Extra = &x
|
||||
case TSTRUCT:
|
||||
x := *t.Extra.(*StructType)
|
||||
nt.Extra = &x
|
||||
case TINTER:
|
||||
x := *t.Extra.(*InterType)
|
||||
nt.Extra = &x
|
||||
case TCHAN:
|
||||
x := *t.Extra.(*ChanType)
|
||||
nt.Extra = &x
|
||||
case TARRAY:
|
||||
if arr, ok := t.Extra.(*ArrayType); ok {
|
||||
x := *arr
|
||||
nt.Extra = &x
|
||||
}
|
||||
}
|
||||
// TODO(mdempsky): Find out why this is necessary and explain.
|
||||
if t.Orig == t {
|
||||
nt.Orig = &nt
|
||||
@ -483,17 +684,17 @@ func (t *Type) wantEtype2(et1, et2 EType) {
|
||||
|
||||
func (t *Type) RecvsP() **Type {
|
||||
t.wantEtype(TFUNC)
|
||||
return &t.Type
|
||||
return &t.Extra.(*FuncType).Receiver
|
||||
}
|
||||
|
||||
func (t *Type) ParamsP() **Type {
|
||||
t.wantEtype(TFUNC)
|
||||
return &t.Type.Down.Down
|
||||
return &t.Extra.(*FuncType).Params
|
||||
}
|
||||
|
||||
func (t *Type) ResultsP() **Type {
|
||||
t.wantEtype(TFUNC)
|
||||
return &t.Type.Down
|
||||
return &t.Extra.(*FuncType).Results
|
||||
}
|
||||
|
||||
func (t *Type) Recvs() *Type { return *t.RecvsP() }
|
||||
@ -524,51 +725,82 @@ var paramsResults = [2]func(*Type) *Type{
|
||||
// Key returns the key type of map type t.
|
||||
func (t *Type) Key() *Type {
|
||||
t.wantEtype(TMAP)
|
||||
return t.Down
|
||||
return t.Extra.(*MapType).Key
|
||||
}
|
||||
|
||||
// Val returns the value type of map type t.
|
||||
func (t *Type) Val() *Type {
|
||||
t.wantEtype(TMAP)
|
||||
return t.Type
|
||||
return t.Extra.(*MapType).Val
|
||||
}
|
||||
|
||||
// Elem returns the type of elements of t.
|
||||
// Usable with pointers, channels, arrays, and slices.
|
||||
func (t *Type) Elem() *Type {
|
||||
switch t.Etype {
|
||||
case TPTR32, TPTR64, TCHAN, TARRAY:
|
||||
default:
|
||||
Fatalf("Type.Elem %s", t.Etype)
|
||||
case TPTR32, TPTR64:
|
||||
return t.Extra.(PtrType).Elem
|
||||
case TARRAY:
|
||||
switch t := t.Extra.(type) {
|
||||
case *ArrayType:
|
||||
return t.Elem
|
||||
case SliceType:
|
||||
return t.Elem
|
||||
case DDDArrayType:
|
||||
return t.Elem
|
||||
}
|
||||
case TCHAN:
|
||||
return t.Extra.(*ChanType).Elem
|
||||
}
|
||||
return t.Type
|
||||
Fatalf("Type.Elem %s", t.Etype)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Wrapped returns the type that pseudo-type t wraps.
|
||||
func (t *Type) Wrapped() *Type {
|
||||
switch t.Etype {
|
||||
case TCHANARGS, TFUNCARGS, TDDDFIELD:
|
||||
default:
|
||||
Fatalf("Type.Wrapped %s", t.Etype)
|
||||
}
|
||||
return t.Type
|
||||
// DDDField returns the slice ... type for TDDDFIELD type t.
|
||||
func (t *Type) DDDField() *Type {
|
||||
t.wantEtype(TDDDFIELD)
|
||||
return t.Extra.(DDDFieldType).T
|
||||
}
|
||||
|
||||
// ChanArgs returns the channel type for TCHANARGS type t.
|
||||
func (t *Type) ChanArgs() *Type {
|
||||
t.wantEtype(TCHANARGS)
|
||||
return t.Extra.(ChanArgsType).T
|
||||
}
|
||||
|
||||
// FuncArgs returns the channel type for TFUNCARGS type t.
|
||||
func (t *Type) FuncArgs() *Type {
|
||||
t.wantEtype(TFUNCARGS)
|
||||
return t.Extra.(FuncArgsType).T
|
||||
}
|
||||
|
||||
// Nname returns the associated function's nname.
|
||||
func (t *Type) Nname() *Node {
|
||||
t.wantEtype2(TFUNC, TINTERMETH)
|
||||
return t.nname
|
||||
switch t.Etype {
|
||||
case TFUNC:
|
||||
return t.Extra.(*FuncType).Nname
|
||||
case TINTERMETH:
|
||||
return t.Extra.(InterMethType).Nname
|
||||
}
|
||||
Fatalf("Type.Nname %v %v", t.Etype, t)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Nname sets the associated function's nname.
|
||||
func (t *Type) SetNname(n *Node) {
|
||||
t.wantEtype2(TFUNC, TINTERMETH)
|
||||
t.nname = n
|
||||
switch t.Etype {
|
||||
case TFUNC:
|
||||
t.Extra.(*FuncType).Nname = n
|
||||
case TINTERMETH:
|
||||
t.Extra = InterMethType{Nname: n}
|
||||
default:
|
||||
Fatalf("Type.SetNname %v %v", t.Etype, t)
|
||||
}
|
||||
}
|
||||
|
||||
// IsFuncArgStruct reports whether t is a struct representing function parameters.
|
||||
func (t *Type) IsFuncArgStruct() bool {
|
||||
return t.Etype == TSTRUCT && t.Funarg
|
||||
return t.Etype == TSTRUCT && t.Extra.(*StructType).Funarg
|
||||
}
|
||||
|
||||
func (t *Type) Methods() *Fields {
|
||||
@ -582,10 +814,14 @@ func (t *Type) AllMethods() *Fields {
|
||||
}
|
||||
|
||||
func (t *Type) Fields() *Fields {
|
||||
if t.Etype != TSTRUCT && t.Etype != TINTER {
|
||||
Fatalf("Fields: type %v does not have fields", t)
|
||||
switch t.Etype {
|
||||
case TSTRUCT:
|
||||
return &t.Extra.(*StructType).fields
|
||||
case TINTER:
|
||||
return &t.Extra.(*InterType).fields
|
||||
}
|
||||
return &t.fields
|
||||
Fatalf("Fields: type %v does not have fields", t)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Field returns the i'th field/method of struct/interface type t.
|
||||
@ -608,15 +844,15 @@ func (t *Type) isDDDArray() bool {
|
||||
if t.Etype != TARRAY {
|
||||
return false
|
||||
}
|
||||
t.checkBound()
|
||||
return t.Bound == dddBound
|
||||
_, ok := t.Extra.(DDDArrayType)
|
||||
return ok
|
||||
}
|
||||
|
||||
// ArgWidth returns the total aligned argument size for a function.
|
||||
// It includes the receiver, parameters, and results.
|
||||
func (t *Type) ArgWidth() int64 {
|
||||
t.wantEtype(TFUNC)
|
||||
return t.Argwid
|
||||
return t.Extra.(*FuncType).Argwid
|
||||
}
|
||||
|
||||
func (t *Type) Size() int64 {
|
||||
@ -764,20 +1000,20 @@ func (t *Type) cmp(x *Type) ssa.Cmp {
|
||||
// by the general code after the switch.
|
||||
|
||||
case TSTRUCT:
|
||||
if t.Map == nil {
|
||||
if x.Map != nil {
|
||||
if t.StructType().Map == nil {
|
||||
if x.StructType().Map != nil {
|
||||
return ssa.CMPlt // nil < non-nil
|
||||
}
|
||||
// to the fallthrough
|
||||
} else if x.Map == nil {
|
||||
} else if x.StructType().Map == nil {
|
||||
return ssa.CMPgt // nil > non-nil
|
||||
} else if t.Map.Bucket == t {
|
||||
} else if t.StructType().Map.MapType().Bucket == t {
|
||||
// Both have non-nil Map
|
||||
// Special case for Maps which include a recursive type where the recursion is not broken with a named type
|
||||
if x.Map.Bucket != x {
|
||||
if x.StructType().Map.MapType().Bucket != x {
|
||||
return ssa.CMPlt // bucket maps are least
|
||||
}
|
||||
return t.Map.cmp(x.Map)
|
||||
return t.StructType().Map.cmp(x.StructType().Map)
|
||||
} // If t != t.Map.Bucket, fall through to general case
|
||||
|
||||
fallthrough
|
||||
@ -910,21 +1146,22 @@ func (t *Type) IsChan() bool {
|
||||
return t.Etype == TCHAN
|
||||
}
|
||||
|
||||
// checkBound enforces that Bound has an acceptable value.
|
||||
func (t *Type) checkBound() {
|
||||
if t.Bound != sliceBound && t.Bound < 0 && t.Bound != dddBound {
|
||||
Fatalf("bad TARRAY bounds %d %s", t.Bound, t)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove noinline when issue 15084 is resolved.
|
||||
//go:noinline
|
||||
func (t *Type) IsSlice() bool {
|
||||
t.checkBound()
|
||||
return t.Etype == TARRAY && t.Bound == sliceBound
|
||||
if t.Etype != TARRAY {
|
||||
return false
|
||||
}
|
||||
_, ok := t.Extra.(SliceType)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (t *Type) IsArray() bool {
|
||||
t.checkBound()
|
||||
return t.Etype == TARRAY && t.Bound >= 0
|
||||
if t.Etype != TARRAY {
|
||||
return false
|
||||
}
|
||||
_, ok := t.Extra.(*ArrayType)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (t *Type) IsStruct() bool {
|
||||
@ -961,24 +1198,48 @@ func (t *Type) FieldOff(i int) int64 {
|
||||
|
||||
func (t *Type) NumElem() int64 {
|
||||
t.wantEtype(TARRAY)
|
||||
t.checkBound()
|
||||
return t.Bound
|
||||
switch t := t.Extra.(type) {
|
||||
case *ArrayType:
|
||||
return t.Bound
|
||||
case SliceType:
|
||||
return sliceBound
|
||||
case DDDArrayType:
|
||||
return dddBound
|
||||
}
|
||||
Fatalf("NumElem on non-array %T %v", t.Extra, t)
|
||||
return 0
|
||||
}
|
||||
|
||||
// SetNumElem sets the number of elements in an array type.
|
||||
// It should not be used if at all possible.
|
||||
// Create a new array/slice/dddArray with typX instead.
|
||||
// TODO(josharian): figure out how to get rid of this.
|
||||
// The only allowed uses are:
|
||||
// * array -> slice as a hack to suppress extra error output
|
||||
// * ddd array -> array
|
||||
// TODO(josharian): figure out how to get rid of this entirely.
|
||||
func (t *Type) SetNumElem(n int64) {
|
||||
t.wantEtype(TARRAY)
|
||||
t.Bound = n
|
||||
switch {
|
||||
case n >= 0:
|
||||
if !t.isDDDArray() {
|
||||
Fatalf("SetNumElem non-ddd -> array %v", t)
|
||||
}
|
||||
t.Extra = &ArrayType{Elem: t.Elem(), Bound: n}
|
||||
case n == sliceBound:
|
||||
if !t.IsArray() {
|
||||
Fatalf("SetNumElem non-array -> slice %v", t)
|
||||
}
|
||||
t.Extra = SliceType{Elem: t.Elem()}
|
||||
default:
|
||||
Fatalf("SetNumElem %d %v", n, t)
|
||||
}
|
||||
}
|
||||
|
||||
// ChanDir returns the direction of a channel type t.
|
||||
// The direction will be one of Crecv, Csend, or Cboth.
|
||||
func (t *Type) ChanDir() ChanDir {
|
||||
t.wantEtype(TCHAN)
|
||||
return t.Chan
|
||||
return t.Extra.(*ChanType).Dir
|
||||
}
|
||||
|
||||
func (t *Type) IsMemory() bool { return false }
|
||||
|
@ -2103,7 +2103,7 @@ OpSwitch:
|
||||
return n
|
||||
}
|
||||
|
||||
if Curfn.Type.Outnamed && n.List.Len() == 0 {
|
||||
if Curfn.Type.FuncType().Outnamed && n.List.Len() == 0 {
|
||||
break OpSwitch
|
||||
}
|
||||
typecheckaste(ORETURN, nil, false, Curfn.Type.Results(), n.List, func() string { return "return argument" })
|
||||
@ -2161,12 +2161,8 @@ OpSwitch:
|
||||
t := n.Type
|
||||
if t != nil && !t.IsFuncArgStruct() && n.Op != OTYPE {
|
||||
switch t.Etype {
|
||||
case TFUNC, // might have TANY; wait until its called
|
||||
TANY,
|
||||
TFORW,
|
||||
TIDEAL,
|
||||
TNIL,
|
||||
TBLANK:
|
||||
case TFUNC, // might have TANY; wait until it's called
|
||||
TANY, TFORW, TIDEAL, TNIL, TBLANK:
|
||||
break
|
||||
|
||||
default:
|
||||
@ -3522,13 +3518,13 @@ var mapqueue []*Node
|
||||
func copytype(n *Node, t *Type) {
|
||||
if t.Etype == TFORW {
|
||||
// This type isn't computed yet; when it is, update n.
|
||||
t.Copyto = append(t.Copyto, n)
|
||||
t.ForwardType().Copyto = append(t.ForwardType().Copyto, n)
|
||||
return
|
||||
}
|
||||
|
||||
maplineno := n.Type.Maplineno
|
||||
embedlineno := n.Type.Embedlineno
|
||||
l := n.Type.Copyto
|
||||
embedlineno := n.Type.ForwardType().Embedlineno
|
||||
l := n.Type.ForwardType().Copyto
|
||||
|
||||
// TODO(mdempsky): Fix Type rekinding.
|
||||
*n.Type = *t
|
||||
@ -3544,7 +3540,6 @@ func copytype(n *Node, t *Type) {
|
||||
t.Nod = nil
|
||||
t.Printed = false
|
||||
t.Deferwidth = false
|
||||
t.Copyto = nil
|
||||
|
||||
// Update nodes waiting on this type.
|
||||
for _, n := range l {
|
||||
|
@ -359,16 +359,16 @@ func lexinit1() {
|
||||
// t = interface { Error() string }
|
||||
|
||||
rcvr := typ(TSTRUCT)
|
||||
rcvr.Funarg = true
|
||||
rcvr.StructType().Funarg = true
|
||||
field := newField()
|
||||
field.Type = Ptrto(typ(TSTRUCT))
|
||||
rcvr.SetFields([]*Field{field})
|
||||
|
||||
in := typ(TSTRUCT)
|
||||
in.Funarg = true
|
||||
in.StructType().Funarg = true
|
||||
|
||||
out := typ(TSTRUCT)
|
||||
out.Funarg = true
|
||||
out.StructType().Funarg = true
|
||||
field = newField()
|
||||
field.Type = Types[TSTRING]
|
||||
out.SetFields([]*Field{field})
|
||||
|
@ -287,7 +287,7 @@ func walkstmt(n *Node) *Node {
|
||||
if n.List.Len() == 0 {
|
||||
break
|
||||
}
|
||||
if (Curfn.Type.Outnamed && n.List.Len() > 1) || paramoutheap(Curfn) {
|
||||
if (Curfn.Type.FuncType().Outnamed && n.List.Len() > 1) || paramoutheap(Curfn) {
|
||||
// assign to the function out parameters,
|
||||
// so that reorder3 can fix up conflicts
|
||||
var rl []*Node
|
||||
|
Loading…
Reference in New Issue
Block a user