mirror of
https://github.com/golang/go
synced 2024-11-18 19:54:44 -07:00
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 <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
740d2c8c22
commit
f672e221fc
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user