From ede27fb4aca9ab103413aff71b254f10db2b302a Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Mon, 9 Oct 2023 13:31:25 -0400 Subject: [PATCH] go/types: clarify semantics of Selection This is one of the more complex areas of the (pre-generics) spec, and I'm probably not the only person who can never remember all the details each time I need them. Change-Id: I25b3c46311df4db33357af5601c5e3586327dac2 Reviewed-on: https://go-review.googlesource.com/c/go/+/533736 Reviewed-by: Robert Griesemer LUCI-TryBot-Result: Go LUCI Auto-Submit: Alan Donovan --- src/cmd/compile/internal/types2/selection.go | 33 ++++++++++++++++++++ src/go/types/selection.go | 33 ++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/src/cmd/compile/internal/types2/selection.go b/src/cmd/compile/internal/types2/selection.go index c820a29fad..0fa771938d 100644 --- a/src/cmd/compile/internal/types2/selection.go +++ b/src/cmd/compile/internal/types2/selection.go @@ -13,6 +13,39 @@ import ( // SelectionKind describes the kind of a selector expression x.f // (excluding qualified identifiers). +// +// If x is a struct or *struct, a selector expression x.f may denote a +// sequence of selection operations x.a.b.c.f. The SelectionKind +// describes the kind of the final (explicit) operation; all the +// previous (implicit) operations are always field selections. +// Each element of Indices specifies an implicit field (a, b, c) +// by its index in the struct type of the field selection operand. +// +// For a FieldVal operation, the final selection refers to the field +// specified by Selection.Obj. +// +// For a MethodVal operation, the final selection refers to a method. +// If the "pointerness" of the method's declared receiver does not +// match that of the effective receiver after implicit field +// selection, then an & or * operation is implicitly applied to the +// receiver variable or value. +// So, x.f denotes (&x.a.b.c).f when f requires a pointer receiver but +// x.a.b.c is a non-pointer variable; and it denotes (*x.a.b.c).f when +// f requires a non-pointer receiver but x.a.b.c is a pointer value. +// +// All pointer indirections, whether due to implicit or explicit field +// selections or * operations inserted for "pointerness", panic if +// applied to a nil pointer, so a method call x.f() may panic even +// before the function call. +// +// By contrast, a MethodExpr operation T.f is essentially equivalent +// to a function literal of the form: +// +// func(x T, args) (results) { return x.f(args) } +// +// Consequently, any implicit field selections and * operations +// inserted for "pointerness" are not evaluated until the function is +// called, so a T.f or (*T).f expression never panics. type SelectionKind int const ( diff --git a/src/go/types/selection.go b/src/go/types/selection.go index c79e13c6eb..02615846b8 100644 --- a/src/go/types/selection.go +++ b/src/go/types/selection.go @@ -15,6 +15,39 @@ import ( // SelectionKind describes the kind of a selector expression x.f // (excluding qualified identifiers). +// +// If x is a struct or *struct, a selector expression x.f may denote a +// sequence of selection operations x.a.b.c.f. The SelectionKind +// describes the kind of the final (explicit) operation; all the +// previous (implicit) operations are always field selections. +// Each element of Indices specifies an implicit field (a, b, c) +// by its index in the struct type of the field selection operand. +// +// For a FieldVal operation, the final selection refers to the field +// specified by Selection.Obj. +// +// For a MethodVal operation, the final selection refers to a method. +// If the "pointerness" of the method's declared receiver does not +// match that of the effective receiver after implicit field +// selection, then an & or * operation is implicitly applied to the +// receiver variable or value. +// So, x.f denotes (&x.a.b.c).f when f requires a pointer receiver but +// x.a.b.c is a non-pointer variable; and it denotes (*x.a.b.c).f when +// f requires a non-pointer receiver but x.a.b.c is a pointer value. +// +// All pointer indirections, whether due to implicit or explicit field +// selections or * operations inserted for "pointerness", panic if +// applied to a nil pointer, so a method call x.f() may panic even +// before the function call. +// +// By contrast, a MethodExpr operation T.f is essentially equivalent +// to a function literal of the form: +// +// func(x T, args) (results) { return x.f(args) } +// +// Consequently, any implicit field selections and * operations +// inserted for "pointerness" are not evaluated until the function is +// called, so a T.f or (*T).f expression never panics. type SelectionKind int const ( -- 2.50.0