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:
parent
97a268624c
commit
ca3dd1d36b
@ -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
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user