From 1608577e0503be1739631d60576a07bdf1bbb49e Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 20 May 2021 21:24:36 -0700 Subject: [PATCH] [dev.typeparams] cmd/compile/internal/types2: re-use existing code for Interface.Complete Change-Id: I0fa07e49651aa086c2edbd1162332608c400250f Reviewed-on: https://go-review.googlesource.com/c/go/+/321751 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/interface.go | 47 +++++++++++++-- src/cmd/compile/internal/types2/type.go | 60 +------------------- 2 files changed, 44 insertions(+), 63 deletions(-) diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index bbd25cbd09..21968b34aa 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -6,6 +6,7 @@ package types2 import ( "cmd/compile/internal/syntax" + "fmt" "sort" ) @@ -139,7 +140,13 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { panic("internal error: incomplete interface") } - if check.conf.Trace { + completeInterface(check, pos, ityp) +} + +func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) { + assert(ityp.allMethods == nil) + + if check != nil && check.conf.Trace { // Types don't generally have position information. // If we don't have a valid pos provided, try to use // one close enough. @@ -175,6 +182,7 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { // we can get rid of the mpos map below and simply use the cloned method's // position. + var todo []*Func var seen objset var methods []*Func mpos := make(map[*Func]syntax.Pos) // method specification or method embedding position, for good error messages @@ -184,6 +192,9 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { methods = append(methods, m) mpos[m] = pos case explicit: + if check == nil { + panic(fmt.Sprintf("%s: duplicate method %s", m.pos, m.name)) + } var err error_ err.errorf(pos, "duplicate method %s", m.name) err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name) @@ -194,6 +205,11 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { // If we're pre-go1.14 (overlapping embeddings are not permitted), report that // error here as well (even though we could do it eagerly) because it's the same // error message. + if check == nil { + // check method signatures after all locally embedded interfaces are computed + todo = append(todo, m, other.(*Func)) + break + } check.later(func() { if !check.allowVersion(m.pkg, 1, 14) || !check.identical(m.typ, other.Type()) { var err error_ @@ -212,9 +228,15 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { // collect types allTypes := ityp.types - posList := check.posMap[ityp] + var posList []syntax.Pos + if check != nil { + posList = check.posMap[ityp] + } for i, typ := range ityp.embeddeds { - pos := posList[i] // embedding position + var pos syntax.Pos // embedding position + if posList != nil { + pos = posList[i] + } utyp := under(typ) etyp := asInterface(utyp) if etyp == nil { @@ -225,17 +247,32 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) { } else { format = "%s is not an interface" } - check.errorf(pos, format, typ) + if check != nil { + check.errorf(pos, format, typ) + } else { + panic(fmt.Sprintf("%s: "+format, pos, typ)) + } } continue } - check.completeInterface(pos, etyp) + if etyp.allMethods == nil { + completeInterface(check, pos, etyp) + } for _, m := range etyp.allMethods { addMethod(pos, m, false) // use embedding position pos rather than m.pos } allTypes = intersect(allTypes, etyp.allTypes) } + // process todo's (this only happens if check == nil) + for i := 0; i < len(todo); i += 2 { + m := todo[i] + other := todo[i+1] + if !Identical(m.typ, other.typ) { + panic(fmt.Sprintf("%s: duplicate method %s", m.pos, m.name)) + } + } + if methods != nil { sortMethods(methods) ityp.allMethods = methods diff --git a/src/cmd/compile/internal/types2/type.go b/src/cmd/compile/internal/types2/type.go index 55c2f336ce..db955a8509 100644 --- a/src/cmd/compile/internal/types2/type.go +++ b/src/cmd/compile/internal/types2/type.go @@ -6,7 +6,6 @@ package types2 import ( "cmd/compile/internal/syntax" - "fmt" "sync/atomic" ) @@ -544,64 +543,9 @@ func (t *Interface) isSatisfiedBy(typ Type) bool { // form other types. The interface must not contain duplicate methods or a // panic occurs. Complete returns the receiver. func (t *Interface) Complete() *Interface { - // TODO(gri) consolidate this method with Checker.completeInterface - if t.allMethods != nil { - return t + if t.allMethods == nil { + completeInterface(nil, nopos, t) } - - t.allMethods = markComplete // avoid infinite recursion - - var todo []*Func - var methods []*Func - var seen objset - addMethod := func(m *Func, explicit bool) { - switch other := seen.insert(m); { - case other == nil: - methods = append(methods, m) - case explicit: - panic("duplicate method " + m.name) - default: - // check method signatures after all locally embedded interfaces are computed - todo = append(todo, m, other.(*Func)) - } - } - - for _, m := range t.methods { - addMethod(m, true) - } - - allTypes := t.types - - for _, typ := range t.embeddeds { - utyp := under(typ) - etyp := asInterface(utyp) - if etyp == nil { - if utyp != Typ[Invalid] { - panic(fmt.Sprintf("%s is not an interface", typ)) - } - continue - } - etyp.Complete() - for _, m := range etyp.allMethods { - addMethod(m, false) - } - allTypes = intersect(allTypes, etyp.allTypes) - } - - for i := 0; i < len(todo); i += 2 { - m := todo[i] - other := todo[i+1] - if !Identical(m.typ, other.typ) { - panic("duplicate method " + m.name) - } - } - - if methods != nil { - sortMethods(methods) - t.allMethods = methods - } - t.allTypes = allTypes - return t }