package gc
+import (
+ "sort"
+)
+
// machine size and rounding alignment is dictated around
// the size of a pointer, set in betypeinit (see ../amd64/galign.go).
var defercalc int
return (o + r - 1) &^ (r - 1)
}
+// expandiface computes the method set for interface type t by
+// expanding embedded interfaces.
+func expandiface(t *Type) {
+ var fields []*Field
+ for _, m := range t.Methods().Slice() {
+ if m.Sym != nil {
+ fields = append(fields, m)
+ continue
+ }
+
+ if !m.Type.IsInterface() {
+ yyerrorl(m.Nname.Pos, "interface contains embedded non-interface %v", m.Type)
+ m.SetBroke(true)
+ t.SetBroke(true)
+ // Add to fields so that error messages
+ // include the broken embedded type when
+ // printing t.
+ // TODO(mdempsky): Revisit this.
+ fields = append(fields, m)
+ continue
+ }
+
+ // Embedded interface: duplicate all methods
+ // (including broken ones, if any) and add to t's
+ // method set.
+ for _, t1 := range m.Type.Fields().Slice() {
+ f := newField()
+ f.Type = t1.Type
+ f.SetBroke(t1.Broke())
+ f.Sym = t1.Sym
+ f.Nname = m.Nname // preserve embedding position
+ fields = append(fields, f)
+ }
+ }
+ sort.Sort(methcmp(fields))
+
+ // Access fields directly to avoid recursively calling dowidth
+ // within Type.Fields().
+ t.Extra.(*InterType).fields.Set(fields)
+}
+
func offmod(t *Type) {
o := int32(0)
for _, f := range t.Fields().Slice() {
case TINTER: // implemented as 2 pointers
w = 2 * int64(Widthptr)
-
t.Align = uint8(Widthptr)
- offmod(t)
+ expandiface(t)
case TCHAN: // implemented as pointer
w = int64(Widthptr)
t.Align = uint8(w)
}
+ if t.Etype == TINTER {
+ // We defer calling these functions until after
+ // setting t.Width and t.Align so the recursive calls
+ // to dowidth within t.Fields() will succeed.
+ checkdupfields("method", t)
+ offmod(t)
+ }
+
lineno = lno
if defercalc == 1 {
t = p.newtyp(TINTER)
t.SetInterface(ml)
}
- checkwidth(t)
case mapTag:
t = p.newtyp(TMAP)
import (
"cmd/internal/src"
"fmt"
- "sort"
"strings"
)
// checkdupfields emits errors for duplicately named fields or methods in
// a list of struct or interface types.
func checkdupfields(what string, ts ...*Type) {
- lno := lineno
-
seen := make(map[*Sym]bool)
for _, t := range ts {
for _, f := range t.Fields().Slice() {
- if f.Sym == nil || f.Nname == nil || isblank(f.Nname) {
+ if f.Sym == nil || isblanksym(f.Sym) || f.Nname == nil {
continue
}
if seen[f.Sym] {
- lineno = f.Nname.Pos
- yyerror("duplicate %s %s", what, f.Sym.Name)
+ yyerrorl(f.Nname.Pos, "duplicate %s %s", what, f.Sym.Name)
continue
}
seen[f.Sym] = true
}
}
-
- lineno = lno
}
// convert a parsed id/type list into
yyerror("interface method cannot have annotation")
}
- f := newField()
- f.SetIsddd(n.Isddd())
+ // MethodSpec = MethodName Signature | InterfaceTypeName .
+ //
+ // If Left != nil, then Left is MethodName and Right is Signature.
+ // Otherwise, Right is InterfaceTypeName.
if n.Right != nil {
- if n.Left != nil {
- // queue resolution of method type for later.
- // right now all we need is the name list.
- // avoids cycles for recursive interface types.
- n.Type = typ(TINTERMETH)
- n.Type.SetNname(n.Right)
- n.Left.Type = n.Type
- queuemethod(n)
-
- if n.Left.Op == ONAME {
- f.Nname = n.Left
- f.Embedded = n.Embedded
- f.Sym = f.Nname.Sym
- }
- } else {
- n.Right = typecheck(n.Right, Etype)
- n.Type = n.Right.Type
-
- if n.Embedded != 0 {
- checkembeddedtype(n.Type)
- }
-
- if n.Type != nil {
- switch n.Type.Etype {
- case TINTER:
- break
-
- case TFORW:
- yyerror("interface type loop involving %v", n.Type)
- f.SetBroke(true)
-
- default:
- yyerror("interface contains embedded non-interface %v", n.Type)
- f.SetBroke(true)
- }
- }
- }
+ n.Right = typecheck(n.Right, Etype)
+ n.Type = n.Right.Type
+ n.Right = nil
}
- n.Right = nil
+ f := newField()
+ if n.Left != nil {
+ f.Nname = n.Left
+ f.Sym = f.Nname.Sym
+ } else {
+ // Placeholder ONAME just to hold Pos.
+ // TODO(mdempsky): Add Pos directly to Field instead.
+ f.Nname = newname(nblank.Sym)
+ }
f.Type = n.Type
if f.Type == nil {
var fields []*Field
for _, n := range l {
f := interfacefield(n)
-
- if n.Left == nil && f.Type.IsInterface() {
- // embedded interface, inline methods
- for _, t1 := range f.Type.Fields().Slice() {
- f = newField()
- f.Type = t1.Type
- f.SetBroke(t1.Broke())
- f.Sym = t1.Sym
- if f.Sym != nil {
- f.Nname = newname(f.Sym)
- }
- fields = append(fields, f)
- }
- } else {
- fields = append(fields, f)
- }
if f.Broke() {
t.SetBroke(true)
}
+ fields = append(fields, f)
}
- sort.Sort(methcmp(fields))
t.SetInterface(fields)
- checkdupfields("method", t)
- checkwidth(t)
-
return t
}
TBLANK: "TBLANK",
TFUNCARGS: "TFUNCARGS",
TCHANARGS: "TCHANARGS",
- TINTERMETH: "TINTERMETH",
TDDDFIELD: "TDDDFIELD",
}
// pseudo-types for frame layout
TFUNCARGS
TCHANARGS
- TINTERMETH
// pseudo-types for import/export
TDDDFIELD // wrapper: contained type is a ... field
t.Extra = new(ForwardType)
case TFUNC:
t.Extra = new(FuncType)
- case TINTERMETH:
- t.Extra = InterMethType{}
case TSTRUCT:
t.Extra = new(StructType)
case TINTER:
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
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)
}
case TSTRUCT:
return &t.Extra.(*StructType).fields
case TINTER:
+ dowidth(t)
return &t.Extra.(*InterType).fields
}
Fatalf("Fields: type %v does not have fields", t)
func (t *Type) SetInterface(methods []*Field) {
t.wantEtype(TINTER)
- t.Fields().Set(methods)
+ t.Methods().Set(methods)
}
func (t *Type) isDDDArray() bool {
if n.Name != nil {
t.Vargen = n.Name.Vargen
}
- t.methods = Fields{}
- t.allMethods = Fields{}
+
+ // spec: "The declared type does not inherit any methods bound
+ // to the existing type, but the method set of an interface
+ // type [...] remains unchanged."
+ if !t.IsInterface() {
+ t.methods = Fields{}
+ t.allMethods = Fields{}
+ }
+
t.nod = n
t.SetDeferwidth(false)
t.ptrTo = ptrTo
type S struct {
x interface{ S } // ERROR "interface"
}
-type I4 interface {
- I4 // ERROR "interface"
+type I4 interface { // GC_ERROR "invalid recursive type"
+ I4 // GCCGO_ERROR "interface"
}
type I5 interface {
I6 // GCCGO_ERROR "interface"
}
-type I6 interface {
- I5 // ERROR "interface"
+type I6 interface { // GC_ERROR "invalid recursive type"
+ I5 // GCCGO_ERROR "interface"
}
package main
-type I1 interface {
+type I1 interface { // GC_ERROR "invalid recursive type"
m() I2
- I2 // GCCGO_ERROR "loop|interface"
+ // TODO(mdempsky): The duplicate method error is silly
+ // and redundant, but tricky to prevent as it's actually
+ // being emitted against the underlying interface type
+ // literal, not I1 itself.
+ I2 // ERROR "loop|interface|duplicate method m"
}
type I2 interface {
- I1 // ERROR "loop|interface"
+ I1 // GCCGO_ERROR "loop|interface"
}
package p
type A interface {
- Fn(A.Fn) // ERROR "type A has no method A.Fn"
+ // TODO(mdempsky): This should be an error, but this error is
+ // nonsense. The error should actually mention that there's a
+ // type loop.
+ Fn(A.Fn) // ERROR "type A has no method Fn"
}