Skip to content

Commit

Permalink
go/types: fix method set computation
Browse files Browse the repository at this point in the history
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 golang#37081.

Change-Id: Ic1937e01891b3614a6f7965d4384aeb485f3fe3e
Reviewed-on: https://go-review.googlesource.com/c/go/+/218617
Reviewed-by: Alan Donovan <[email protected]>
  • Loading branch information
griesemer committed Mar 2, 2020
1 parent 97a2686 commit ca3dd1d
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 11 deletions.
11 changes: 11 additions & 0 deletions src/go/types/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -147,13 +150,21 @@ 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
//
// 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
Expand Down
20 changes: 9 additions & 11 deletions src/go/types/methodset.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,17 +166,15 @@ 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 {
if _, found := base[k]; !found {
if base == nil {
base = make(methodSet)
}
base[k] = nil // collision
// 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)
}
base[k] = nil // collision
}
}

Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit ca3dd1d

Please sign in to comment.