]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: extract typecheckarraylit function
authorMatthew Dempsky <mdempsky@google.com>
Thu, 26 Sep 2019 19:29:09 +0000 (12:29 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Thu, 26 Sep 2019 20:44:28 +0000 (20:44 +0000)
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 <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/cmd/compile/internal/gc/typecheck.go

index 989805c1df43c59e3029b58aec4062332545bfa0..b13f2e2e1caaabe0b0d597c882b0ead9f74cc445 100644 (file)
@@ -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)