]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: fix method set computation
authorRobert Griesemer <gri@golang.org>
Fri, 7 Feb 2020 23:26:19 +0000 (15:26 -0800)
committerRobert Griesemer <gri@golang.org>
Mon, 2 Mar 2020 22:18:30 +0000 (22:18 +0000)
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>
src/go/types/example_test.go
src/go/types/methodset.go

index b8fba7312ae3e2ae5485017229e9b2f5c3ae1133..3747f3b15a08d94fa4bdd4175d81231efd4cdc91 100644 (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
index a236fe2ea8b3abb640fbfe6b68810bbe70f62422..aacbb0f82a35a39be383ff30b907dfc22cd5087a 100644 (file)
@@ -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
                        }
                }
 
@@ -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.