From a977717393fd779921ca258988230dbc741f5912 Mon Sep 17 00:00:00 2001 From: Mark Freeman Date: Tue, 20 Jan 2026 14:23:19 -0500 Subject: [PATCH] go/types, types2: add check for map value completeness in IndexExpr An index expression can also go from map[K]V to V. Since V could be incomplete (due to some admittedly contrived syntax), we need a check. Change-Id: I03ffbfc0e5bcc9129591d60dfbaa5fafcf8fb183 Reviewed-on: https://go-review.googlesource.com/c/go/+/737620 LUCI-TryBot-Result: Go LUCI Reviewed-by: Robert Griesemer Auto-Submit: Mark Freeman --- src/cmd/compile/internal/types2/index.go | 20 +++++++++++++++----- src/go/types/index.go | 20 +++++++++++++++----- src/internal/types/testdata/check/cycles6.go | 2 ++ 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/cmd/compile/internal/types2/index.go b/src/cmd/compile/internal/types2/index.go index 98d83833c8..5b52cea837 100644 --- a/src/cmd/compile/internal/types2/index.go +++ b/src/cmd/compile/internal/types2/index.go @@ -52,11 +52,21 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo x.mode = invalid return false } - // Additionally, if x.typ is a pointer to an array type, indexing implicitly dereferences the value, meaning - // its base type must also be complete. - if p, ok := x.typ.Underlying().(*Pointer); ok && !check.isComplete(p.base) { - x.mode = invalid - return false + switch typ := x.typ.Underlying().(type) { + case *Pointer: + // Additionally, if x.typ is a pointer to an array type, indexing implicitly dereferences the value, meaning + // its base type must also be complete. + if !check.isComplete(typ.base) { + x.mode = invalid + return false + } + case *Map: + // Lastly, if x.typ is a map type, indexing must produce a value of a complete type, meaning + // its element type must also be complete. + if !check.isComplete(typ.elem) { + x.mode = invalid + return false + } } // ordinary index expression diff --git a/src/go/types/index.go b/src/go/types/index.go index 720cbbf0ea..9089092e52 100644 --- a/src/go/types/index.go +++ b/src/go/types/index.go @@ -53,11 +53,21 @@ func (check *Checker) indexExpr(x *operand, e *indexedExpr) (isFuncInst bool) { x.mode = invalid return false } - // Additionally, if x.typ is a pointer to an array type, indexing implicitly dereferences the value, meaning - // its base type must also be complete. - if p, ok := x.typ.Underlying().(*Pointer); ok && !check.isComplete(p.base) { - x.mode = invalid - return false + switch typ := x.typ.Underlying().(type) { + case *Pointer: + // Additionally, if x.typ is a pointer to an array type, indexing implicitly dereferences the value, meaning + // its base type must also be complete. + if !check.isComplete(typ.base) { + x.mode = invalid + return false + } + case *Map: + // Lastly, if x.typ is a map type, indexing must produce a value of a complete type, meaning + // its element type must also be complete. + if !check.isComplete(typ.elem) { + x.mode = invalid + return false + } } // ordinary index expression diff --git a/src/internal/types/testdata/check/cycles6.go b/src/internal/types/testdata/check/cycles6.go index e5635ed456..7c627749a4 100644 --- a/src/internal/types/testdata/check/cycles6.go +++ b/src/internal/types/testdata/check/cycles6.go @@ -69,3 +69,5 @@ type T11 /* ERROR "invalid recursive type" */ [unsafe.Sizeof(new(T11)[:])]int type T12 /* ERROR "invalid recursive type" */ [unsafe.Sizeof(T12{}[42])]int // index on pointer (case 3) type T13 /* ERROR "invalid recursive type" */ [unsafe.Sizeof(new(T13)[42])]int +// index on map (case 1) +type T14 /* ERROR "invalid recursive type" */ [unsafe.Sizeof((*new(map[int]T14))[42])]int -- 2.52.0