1
0
mirror of https://github.com/golang/go synced 2024-11-17 18:24:45 -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
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 }
`
fset := token.NewFileSet()
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()
}
// 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:
// Method set of temperature.Celsius:
// 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 (*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

View File

@ -166,11 +166,10 @@ func NewMethodSet(T Type) *MethodSet {
}
}
// Multiple fields with matching names collide at this depth and shadow all
// entries further down; add them as collisions to base if no entries with
// matching names exist already.
for k, f := range fset {
if f == nil {
// Add all fields at this depth as collisions (since they will hide any
// method further down) to base if no entries with matching names exist
// already.
for k := range fset {
if _, found := base[k]; !found {
if base == nil {
base = make(methodSet)
@ -178,7 +177,6 @@ func NewMethodSet(T Type) *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
@ -233,7 +231,7 @@ func (s fieldSet) add(f *Var, multiples bool) fieldSet {
// A methodSet is a set of methods and name collisions.
// 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
// Add adds all functions in list to the method set s.