// A special case to make write barriers more efficient.
// Comparing the first field of a named struct can be done directly.
base := n1
- if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Type.Sym == n1.Right.Sym {
+ if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Field(0).Sym == n1.Right.Sym {
base = n1.Left
}
// (look at the first parameter only since either all
// names are present or all are absent)
n := countfield(params)
- if n > 0 && parName(params.Type) == "" {
+ if n > 0 && parName(params.Field(0)) == "" {
n = -n
}
p.int(n)
}
wbVar := syslook("writeBarrier")
- wbEnabled := Nod(ODOT, wbVar, newname(wbVar.Type.Type.Sym))
+ wbEnabled := Nod(ODOT, wbVar, newname(wbVar.Type.Field(0).Sym))
wbEnabled = typecheck(&wbEnabled, Erv)
pbr := Thearch.Ginscmp(ONE, Types[TUINT8], wbEnabled, Nodintconst(0), -1)
Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, &dst)
return false
}
t = t.Type
- if t.Sym != nil || t.Etype != TSTRUCT || t.Type != nil {
+ if t.Sym != nil || t.Etype != TSTRUCT || countfield(t) != 0 {
return false
}
return true
var src *Node
i := 0
lls := ll.Slice()
- for t := fntype.Params().Type; i < len(lls); i++ {
+ for t, it := IterFields(fntype.Params()); i < len(lls); i++ {
src = lls[i]
if t.Isddd && !n.Isddd {
// Introduce ODDDARG node to represent ... allocation.
// This occurs when function parameter type Isddd and n not Isddd
break
}
- t = t.Down
+ t = it.Next()
}
for ; i < len(lls); i++ {
OMAKECHAN:
t := n.Type
- if t.Sym == nil && t.Type != nil {
- t = t.Type
+ switch t.Etype {
+ case TARRAY, TCHAN, TPTR32, TPTR64:
+ if t.Sym == nil {
+ t = t.Type
+ }
}
if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
if Debug['E'] != 0 {
if t == nil {
return
}
+ if t.Etype == TFIELD {
+ Fatalf("unexpected TFIELD in dumpexporttype")
+ }
if t.Printed || t == Types[t.Etype] || t == bytetype || t == runetype || t == errortype {
return
}
t.Printed = true
- if t.Sym != nil && t.Etype != TFIELD {
+ if t.Sym != nil {
dumppkg(t.Sym.Pkg)
}
- dumpexporttype(t.Type)
- dumpexporttype(t.Down)
-
- if t.Sym == nil || t.Etype == TFIELD {
+ switch t.Etype {
+ case TSTRUCT, TINTER:
+ for f, it := IterFields(t); f != nil; f = it.Next() {
+ dumpexporttype(f.Type)
+ }
+ case TFUNC:
+ dumpexporttype(t.Recvs())
+ dumpexporttype(t.Results())
+ dumpexporttype(t.Params())
+ case TMAP:
+ dumpexporttype(t.Type)
+ dumpexporttype(t.Down) // key
+ case TARRAY, TCHAN, TPTR32, TPTR64:
+ dumpexporttype(t.Type)
+ }
+
+ if t.Sym == nil {
return
}
var m []*Type
for f, it := IterMethods(t); f != nil; f = it.Next() {
- dumpexporttype(f)
+ dumpexporttype(f.Type)
m = append(m, f)
}
sort.Sort(methodbyname(m))
buf.WriteString(";")
}
}
- if t.Type != nil {
+ if t.Fields != nil {
buf.WriteString(" ")
}
buf.WriteString("}")
case 1:
if fmtmode != FExp {
buf.WriteString(" ")
- buf.WriteString(Tconv(t.Results().Type.Type, 0)) // struct->field->field's type
+ buf.WriteString(Tconv(t.Results().Field(0).Type, 0)) // struct->field->field's type
break
}
fallthrough
buf.WriteString(";")
}
}
- if t.Type != nil {
+ if t.Fields != nil {
buf.WriteString(" ")
}
buf.WriteString("}")
// A special case to make write barriers more efficient.
// Taking the address of the first field of a named struct
// is the same as taking the address of the struct.
- if n.Left.Type.Etype != TSTRUCT || n.Left.Type.Type.Sym != n.Right.Sym {
+ if n.Left.Type.Etype != TSTRUCT || n.Left.Type.Field(0).Sym != n.Right.Sym {
Debug['h'] = 1
Dump("naddr", n)
Fatalf("naddr: bad %v %v", Oconv(n.Op, 0), Ctxt.Dconv(a))
}
} else {
// match arguments except final variadic (unless the call is dotted itself)
- var t *Type
- for t = fn.Type.Params().Type; t != nil; {
+ t, it := IterFields(fn.Type.Params())
+ for t != nil {
if li >= n.List.Len() {
break
}
break
}
as.List.Append(tinlvar(t))
- t = t.Down
+ t = it.Next()
li++
}
}
if i == varargcount {
- t = t.Down
+ t = it.Next()
}
}
ordercallargs(&n.List, order)
if n.Op == OCALLFUNC {
- t := n.Left.Type.Params().Type
+ t, it := IterFields(n.Left.Type.Params())
for i := range n.List.Slice() {
// Check for "unsafe-uintptr" tag provided by escape analysis.
// If present and the argument is really a pointer being converted
*xp = x
}
}
- t = t.Down
+ t = it.Next()
}
}
}
tk := t.Down
tv := t.Type
+ syma := Lookup("a")
symb := Lookup("b")
- fieldb := typ(TFIELD)
- fieldb.Type = tv
- fieldb.Sym = symb
- syma := Lookup("a")
- fielda := typ(TFIELD)
- fielda.Type = tk
- fielda.Sym = syma
- fielda.Down = fieldb
+ var fields [2]*Type
+ fields[0] = typ(TFIELD)
+ fields[0].Type = tk
+ fields[0].Sym = syma
+ fields[1] = typ(TFIELD)
+ fields[1].Type = tv
+ fields[1].Sym = symb
tstruct := typ(TSTRUCT)
- tstruct.Type = fielda
+ tstruct.SetFields(fields[:])
tarr := typ(TARRAY)
tarr.Bound = int64(b)
{Name{}, 52, 80},
{Node{}, 92, 144},
{Sym{}, 60, 112},
- {Type{}, 136, 224},
+ {Type{}, 140, 232},
}
for _, tt := range tests {
}
func isnilinter(t *Type) bool {
- if !Isinter(t) {
- return false
- }
- if t.Type != nil {
- return false
- }
- return true
+ return Isinter(t) && countfield(t) == 0
}
func isideal(t *Type) bool {
Type *Type // actual type for TFIELD, element type for TARRAY, TCHAN, TMAP, TPTRxx
Width int64 // offset in TFIELD, width in all others
+ // TSTRUCT
+ Fields *Type // first struct field
+
// TFIELD
Down *Type // next struct field, also key type in TMAP
Note *string // literal string annotation
if t.Etype != TSTRUCT && t.Etype != TINTER {
Fatalf("IterFields: type %v does not have fields", t)
}
- return RawIter(t.Type)
+ return RawIter(t.Fields)
}
// IterMethods returns the first method in type t's method set
fields[i].Down = next
next = fields[i]
}
- t.Type = next
+ t.Fields = next
}
func (t *Type) Size() int64 {
}
ok |= Erv
if t.Outtuple == 1 {
- t := l.Type.Results().Type
- if t == nil {
- n.Type = nil
- return
- }
- if t.Etype == TFIELD {
- t = t.Type
- }
- n.Type = t
+ n.Type = l.Type.Results().Field(0).Type
if n.Op == OCALLFUNC && n.Left.Op == ONAME && (compiling_runtime != 0 || n.Left.Sym.Pkg == Runtimepkg) && n.Left.Sym.Name == "getg" {
// Emit code for runtime.getg() directly instead of calling function.
var funarg *Type
if Istype(t, TSTRUCT) && t.Funarg {
funarg = t
- t = t.Type.Type
+ t = t.Field(0).Type
}
n.Type = t
}
if funarg != nil {
- for t := funarg.Type.Down; t != nil; t = t.Down {
+ _, it := IterFields(funarg) // Skip first field
+ for t := it.Next(); t != nil; t = it.Next() {
if assignop(t.Type, n.Type.Type, nil) == 0 {
Yyerror("cannot append %v value to []%v", t.Type, n.Type.Type)
}
s := n.Right.Sym
if t.Etype == TINTER {
- f1 := lookdot1(n, s, t, t.Type, dostrcmp)
+ f1 := lookdot1(n, s, t, t.Fields, dostrcmp)
if f1 == nil {
return false
}
dowidth(t)
var f1 *Type
if t.Etype == TSTRUCT || t.Etype == TINTER {
- f1 = lookdot1(n, s, t, t.Type, dostrcmp)
+ f1 = lookdot1(n, s, t, t.Fields, dostrcmp)
}
var f2 *Type
}
}
- tn := n.Type.Type
+ tn, it := IterFields(n.Type)
var why string
for tl, it2 := IterFields(tstruct); tl != nil; tl = it2.Next() {
if tl.Isddd {
- for ; tn != nil; tn = tn.Down {
+ for ; tn != nil; tn = it.Next() {
if assignop(tn.Type, tl.Type.Type, &why) == 0 {
if call != nil {
Yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type.Type, call, why)
}
}
- tn = tn.Down
+ tn = it.Next()
}
if tn != nil {
bad := 0
if n.List.Len() != 0 && nokeys(n.List) {
// simple list of variables
- f := t.Type
+ f, it := IterFields(t)
var s *Sym
ls := n.List.Slice()
n1.Left.Type = f
n1.Left.Typecheck = 1
ls[i1] = n1
- f = f.Down
+ f = it.Next()
}
if f != nil {
}
}
- f := lookdot1(nil, s, t, t.Type, 0)
+ f := lookdot1(nil, s, t, t.Fields, 0)
if f == nil {
Yyerror("unknown %v field '%v' in struct literal", t, s)
continue
func lexinit1() {
// t = interface { Error() string }
- rcvr := typ(TSTRUCT)
- rcvr.Type = typ(TFIELD)
- rcvr.Type.Type = Ptrto(typ(TSTRUCT))
+ rcvr := typ(TSTRUCT)
rcvr.Funarg = true
+ field := typ(TFIELD)
+ field.Type = Ptrto(typ(TSTRUCT))
+ rcvr.SetFields([]*Type{field})
+
in := typ(TSTRUCT)
in.Funarg = true
+
out := typ(TSTRUCT)
- out.Type = typ(TFIELD)
- out.Type.Type = Types[TSTRING]
out.Funarg = true
+ field = typ(TFIELD)
+ field.Type = Types[TSTRING]
+ out.SetFields([]*Type{field})
+
f := typ(TFUNC)
*f.RecvsP() = rcvr
*f.ResultsP() = out
f.Intuple = 0
f.Outnamed = false
f.Outtuple = 1
+
t := typ(TINTER)
- t.Type = typ(TFIELD)
- t.Type.Sym = Lookup("Error")
- t.Type.Type = f
+ field = typ(TFIELD)
+ field.Sym = Lookup("Error")
+ field.Type = f
+ t.SetFields([]*Type{field})
// error type
s := Pkglookup("error", builtinpkg)
// Update type of OCALLFUNC node.
// Output arguments had not changed, but their offsets could.
if n.Left.Type.Outtuple == 1 {
- t := n.Left.Type.Results().Type
- if t.Etype == TFIELD {
- t = t.Type
- }
- n.Type = t
+ n.Type = n.Left.Type.Results().Field(0).Type
} else {
n.Type = n.Left.Type.Results()
}
continue
}
- t = on.Type.Params()
- if t != nil {
- t = t.Type
- }
- if t != nil {
- t = t.Type
- }
+ t = on.Type.Params().Field(0).Type
if !Eqtype(t, n.Type) {
n = Nod(OCONV, n, nil)
// A special case to make write barriers more efficient.
// Comparing the first field of a named struct can be done directly.
base := n1
- if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Type.Sym == n1.Right.Sym {
+ if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Field(0).Sym == n1.Right.Sym {
base = n1.Left
}