diff options
author | Robert Griesemer <gri@golang.org> | 2021-06-17 17:49:15 -0700 |
---|---|---|
committer | Robert Griesemer <gri@golang.org> | 2021-06-30 18:58:34 +0000 |
commit | 4b5fdb0b7a362cb6fa6ad551757104e490483121 (patch) | |
tree | a2d35fe408f7c5fb8d2fd8836481a23d023844c3 /src/cmd/compile/internal/types2/interface.go | |
parent | f503740ccf6302ed13c7722ea50c6880a17703fb (diff) | |
download | go-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.go | 64 |
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) { |