From: Robert Griesemer Date: Wed, 21 Jan 2026 23:11:13 +0000 (-0800) Subject: go/types, types: flip field/method selection logic inside out (cleanup) X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=6d89ab44cc783abb68d511e88723c2b8ebf4ca3b;p=gostls13.git go/types, types: flip field/method selection logic inside out (cleanup) 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 Commit-Queue: Robert Griesemer Reviewed-by: Robert Griesemer LUCI-TryBot-Result: Go LUCI Auto-Submit: Robert Griesemer --- diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index dfbb0a5491..c23a1048f2 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -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 diff --git a/src/go/types/call.go b/src/go/types/call.go index 56800c0ac8..1b62569d8f 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -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