aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2021-01-22 16:59:45 -0800
committerRobert Griesemer <gri@golang.org>2021-01-23 01:57:35 +0000
commita49e9410276975d187a5cfda1a396194c45d4464 (patch)
treeb8fc9e70e84289f514cc6168ebf5b970710939ea
parent5347241b5e64eb9a7b0ef97b12d899f32a05c2b8 (diff)
downloadgo-a49e9410276975d187a5cfda1a396194c45d4464.tar.gz
go-a49e9410276975d187a5cfda1a396194c45d4464.zip
[dev.typeparams] cmd/compile/internal/types2: remove MethodSet code - not used by types2
We can always re-introduce it if we decide to make use of it. Change-Id: Ia939fdae978568edc58e21d1af732c6137744aab Reviewed-on: https://go-review.googlesource.com/c/go/+/285678 Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
-rw-r--r--src/cmd/compile/internal/importer/gcimporter_test.go5
-rw-r--r--src/cmd/compile/internal/types2/call.go45
-rw-r--r--src/cmd/compile/internal/types2/example_test.go55
-rw-r--r--src/cmd/compile/internal/types2/lookup.go19
-rw-r--r--src/cmd/compile/internal/types2/methodset.go262
5 files changed, 21 insertions, 365 deletions
diff --git a/src/cmd/compile/internal/importer/gcimporter_test.go b/src/cmd/compile/internal/importer/gcimporter_test.go
index a275524484..7fb8fed59c 100644
--- a/src/cmd/compile/internal/importer/gcimporter_test.go
+++ b/src/cmd/compile/internal/importer/gcimporter_test.go
@@ -384,9 +384,8 @@ func TestCorrectMethodPackage(t *testing.T) {
}
mutex := imports["sync"].Scope().Lookup("Mutex").(*types2.TypeName).Type()
- mset := types2.NewMethodSet(types2.NewPointer(mutex)) // methods of *sync.Mutex
- sel := mset.Lookup(nil, "Lock")
- lock := sel.Obj().(*types2.Func)
+ obj, _, _ := types2.LookupFieldOrMethod(types2.NewPointer(mutex), false, nil, "Lock")
+ lock := obj.(*types2.Func)
if got, want := lock.Pkg().Path(), "sync"; got != want {
t.Errorf("got package path %q; want %q", got, want)
}
diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go
index 5a7ae221e6..72a33b50b1 100644
--- a/src/cmd/compile/internal/types2/call.go
+++ b/src/cmd/compile/internal/types2/call.go
@@ -685,51 +685,6 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
// addressability, should we report the type &(x.typ) instead?
check.recordSelection(e, MethodVal, x.typ, obj, index, indirect)
- // TODO(gri) The verification pass below is disabled for now because
- // method sets don't match method lookup in some cases.
- // For instance, if we made a copy above when creating a
- // custom method for a parameterized received type, the
- // method set method doesn't match (no copy there). There
- /// may be other situations.
- disabled := true
- if !disabled && debug {
- // Verify that LookupFieldOrMethod and MethodSet.Lookup agree.
- // TODO(gri) This only works because we call LookupFieldOrMethod
- // _before_ calling NewMethodSet: LookupFieldOrMethod completes
- // any incomplete interfaces so they are available to NewMethodSet
- // (which assumes that interfaces have been completed already).
- typ := x.typ
- if x.mode == variable {
- // If typ is not an (unnamed) pointer or an interface,
- // use *typ instead, because the method set of *typ
- // includes the methods of typ.
- // Variables are addressable, so we can always take their
- // address.
- if _, ok := typ.(*Pointer); !ok && !IsInterface(typ) {
- typ = &Pointer{base: typ}
- }
- }
- // If we created a synthetic pointer type above, we will throw
- // away the method set computed here after use.
- // TODO(gri) Method set computation should probably always compute
- // both, the value and the pointer receiver method set and represent
- // them in a single structure.
- // TODO(gri) Consider also using a method set cache for the lifetime
- // of checker once we rely on MethodSet lookup instead of individual
- // lookup.
- mset := NewMethodSet(typ)
- if m := mset.Lookup(check.pkg, sel); m == nil || m.obj != obj {
- check.dump("%v: (%s).%v -> %s", posFor(e), typ, obj.name, m)
- check.dump("%s\n", mset)
- // Caution: MethodSets are supposed to be used externally
- // only (after all interface types were completed). It's
- // now possible that we get here incorrectly. Not urgent
- // to fix since we only run this code in debug mode.
- // TODO(gri) fix this eventually.
- panic("method sets and lookup don't agree")
- }
- }
-
x.mode = value
// remove receiver
diff --git a/src/cmd/compile/internal/types2/example_test.go b/src/cmd/compile/internal/types2/example_test.go
index dcdeaca0c0..ffd54fe459 100644
--- a/src/cmd/compile/internal/types2/example_test.go
+++ b/src/cmd/compile/internal/types2/example_test.go
@@ -107,61 +107,6 @@ func Unused() { {}; {{ var x int; _ = x }} } // make sure empty block scopes get
// }
}
-// ExampleMethodSet prints the method sets of various types.
-func ExampleMethodSet() {
- // Parse a single source file.
- const input = `
-package temperature
-import "fmt"
-type Celsius float64
-func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
-func (c *Celsius) SetF(f float64) { *c = Celsius(f - 32 / 9 * 5) }
-
-type S struct { I; m int }
-type I interface { m() byte }
-`
- f, err := parseSrc("celsius.go", input)
- if err != nil {
- log.Fatal(err)
- }
-
- // Type-check a package consisting of this file.
- // Type information for the imported packages
- // comes from $GOROOT/pkg/$GOOS_$GOOARCH/fmt.a.
- conf := types2.Config{Importer: defaultImporter()}
- pkg, err := conf.Check("temperature", []*syntax.File{f}, nil)
- if err != nil {
- log.Fatal(err)
- }
-
- // Print the method sets of Celsius and *Celsius.
- celsius := pkg.Scope().Lookup("Celsius").Type()
- for _, t := range []types2.Type{celsius, types2.NewPointer(celsius)} {
- fmt.Printf("Method set of %s:\n", t)
- mset := types2.NewMethodSet(t)
- for i := 0; i < mset.Len(); i++ {
- fmt.Println(mset.At(i))
- }
- fmt.Println()
- }
-
- // Print the method set of S.
- styp := pkg.Scope().Lookup("S").Type()
- fmt.Printf("Method set of %s:\n", styp)
- fmt.Println(types2.NewMethodSet(styp))
-
- // Output:
- // Method set of temperature.Celsius:
- // method (temperature.Celsius) String() string
- //
- // Method set of *temperature.Celsius:
- // method (*temperature.Celsius) SetF(f float64)
- // method (*temperature.Celsius) String() string
- //
- // Method set of temperature.S:
- // MethodSet {}
-}
-
// ExampleInfo prints various facts recorded by the type checker in a
// types2.Info struct: definitions of and references to each named object,
// and the type, value, and mode of every expression in the package.
diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go
index e1e7b5814d..5dfb8bfee7 100644
--- a/src/cmd/compile/internal/types2/lookup.go
+++ b/src/cmd/compile/internal/types2/lookup.go
@@ -491,3 +491,22 @@ func lookupMethod(methods []*Func, pkg *Package, name string) (int, *Func) {
}
return -1, nil
}
+
+// ptrRecv reports whether the receiver is of the form *T.
+func ptrRecv(f *Func) bool {
+ // If a method's receiver type is set, use that as the source of truth for the receiver.
+ // Caution: Checker.funcDecl (decl.go) marks a function by setting its type to an empty
+ // signature. We may reach here before the signature is fully set up: we must explicitly
+ // check if the receiver is set (we cannot just look for non-nil f.typ).
+ if sig, _ := f.typ.(*Signature); sig != nil && sig.recv != nil {
+ _, isPtr := deref(sig.recv.typ)
+ return isPtr
+ }
+
+ // If a method's type is not set it may be a method/function that is:
+ // 1) client-supplied (via NewFunc with no signature), or
+ // 2) internally created but not yet type-checked.
+ // For case 1) we can't do anything; the client must know what they are doing.
+ // For case 2) we can use the information gathered by the resolver.
+ return f.hasPtrRecv
+}
diff --git a/src/cmd/compile/internal/types2/methodset.go b/src/cmd/compile/internal/types2/methodset.go
deleted file mode 100644
index eb8f1221cc..0000000000
--- a/src/cmd/compile/internal/types2/methodset.go
+++ /dev/null
@@ -1,262 +0,0 @@
-// UNREVIEWED
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file implements method sets.
-
-package types2
-
-import (
- "bytes"
- "fmt"
- "sort"
-)
-
-// A MethodSet is an ordered set of concrete or abstract (interface) methods;
-// a method is a MethodVal selection, and they are ordered by ascending m.Obj().Id().
-// The zero value for a MethodSet is a ready-to-use empty method set.
-type MethodSet struct {
- list []*Selection
-}
-
-func (s *MethodSet) String() string {
- if s.Len() == 0 {
- return "MethodSet {}"
- }
-
- // Would like to use strings.Builder but it's not available in Go 1.4.
- var buf bytes.Buffer
- fmt.Fprintln(&buf, "MethodSet {")
- for _, f := range s.list {
- fmt.Fprintf(&buf, "\t%s\n", f)
- }
- fmt.Fprintln(&buf, "}")
- return buf.String()
-}
-
-// Len returns the number of methods in s.
-func (s *MethodSet) Len() int { return len(s.list) }
-
-// At returns the i'th method in s for 0 <= i < s.Len().
-func (s *MethodSet) At(i int) *Selection { return s.list[i] }
-
-// Lookup returns the method with matching package and name, or nil if not found.
-func (s *MethodSet) Lookup(pkg *Package, name string) *Selection {
- if s.Len() == 0 {
- return nil
- }
-
- key := Id(pkg, name)
- i := sort.Search(len(s.list), func(i int) bool {
- m := s.list[i]
- return m.obj.Id() >= key
- })
- if i < len(s.list) {
- m := s.list[i]
- if m.obj.Id() == key {
- return m
- }
- }
- return nil
-}
-
-// Shared empty method set.
-var emptyMethodSet MethodSet
-
-// Note: NewMethodSet is intended for external use only as it
-// requires interfaces to be complete. If may be used
-// internally if LookupFieldOrMethod completed the same
-// interfaces beforehand.
-
-// NewMethodSet returns the method set for the given type T.
-// It always returns a non-nil method set, even if it is empty.
-func NewMethodSet(T Type) *MethodSet {
- // WARNING: The code in this function is extremely subtle - do not modify casually!
- // This function and lookupFieldOrMethod should be kept in sync.
-
- // method set up to the current depth, allocated lazily
- var base methodSet
-
- typ, isPtr := deref(T)
-
- // *typ where typ is an interface has no methods.
- if isPtr && IsInterface(typ) {
- return &emptyMethodSet
- }
-
- // Start with typ as single entry at shallowest depth.
- current := []embeddedType{{typ, nil, isPtr, false}}
-
- // Named types that we have seen already, allocated lazily.
- // Used to avoid endless searches in case of recursive types.
- // Since only Named types can be used for recursive types, we
- // only need to track those.
- // (If we ever allow type aliases to construct recursive types,
- // we must use type identity rather than pointer equality for
- // the map key comparison, as we do in consolidateMultiples.)
- var seen map[*Named]bool
-
- // collect methods at current depth
- for len(current) > 0 {
- var next []embeddedType // embedded types found at current depth
-
- // field and method sets at current depth, indexed by names (Id's), and allocated lazily
- var fset map[string]bool // we only care about the field names
- var mset methodSet
-
- for _, e := range current {
- typ := e.typ
-
- // If we have a named type, we may have associated methods.
- // Look for those first.
- if named := typ.Named(); named != nil {
- if seen[named] {
- // We have seen this type before, at a more shallow depth
- // (note that multiples of this type at the current depth
- // were consolidated before). The type at that depth shadows
- // this same type at the current depth, so we can ignore
- // this one.
- continue
- }
- if seen == nil {
- seen = make(map[*Named]bool)
- }
- seen[named] = true
-
- mset = mset.add(named.methods, e.index, e.indirect, e.multiples)
-
- // continue with underlying type
- typ = named.underlying
- }
-
- switch t := typ.(type) {
- case *Struct:
- for i, f := range t.fields {
- if fset == nil {
- fset = make(map[string]bool)
- }
- fset[f.Id()] = true
-
- // Embedded fields are always of the form T or *T where
- // T is a type name. If typ appeared multiple times at
- // this depth, f.Type appears multiple times at the next
- // depth.
- if f.embedded {
- typ, isPtr := deref(f.typ)
- // TODO(gri) optimization: ignore types that can't
- // have fields or methods (only Named, Struct, and
- // Interface types need to be considered).
- next = append(next, embeddedType{typ, concat(e.index, i), e.indirect || isPtr, e.multiples})
- }
- }
-
- case *Interface:
- mset = mset.add(t.allMethods, e.index, true, e.multiples)
- }
- }
-
- // Add methods and collisions at this depth to base if no entries with matching
- // names exist already.
- for k, m := range mset {
- if _, found := base[k]; !found {
- // Fields collide with methods of the same name at this depth.
- if fset[k] {
- m = nil // collision
- }
- if base == nil {
- base = make(methodSet)
- }
- base[k] = m
- }
- }
-
- // Add all (remaining) fields at this depth as collisions (since they will
- // hide any method further down) if no entries with matching names exist already.
- for k := range fset {
- if _, found := base[k]; !found {
- if base == nil {
- base = make(methodSet)
- }
- base[k] = nil // collision
- }
- }
-
- // It's ok to call consolidateMultiples with a nil *Checker because
- // MethodSets are not used internally (outside debug mode). When used
- // externally, interfaces are expected to be completed and then we do
- // not need a *Checker to complete them when (indirectly) calling
- // Checker.identical via consolidateMultiples.
- current = (*Checker)(nil).consolidateMultiples(next)
- }
-
- if len(base) == 0 {
- return &emptyMethodSet
- }
-
- // collect methods
- var list []*Selection
- for _, m := range base {
- if m != nil {
- m.recv = T
- list = append(list, m)
- }
- }
- // sort by unique name
- sort.Slice(list, func(i, j int) bool {
- return list[i].obj.Id() < list[j].obj.Id()
- })
- return &MethodSet{list}
-}
-
-// A methodSet is a set of methods and name collisions.
-// A collision indicates that multiple methods with the
-// same unique id, or a field with that id appeared.
-type methodSet map[string]*Selection // a nil entry indicates a name collision
-
-// Add adds all functions in list to the method set s.
-// If multiples is set, every function in list appears multiple times
-// and is treated as a collision.
-func (s methodSet) add(list []*Func, index []int, indirect bool, multiples bool) methodSet {
- if len(list) == 0 {
- return s
- }
- if s == nil {
- s = make(methodSet)
- }
- for i, f := range list {
- key := f.Id()
- // if f is not in the set, add it
- if !multiples {
- // TODO(gri) A found method may not be added because it's not in the method set
- // (!indirect && ptrRecv(f)). A 2nd method on the same level may be in the method
- // set and may not collide with the first one, thus leading to a false positive.
- // Is that possible? Investigate.
- if _, found := s[key]; !found && (indirect || !ptrRecv(f)) {
- s[key] = &Selection{MethodVal, nil, f, concat(index, i), indirect}
- continue
- }
- }
- s[key] = nil // collision
- }
- return s
-}
-
-// ptrRecv reports whether the receiver is of the form *T.
-func ptrRecv(f *Func) bool {
- // If a method's receiver type is set, use that as the source of truth for the receiver.
- // Caution: Checker.funcDecl (decl.go) marks a function by setting its type to an empty
- // signature. We may reach here before the signature is fully set up: we must explicitly
- // check if the receiver is set (we cannot just look for non-nil f.typ).
- if sig, _ := f.typ.(*Signature); sig != nil && sig.recv != nil {
- _, isPtr := deref(sig.recv.typ)
- return isPtr
- }
-
- // If a method's type is not set it may be a method/function that is:
- // 1) client-supplied (via NewFunc with no signature), or
- // 2) internally created but not yet type-checked.
- // For case 1) we can't do anything; the client must know what they are doing.
- // For case 2) we can use the information gathered by the resolver.
- return f.hasPtrRecv
-}