mirror of
https://github.com/golang/go
synced 2024-11-02 09:28:34 +00:00
[dev.typeparams] go/types: re-use existing code for Interface.Complete
This is a port of CL 321751 to go/types, adjusted to use token.Pos, and to exclude a missing position from a panic message (an unresolved comment on the original CL). Change-Id: I5814067aecb67aca9d73f2093fb6004b769924f3 Reviewed-on: https://go-review.googlesource.com/c/go/+/324756 Trust: Robert Findley <rfindley@google.com> Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
1395952075
commit
2f26adc232
2 changed files with 44 additions and 64 deletions
|
@ -5,6 +5,7 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/internal/typeparams"
|
"go/internal/typeparams"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
@ -142,8 +143,13 @@ func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) {
|
||||||
if check == nil {
|
if check == nil {
|
||||||
panic("internal error: incomplete interface")
|
panic("internal error: incomplete interface")
|
||||||
}
|
}
|
||||||
|
completeInterface(check, pos, ityp)
|
||||||
|
}
|
||||||
|
|
||||||
if trace {
|
func completeInterface(check *Checker, pos token.Pos, ityp *Interface) {
|
||||||
|
assert(ityp.allMethods == nil)
|
||||||
|
|
||||||
|
if check != nil && trace {
|
||||||
// Types don't generally have position information.
|
// Types don't generally have position information.
|
||||||
// If we don't have a valid pos provided, try to use
|
// If we don't have a valid pos provided, try to use
|
||||||
// one close enough.
|
// one close enough.
|
||||||
|
@ -179,6 +185,7 @@ func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) {
|
||||||
// we can get rid of the mpos map below and simply use the cloned method's
|
// we can get rid of the mpos map below and simply use the cloned method's
|
||||||
// position.
|
// position.
|
||||||
|
|
||||||
|
var todo []*Func
|
||||||
var seen objset
|
var seen objset
|
||||||
var methods []*Func
|
var methods []*Func
|
||||||
mpos := make(map[*Func]token.Pos) // method specification or method embedding position, for good error messages
|
mpos := make(map[*Func]token.Pos) // method specification or method embedding position, for good error messages
|
||||||
|
@ -188,6 +195,9 @@ func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) {
|
||||||
methods = append(methods, m)
|
methods = append(methods, m)
|
||||||
mpos[m] = pos
|
mpos[m] = pos
|
||||||
case explicit:
|
case explicit:
|
||||||
|
if check == nil {
|
||||||
|
panic(fmt.Sprintf("%v: duplicate method %s", m.pos, m.name))
|
||||||
|
}
|
||||||
check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name)
|
check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name)
|
||||||
check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented
|
check.errorf(atPos(mpos[other.(*Func)]), _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented
|
||||||
default:
|
default:
|
||||||
|
@ -196,6 +206,11 @@ func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) {
|
||||||
// If we're pre-go1.14 (overlapping embeddings are not permitted), report that
|
// 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 here as well (even though we could do it eagerly) because it's the same
|
||||||
// error message.
|
// 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() {
|
check.later(func() {
|
||||||
if !check.allowVersion(m.pkg, 1, 14) || !check.identical(m.typ, other.Type()) {
|
if !check.allowVersion(m.pkg, 1, 14) || !check.identical(m.typ, other.Type()) {
|
||||||
check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name)
|
check.errorf(atPos(pos), _DuplicateDecl, "duplicate method %s", m.name)
|
||||||
|
@ -212,9 +227,15 @@ func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) {
|
||||||
// collect types
|
// collect types
|
||||||
allTypes := ityp.types
|
allTypes := ityp.types
|
||||||
|
|
||||||
posList := check.posMap[ityp]
|
var posList []token.Pos
|
||||||
|
if check != nil {
|
||||||
|
posList = check.posMap[ityp]
|
||||||
|
}
|
||||||
for i, typ := range ityp.embeddeds {
|
for i, typ := range ityp.embeddeds {
|
||||||
pos := posList[i] // embedding position
|
var pos token.Pos // embedding position
|
||||||
|
if posList != nil {
|
||||||
|
pos = posList[i]
|
||||||
|
}
|
||||||
utyp := under(typ)
|
utyp := under(typ)
|
||||||
etyp := asInterface(utyp)
|
etyp := asInterface(utyp)
|
||||||
if etyp == nil {
|
if etyp == nil {
|
||||||
|
@ -225,18 +246,33 @@ func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) {
|
||||||
} else {
|
} else {
|
||||||
format = "%s is not an interface"
|
format = "%s is not an interface"
|
||||||
}
|
}
|
||||||
// TODO: correct error code.
|
if check != nil {
|
||||||
check.errorf(atPos(pos), _InvalidIfaceEmbed, format, typ)
|
// TODO: correct error code.
|
||||||
|
check.errorf(atPos(pos), _InvalidIfaceEmbed, format, typ)
|
||||||
|
} else {
|
||||||
|
panic(fmt.Sprintf(format, typ))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
check.completeInterface(pos, etyp)
|
if etyp.allMethods == nil {
|
||||||
|
completeInterface(check, pos, etyp)
|
||||||
|
}
|
||||||
for _, m := range etyp.allMethods {
|
for _, m := range etyp.allMethods {
|
||||||
addMethod(pos, m, false) // use embedding position pos rather than m.pos
|
addMethod(pos, m, false) // use embedding position pos rather than m.pos
|
||||||
}
|
}
|
||||||
allTypes = intersect(allTypes, etyp.allTypes)
|
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("%v: duplicate method %s", m.pos, m.name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if methods != nil {
|
if methods != nil {
|
||||||
sort.Sort(byUniqueMethodName(methods))
|
sort.Sort(byUniqueMethodName(methods))
|
||||||
ityp.allMethods = methods
|
ityp.allMethods = methods
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"go/token"
|
"go/token"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
@ -538,64 +537,9 @@ func (t *Interface) isSatisfiedBy(typ Type) bool {
|
||||||
// form other types. The interface must not contain duplicate methods or a
|
// form other types. The interface must not contain duplicate methods or a
|
||||||
// panic occurs. Complete returns the receiver.
|
// panic occurs. Complete returns the receiver.
|
||||||
func (t *Interface) Complete() *Interface {
|
func (t *Interface) Complete() *Interface {
|
||||||
// TODO(gri) consolidate this method with Checker.completeInterface
|
if t.allMethods == nil {
|
||||||
if t.allMethods != nil {
|
completeInterface(nil, token.NoPos, t)
|
||||||
return 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
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue