]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types: flip field/method selection logic inside out (cleanup)
authorRobert Griesemer <gri@google.com>
Wed, 21 Jan 2026 23:11:13 +0000 (15:11 -0800)
committerGopher Robot <gobot@golang.org>
Fri, 23 Jan 2026 17:18:50 +0000 (09:18 -0800)
By selecting on *Var/*Func first, the field/method selection logic
becomes a bit cleaner, clearer, and a little bit simpler.

No functional changes.

Change-Id: I9860f98d52779b0f7ce4484ea77e74a3667d9e6b
Reviewed-on: https://go-review.googlesource.com/c/go/+/738080
Reviewed-by: Alan Donovan <adonovan@google.com>
Commit-Queue: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Robert Griesemer <gri@google.com>

src/cmd/compile/internal/types2/call.go
src/go/types/call.go

index dfbb0a5491eaebd7b6c91448a8b0e5dc7a2934d1..c23a1048f23d7d8c69bc633e2196ed26501acf22 100644 (file)
@@ -837,71 +837,67 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, wantType bool
        }
        // obj != nil
 
-       // methods may not have a fully set up signature yet
-       if m, _ := obj.(*Func); m != nil {
-               check.objDecl(m)
-       }
-
-       if x.mode == typexpr {
-               // method expression
-               m, _ := obj.(*Func)
-               if m == nil {
+       switch obj := obj.(type) {
+       case *Var:
+               if x.mode == typexpr {
                        check.errorf(e.X, MissingFieldOrMethod, "operand for field selector %s must be value of type %s", sel, x.typ)
                        goto Error
                }
 
-               check.recordSelection(e, MethodExpr, x.typ, m, index, indirect)
-
-               sig := m.typ.(*Signature)
-               if sig.recv == nil {
-                       check.error(e, InvalidDeclCycle, "illegal cycle in method declaration")
-                       goto Error
+               // field value
+               check.recordSelection(e, FieldVal, x.typ, obj, index, indirect)
+               if x.mode == variable || indirect {
+                       x.mode = variable
+               } else {
+                       x.mode = value
                }
+               x.typ = obj.typ
 
-               // The receiver type becomes the type of the first function
-               // argument of the method expression's function type.
-               var params []*Var
-               if sig.params != nil {
-                       params = sig.params.vars
-               }
-               // Be consistent about named/unnamed parameters. This is not needed
-               // for type-checking, but the newly constructed signature may appear
-               // in an error message and then have mixed named/unnamed parameters.
-               // (An alternative would be to not print parameter names in errors,
-               // but it's useful to see them; this is cheap and method expressions
-               // are rare.)
-               name := ""
-               if len(params) > 0 && params[0].name != "" {
-                       // name needed
-                       name = sig.recv.name
-                       if name == "" {
-                               name = "_"
-                       }
-               }
-               params = append([]*Var{NewParam(sig.recv.pos, sig.recv.pkg, name, x.typ)}, params...)
-               x.mode = value
-               x.typ = &Signature{
-                       tparams:  sig.tparams,
-                       params:   NewTuple(params...),
-                       results:  sig.results,
-                       variadic: sig.variadic,
-               }
+       case *Func:
+               check.objDecl(obj) // ensure fully set-up signature
+               check.addDeclDep(obj)
 
-               check.addDeclDep(m)
+               if x.mode == typexpr {
+                       // method expression
+                       check.recordSelection(e, MethodExpr, x.typ, obj, index, indirect)
 
-       } else {
-               // regular selector
-               switch obj := obj.(type) {
-               case *Var:
-                       check.recordSelection(e, FieldVal, x.typ, obj, index, indirect)
-                       if x.mode == variable || indirect {
-                               x.mode = variable
-                       } else {
-                               x.mode = value
+                       sig := obj.typ.(*Signature)
+                       if sig.recv == nil {
+                               check.error(e, InvalidDeclCycle, "illegal cycle in method declaration")
+                               goto Error
+                       }
+
+                       // The receiver type becomes the type of the first function
+                       // argument of the method expression's function type.
+                       var params []*Var
+                       if sig.params != nil {
+                               params = sig.params.vars
+                       }
+                       // Be consistent about named/unnamed parameters. This is not needed
+                       // for type-checking, but the newly constructed signature may appear
+                       // in an error message and then have mixed named/unnamed parameters.
+                       // (An alternative would be to not print parameter names in errors,
+                       // but it's useful to see them; this is cheap and method expressions
+                       // are rare.)
+                       name := ""
+                       if len(params) > 0 && params[0].name != "" {
+                               // name needed
+                               name = sig.recv.name
+                               if name == "" {
+                                       name = "_"
+                               }
+                       }
+                       params = append([]*Var{NewParam(sig.recv.pos, sig.recv.pkg, name, x.typ)}, params...)
+                       x.mode = value
+                       x.typ = &Signature{
+                               tparams:  sig.tparams,
+                               params:   NewTuple(params...),
+                               results:  sig.results,
+                               variadic: sig.variadic,
                        }
-                       x.typ = obj.typ
+               } else {
+                       // method value
 
-               case *Func:
                        // TODO(gri) If we needed to take into account the receiver's
                        // addressability, should we report the type &(x.typ) instead?
                        check.recordSelection(e, MethodVal, x.typ, obj, index, indirect)
@@ -912,12 +908,10 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, wantType bool
                        sig := *obj.typ.(*Signature)
                        sig.recv = nil
                        x.typ = &sig
-
-                       check.addDeclDep(obj)
-
-               default:
-                       panic("unreachable")
                }
+
+       default:
+               panic("unreachable")
        }
 
        // everything went well
index 56800c0ac8c4f8c833f1fb210358459d1a674ea1..1b62569d8f0362ccea6db540684d3d23e9d497fb 100644 (file)
@@ -840,71 +840,67 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, wantType bool) {
        }
        // obj != nil
 
-       // methods may not have a fully set up signature yet
-       if m, _ := obj.(*Func); m != nil {
-               check.objDecl(m)
-       }
-
-       if x.mode == typexpr {
-               // method expression
-               m, _ := obj.(*Func)
-               if m == nil {
+       switch obj := obj.(type) {
+       case *Var:
+               if x.mode == typexpr {
                        check.errorf(e.X, MissingFieldOrMethod, "operand for field selector %s must be value of type %s", sel, x.typ)
                        goto Error
                }
 
-               check.recordSelection(e, MethodExpr, x.typ, m, index, indirect)
-
-               sig := m.typ.(*Signature)
-               if sig.recv == nil {
-                       check.error(e, InvalidDeclCycle, "illegal cycle in method declaration")
-                       goto Error
+               // field value
+               check.recordSelection(e, FieldVal, x.typ, obj, index, indirect)
+               if x.mode == variable || indirect {
+                       x.mode = variable
+               } else {
+                       x.mode = value
                }
+               x.typ = obj.typ
 
-               // the receiver type becomes the type of the first function
-               // argument of the method expression's function type
-               var params []*Var
-               if sig.params != nil {
-                       params = sig.params.vars
-               }
-               // Be consistent about named/unnamed parameters. This is not needed
-               // for type-checking, but the newly constructed signature may appear
-               // in an error message and then have mixed named/unnamed parameters.
-               // (An alternative would be to not print parameter names in errors,
-               // but it's useful to see them; this is cheap and method expressions
-               // are rare.)
-               name := ""
-               if len(params) > 0 && params[0].name != "" {
-                       // name needed
-                       name = sig.recv.name
-                       if name == "" {
-                               name = "_"
-                       }
-               }
-               params = append([]*Var{NewParam(sig.recv.pos, sig.recv.pkg, name, x.typ)}, params...)
-               x.mode = value
-               x.typ = &Signature{
-                       tparams:  sig.tparams,
-                       params:   NewTuple(params...),
-                       results:  sig.results,
-                       variadic: sig.variadic,
-               }
+       case *Func:
+               check.objDecl(obj) // ensure fully set-up signature
+               check.addDeclDep(obj)
 
-               check.addDeclDep(m)
+               if x.mode == typexpr {
+                       // method expression
+                       check.recordSelection(e, MethodExpr, x.typ, obj, index, indirect)
 
-       } else {
-               // regular selector
-               switch obj := obj.(type) {
-               case *Var:
-                       check.recordSelection(e, FieldVal, x.typ, obj, index, indirect)
-                       if x.mode == variable || indirect {
-                               x.mode = variable
-                       } else {
-                               x.mode = value
+                       sig := obj.typ.(*Signature)
+                       if sig.recv == nil {
+                               check.error(e, InvalidDeclCycle, "illegal cycle in method declaration")
+                               goto Error
+                       }
+
+                       // The receiver type becomes the type of the first function
+                       // argument of the method expression's function type.
+                       var params []*Var
+                       if sig.params != nil {
+                               params = sig.params.vars
+                       }
+                       // Be consistent about named/unnamed parameters. This is not needed
+                       // for type-checking, but the newly constructed signature may appear
+                       // in an error message and then have mixed named/unnamed parameters.
+                       // (An alternative would be to not print parameter names in errors,
+                       // but it's useful to see them; this is cheap and method expressions
+                       // are rare.)
+                       name := ""
+                       if len(params) > 0 && params[0].name != "" {
+                               // name needed
+                               name = sig.recv.name
+                               if name == "" {
+                                       name = "_"
+                               }
+                       }
+                       params = append([]*Var{NewParam(sig.recv.pos, sig.recv.pkg, name, x.typ)}, params...)
+                       x.mode = value
+                       x.typ = &Signature{
+                               tparams:  sig.tparams,
+                               params:   NewTuple(params...),
+                               results:  sig.results,
+                               variadic: sig.variadic,
                        }
-                       x.typ = obj.typ
+               } else {
+                       // method value
 
-               case *Func:
                        // TODO(gri) If we needed to take into account the receiver's
                        // addressability, should we report the type &(x.typ) instead?
                        check.recordSelection(e, MethodVal, x.typ, obj, index, indirect)
@@ -960,12 +956,10 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, wantType bool) {
                        sig := *obj.typ.(*Signature)
                        sig.recv = nil
                        x.typ = &sig
-
-                       check.addDeclDep(obj)
-
-               default:
-                       panic("unreachable")
                }
+
+       default:
+               panic("unreachable")
        }
 
        // everything went well