Skip to content

Commit f672e22

Browse files
committed
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Robert Griesemer <[email protected]>
1 parent 740d2c8 commit f672e22

File tree

1 file changed

+71
-65
lines changed

1 file changed

+71
-65
lines changed

src/cmd/compile/internal/gc/typecheck.go

Lines changed: 71 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2795,75 +2795,20 @@ func typecheckcomplit(n *Node) (res *Node) {
27952795
yyerror("invalid composite literal type %v", t)
27962796
n.Type = nil
27972797

2798-
case TARRAY, TSLICE:
2799-
// If there are key/value pairs, create a map to keep seen
2800-
// keys so we can check for duplicate indices.
2801-
var indices map[int64]bool
2802-
for _, n1 := range n.List.Slice() {
2803-
if n1.Op == OKEY {
2804-
indices = make(map[int64]bool)
2805-
break
2806-
}
2807-
}
2808-
2809-
var length, i int64
2810-
checkBounds := t.IsArray() && !t.IsDDDArray()
2811-
nl := n.List.Slice()
2812-
for i2, l := range nl {
2813-
setlineno(l)
2814-
vp := &nl[i2]
2815-
if l.Op == OKEY {
2816-
l.Left = typecheck(l.Left, ctxExpr)
2817-
evconst(l.Left)
2818-
i = indexconst(l.Left)
2819-
if i < 0 {
2820-
if !l.Left.Diag() {
2821-
if i == -2 {
2822-
yyerror("index too large")
2823-
} else {
2824-
yyerror("index must be non-negative integer constant")
2825-
}
2826-
l.Left.SetDiag(true)
2827-
}
2828-
i = -(1 << 30) // stay negative for a while
2829-
}
2830-
vp = &l.Right
2831-
}
2832-
2833-
if i >= 0 && indices != nil {
2834-
if indices[i] {
2835-
yyerror("duplicate index in array literal: %d", i)
2836-
} else {
2837-
indices[i] = true
2838-
}
2839-
}
2840-
2841-
r := *vp
2842-
r = pushtype(r, t.Elem())
2843-
r = typecheck(r, ctxExpr)
2844-
*vp = assignconv(r, t.Elem(), "array or slice literal")
2845-
2846-
i++
2847-
if i > length {
2848-
length = i
2849-
if checkBounds && length > t.NumElem() {
2850-
setlineno(l)
2851-
yyerror("array index %d out of bounds [0:%d]", length-1, t.NumElem())
2852-
checkBounds = false
2853-
}
2854-
}
2855-
}
2856-
2798+
case TARRAY:
28572799
if t.IsDDDArray() {
2800+
length := typecheckarraylit(t.Elem(), -1, n.List.Slice())
28582801
t.SetNumElem(length)
2859-
}
2860-
if t.IsSlice() {
2861-
n.Op = OSLICELIT
2862-
n.Right = nodintconst(length)
28632802
} else {
2864-
n.Op = OARRAYLIT
2865-
n.Right = nil
2803+
typecheckarraylit(t.Elem(), t.NumElem(), n.List.Slice())
28662804
}
2805+
n.Op = OARRAYLIT
2806+
n.Right = nil
2807+
2808+
case TSLICE:
2809+
length := typecheckarraylit(t.Elem(), -1, n.List.Slice())
2810+
n.Op = OSLICELIT
2811+
n.Right = nodintconst(length)
28672812

28682813
case TMAP:
28692814
var cs constSet
@@ -3017,6 +2962,67 @@ func typecheckcomplit(n *Node) (res *Node) {
30172962
return n
30182963
}
30192964

2965+
func typecheckarraylit(elemType *types.Type, bound int64, elts []*Node) int64 {
2966+
// If there are key/value pairs, create a map to keep seen
2967+
// keys so we can check for duplicate indices.
2968+
var indices map[int64]bool
2969+
for _, elt := range elts {
2970+
if elt.Op == OKEY {
2971+
indices = make(map[int64]bool)
2972+
break
2973+
}
2974+
}
2975+
2976+
var key, length int64
2977+
for i, elt := range elts {
2978+
setlineno(elt)
2979+
vp := &elts[i]
2980+
if elt.Op == OKEY {
2981+
elt.Left = typecheck(elt.Left, ctxExpr)
2982+
key = indexconst(elt.Left)
2983+
if key < 0 {
2984+
if !elt.Left.Diag() {
2985+
if key == -2 {
2986+
yyerror("index too large")
2987+
} else {
2988+
yyerror("index must be non-negative integer constant")
2989+
}
2990+
elt.Left.SetDiag(true)
2991+
}
2992+
key = -(1 << 30) // stay negative for a while
2993+
}
2994+
vp = &elt.Right
2995+
}
2996+
2997+
r := *vp
2998+
r = pushtype(r, elemType)
2999+
r = typecheck(r, ctxExpr)
3000+
*vp = assignconv(r, elemType, "array or slice literal")
3001+
3002+
if key >= 0 {
3003+
if indices != nil {
3004+
if indices[key] {
3005+
yyerror("duplicate index in array literal: %d", key)
3006+
} else {
3007+
indices[key] = true
3008+
}
3009+
}
3010+
3011+
if bound >= 0 && key >= bound {
3012+
yyerror("array index %d out of bounds [0:%d]", key, bound)
3013+
bound = -1
3014+
}
3015+
}
3016+
3017+
key++
3018+
if key > length {
3019+
length = key
3020+
}
3021+
}
3022+
3023+
return length
3024+
}
3025+
30203026
// visible reports whether sym is exported or locally defined.
30213027
func visible(sym *types.Sym) bool {
30223028
return sym != nil && (types.IsExported(sym.Name) || sym.Pkg == localpkg)

0 commit comments

Comments
 (0)