aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/types2/interface.go
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2021-06-17 17:49:15 -0700
committerRobert Griesemer <gri@golang.org>2021-06-30 18:58:34 +0000
commit4b5fdb0b7a362cb6fa6ad551757104e490483121 (patch)
treea2d35fe408f7c5fb8d2fd8836481a23d023844c3 /src/cmd/compile/internal/types2/interface.go
parentf503740ccf6302ed13c7722ea50c6880a17703fb (diff)
downloadgo-4b5fdb0b7a362cb6fa6ad551757104e490483121.tar.gz
go-4b5fdb0b7a362cb6fa6ad551757104e490483121.zip
[dev.typeparams] cmd/compile/internal/types2: introduce type set abstraction for interfaces
With this change, interfaces are "completed" on-demand, when needed, and the respective information (set of all methods, type constraints) is recorded in a new typeSet data structure. As a consequence, interfaces don't need to be explicitly completed anymore and (internal) uses of interfaces have become much simpler. This change also introduces a new field Interface.complete to indicate that all methods and embedded elements have been set up. This prevent the computation and recording (!) of a partial type set for erroneous programs (if we compute the partial type set and store it, subsequent type set accesses use the wrong type set which may lead to follow-on errors). Change-Id: I1ffc907f7d0fb93b3e987fe5ff9c6fa5cae00d7f Reviewed-on: https://go-review.googlesource.com/c/go/+/329309 Trust: Robert Griesemer <gri@golang.org> Run-TryBot: Robert Griesemer <gri@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
Diffstat (limited to 'src/cmd/compile/internal/types2/interface.go')
-rw-r--r--src/cmd/compile/internal/types2/interface.go64
1 files changed, 36 insertions, 28 deletions
diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go
index c79026f00d..4dee923422 100644
--- a/src/cmd/compile/internal/types2/interface.go
+++ b/src/cmd/compile/internal/types2/interface.go
@@ -95,9 +95,13 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType
check.posMap[ityp] = append(check.posMap[ityp], tlist[0].(*syntax.Operation).X.Pos())
}
+ // All methods and embedded elements for this interface are collected;
+ // i.e., this interface is may be used in a type set computation.
+ ityp.complete = true
+
if len(ityp.methods) == 0 && len(ityp.embeddeds) == 0 {
// empty interface
- ityp.allMethods = markComplete
+ ityp.tset = &topTypeSet
return
}
@@ -105,7 +109,10 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType
sortMethods(ityp.methods)
sortTypes(ityp.embeddeds)
- check.later(func() { check.completeInterface(iface.Pos(), ityp) })
+ // Compute type set with a non-nil *Checker as soon as possible
+ // to report any errors. Subsequent uses of type sets should be
+ // using this computed type set and won't need to pass in a *Checker.
+ check.later(func() { newTypeSet(check, iface.Pos(), ityp) })
}
func flattenUnion(list []syntax.Expr, x syntax.Expr) []syntax.Expr {
@@ -116,26 +123,27 @@ func flattenUnion(list []syntax.Expr, x syntax.Expr) []syntax.Expr {
return append(list, x)
}
-func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) {
- if ityp.allMethods != nil {
- return
+// newTypeSet may be called with check == nil.
+// TODO(gri) move this function into typeset.go eventually
+func newTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *TypeSet {
+ if ityp.tset != nil {
+ return ityp.tset
}
- // completeInterface may be called via the LookupFieldOrMethod,
- // MissingMethod, Identical, or IdenticalIgnoreTags external API
- // in which case check will be nil. In this case, type-checking
- // must be finished and all interfaces should have been completed.
- if check == nil {
- panic("internal error: incomplete interface")
+ // If the interface is not fully set up yet, the type set will
+ // not be complete, which may lead to errors when using the the
+ // type set (e.g. missing method). Don't compute a partial type
+ // set (and don't store it!), so that we still compute the full
+ // type set eventually. Instead, return the top type set and
+ // let any follow-on errors play out.
+ //
+ // TODO(gri) Consider recording when this happens and reporting
+ // it as an error (but only if there were no other errors so to
+ // to not have unnecessary follow-on errors).
+ if !ityp.complete {
+ return &topTypeSet
}
- completeInterface(check, pos, ityp)
-}
-
-// completeInterface may be called with check == nil.
-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
@@ -144,11 +152,11 @@ func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) {
pos = ityp.methods[0].pos
}
- check.trace(pos, "complete %s", ityp)
+ check.trace(pos, "type set for %s", ityp)
check.indent++
defer func() {
check.indent--
- check.trace(pos, "=> %s (methods = %v, types = %v)", ityp, ityp.allMethods, ityp.allTypes)
+ check.trace(pos, "=> %s ", ityp.typeSet())
}()
}
@@ -157,7 +165,7 @@ func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) {
// have valid interfaces. Mark the interface as complete to avoid
// infinite recursion if the validType check occurs later for some
// reason.
- ityp.allMethods = markComplete
+ ityp.tset = new(TypeSet) // TODO(gri) is this sufficient?
// Methods of embedded interfaces are collected unchanged; i.e., the identity
// of a method I.m's Func Object of an interface I is the same as that of
@@ -231,13 +239,11 @@ func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) {
var types Type
switch t := under(typ).(type) {
case *Interface:
- if t.allMethods == nil {
- completeInterface(check, pos, t)
- }
- for _, m := range t.allMethods {
+ tset := newTypeSet(check, pos, t)
+ for _, m := range tset.methods {
addMethod(pos, m, false) // use embedding position pos rather than m.pos
}
- types = t.allTypes
+ types = tset.types
case *Union:
// TODO(gri) combine with default case once we have
// converted all tests to new notation and we
@@ -274,9 +280,11 @@ func completeInterface(check *Checker, pos syntax.Pos, ityp *Interface) {
if methods != nil {
sortMethods(methods)
- ityp.allMethods = methods
+ ityp.tset.methods = methods
}
- ityp.allTypes = allTypes
+ ityp.tset.types = allTypes
+
+ return ityp.tset
}
func sortTypes(list []Type) {