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"
 }