From f672e221fc40a376d1b4dc57bd7dda9d3b4f8807 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 26 Sep 2019 12:29:09 -0700 Subject: [PATCH] cmd/compile: extract typecheckarraylit function Typechecking slice literals, array literals, and array literals using "..." notation all use very similar logic, but tie into the logic for checking the OCOMPLIT node in slightly different ways. By refactoring this function out into a separate helper, it makes it easier to separate slice and array literals, and the subsequent CL will further separate array literals that do use "..." notation from those that do not. Passes toolstash-check. Change-Id: I4c572e0d9d08bcc86b5c224bd6f9e1c498726c19 Reviewed-on: https://go-review.googlesource.com/c/go/+/197603 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/gc/typecheck.go | 136 ++++++++++++----------- 1 file changed, 71 insertions(+), 65 deletions(-) diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 989805c1df..b13f2e2e1c 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -2795,75 +2795,20 @@ func typecheckcomplit(n *Node) (res *Node) { yyerror("invalid composite literal type %v", t) n.Type = nil - case TARRAY, TSLICE: - // If there are key/value pairs, create a map to keep seen - // keys so we can check for duplicate indices. - var indices map[int64]bool - for _, n1 := range n.List.Slice() { - if n1.Op == OKEY { - indices = make(map[int64]bool) - break - } - } - - var length, i int64 - checkBounds := t.IsArray() && !t.IsDDDArray() - nl := n.List.Slice() - for i2, l := range nl { - setlineno(l) - vp := &nl[i2] - if l.Op == OKEY { - l.Left = typecheck(l.Left, ctxExpr) - evconst(l.Left) - i = indexconst(l.Left) - if i < 0 { - if !l.Left.Diag() { - if i == -2 { - yyerror("index too large") - } else { - yyerror("index must be non-negative integer constant") - } - l.Left.SetDiag(true) - } - i = -(1 << 30) // stay negative for a while - } - vp = &l.Right - } - - if i >= 0 && indices != nil { - if indices[i] { - yyerror("duplicate index in array literal: %d", i) - } else { - indices[i] = true - } - } - - r := *vp - r = pushtype(r, t.Elem()) - r = typecheck(r, ctxExpr) - *vp = assignconv(r, t.Elem(), "array or slice literal") - - i++ - if i > length { - length = i - if checkBounds && length > t.NumElem() { - setlineno(l) - yyerror("array index %d out of bounds [0:%d]", length-1, t.NumElem()) - checkBounds = false - } - } - } - + case TARRAY: if t.IsDDDArray() { + length := typecheckarraylit(t.Elem(), -1, n.List.Slice()) t.SetNumElem(length) - } - if t.IsSlice() { - n.Op = OSLICELIT - n.Right = nodintconst(length) } else { - n.Op = OARRAYLIT - n.Right = nil + typecheckarraylit(t.Elem(), t.NumElem(), n.List.Slice()) } + n.Op = OARRAYLIT + n.Right = nil + + case TSLICE: + length := typecheckarraylit(t.Elem(), -1, n.List.Slice()) + n.Op = OSLICELIT + n.Right = nodintconst(length) case TMAP: var cs constSet @@ -3017,6 +2962,67 @@ func typecheckcomplit(n *Node) (res *Node) { return n } +func typecheckarraylit(elemType *types.Type, bound int64, elts []*Node) int64 { + // If there are key/value pairs, create a map to keep seen + // keys so we can check for duplicate indices. + var indices map[int64]bool + for _, elt := range elts { + if elt.Op == OKEY { + indices = make(map[int64]bool) + break + } + } + + var key, length int64 + for i, elt := range elts { + setlineno(elt) + vp := &elts[i] + if elt.Op == OKEY { + elt.Left = typecheck(elt.Left, ctxExpr) + key = indexconst(elt.Left) + if key < 0 { + if !elt.Left.Diag() { + if key == -2 { + yyerror("index too large") + } else { + yyerror("index must be non-negative integer constant") + } + elt.Left.SetDiag(true) + } + key = -(1 << 30) // stay negative for a while + } + vp = &elt.Right + } + + r := *vp + r = pushtype(r, elemType) + r = typecheck(r, ctxExpr) + *vp = assignconv(r, elemType, "array or slice literal") + + if key >= 0 { + if indices != nil { + if indices[key] { + yyerror("duplicate index in array literal: %d", key) + } else { + indices[key] = true + } + } + + if bound >= 0 && key >= bound { + yyerror("array index %d out of bounds [0:%d]", key, bound) + bound = -1 + } + } + + key++ + if key > length { + length = key + } + } + + return length +} + // visible reports whether sym is exported or locally defined. func visible(sym *types.Sym) bool { return sym != nil && (types.IsExported(sym.Name) || sym.Pkg == localpkg)