1
0
mirror of https://github.com/golang/go synced 2024-11-17 20:24:46 -07:00

go/types: fix method set computation

When computing method sets, any struct field that "shadows" a
method at a lower embedding level eliminates that method from
the method set. Treat any field at a given level as a "collision"
for any methods at lower embedding level.

Method sets are not directly used by go/types (except for self-
verification in debug mode); they are a functionality provided
by go/types. Thus, the method sets that go/types is using were
not affected by this bug.

Fixes #37081.

Change-Id: Ic1937e01891b3614a6f7965d4384aeb485f3fe3e
Reviewed-on: https://go-review.googlesource.com/c/go/+/218617
Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
Robert Griesemer 2020-02-07 15:26:19 -08:00
parent 97a268624c
commit ca3dd1d36b
2 changed files with 20 additions and 11 deletions

View File

@ -120,6 +120,9 @@ import "fmt"
type Celsius float64 type Celsius float64
func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) } func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
func (c *Celsius) SetF(f float64) { *c = Celsius(f - 32 / 9 * 5) } func (c *Celsius) SetF(f float64) { *c = Celsius(f - 32 / 9 * 5) }
type S struct { I; m int }
type I interface { m() byte }
` `
fset := token.NewFileSet() fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "celsius.go", input, 0) f, err := parser.ParseFile(fset, "celsius.go", input, 0)
@ -147,6 +150,11 @@ func (c *Celsius) SetF(f float64) { *c = Celsius(f - 32 / 9 * 5) }
fmt.Println() fmt.Println()
} }
// Print the method set of S.
styp := pkg.Scope().Lookup("S").Type()
fmt.Printf("Method set of %s:\n", styp)
fmt.Println(types.NewMethodSet(styp))
// Output: // Output:
// Method set of temperature.Celsius: // Method set of temperature.Celsius:
// method (temperature.Celsius) String() string // method (temperature.Celsius) String() string
@ -154,6 +162,9 @@ func (c *Celsius) SetF(f float64) { *c = Celsius(f - 32 / 9 * 5) }
// Method set of *temperature.Celsius: // Method set of *temperature.Celsius:
// method (*temperature.Celsius) SetF(f float64) // method (*temperature.Celsius) SetF(f float64)
// method (*temperature.Celsius) String() string // method (*temperature.Celsius) String() string
//
// Method set of temperature.S:
// MethodSet {}
} }
// ExampleInfo prints various facts recorded by the type checker in a // ExampleInfo prints various facts recorded by the type checker in a

View File

@ -166,11 +166,10 @@ func NewMethodSet(T Type) *MethodSet {
} }
} }
// Multiple fields with matching names collide at this depth and shadow all // Add all fields at this depth as collisions (since they will hide any
// entries further down; add them as collisions to base if no entries with // method further down) to base if no entries with matching names exist
// matching names exist already. // already.
for k, f := range fset { for k := range fset {
if f == nil {
if _, found := base[k]; !found { if _, found := base[k]; !found {
if base == nil { if base == nil {
base = make(methodSet) base = make(methodSet)
@ -178,7 +177,6 @@ func NewMethodSet(T Type) *MethodSet {
base[k] = nil // collision base[k] = nil // collision
} }
} }
}
// It's ok to call consolidateMultiples with a nil *Checker because // It's ok to call consolidateMultiples with a nil *Checker because
// MethodSets are not used internally (outside debug mode). When used // MethodSets are not used internally (outside debug mode). When used
@ -233,7 +231,7 @@ func (s fieldSet) add(f *Var, multiples bool) fieldSet {
// A methodSet is a set of methods and name collisions. // A methodSet is a set of methods and name collisions.
// A collision indicates that multiple methods with the // A collision indicates that multiple methods with the
// same unique id appeared. // same unique id, or a field with that id appeared.
type methodSet map[string]*Selection // a nil entry indicates a name collision type methodSet map[string]*Selection // a nil entry indicates a name collision
// Add adds all functions in list to the method set s. // Add adds all functions in list to the method set s.