1
2
3
4
5
6
7 package types2
8
9 import (
10 "cmd/compile/internal/syntax"
11 "go/constant"
12 . "internal/types/errors"
13 )
14
15
16
17
18
19
20
21
22
23 func (check *Checker) rangeStmt(inner stmtContext, rangeStmt *syntax.ForStmt, noNewVarPos poser, sKey, sValue, sExtra, rangeVar syntax.Expr, isDef bool) {
24
25 var x operand
26
27
28
29
30
31
32
33
34 check.hasCallOrRecv = false
35 check.expr(nil, &x, rangeVar)
36
37 if isTypes2 && x.mode != invalid && sValue == nil && !check.hasCallOrRecv {
38 if t, ok := arrayPtrDeref(under(x.typ)).(*Array); ok {
39 for {
40
41
42
43 p, ok := rangeVar.(*syntax.ParenExpr)
44 if !ok {
45 break
46 }
47 rangeVar = p.X
48 }
49
50
51
52 check.record(&operand{
53 mode: constant_,
54 expr: rangeVar,
55 typ: Typ[Int],
56 val: constant.MakeInt64(t.len),
57 id: x.id,
58 })
59 }
60 }
61
62
63 var key, val Type
64 if x.mode != invalid {
65 k, v, cause, ok := rangeKeyVal(check, x.typ, func(v goVersion) bool {
66 return check.allowVersion(v)
67 })
68 switch {
69 case !ok && cause != "":
70 check.softErrorf(&x, InvalidRangeExpr, "cannot range over %s: %s", &x, cause)
71 case !ok:
72 check.softErrorf(&x, InvalidRangeExpr, "cannot range over %s", &x)
73 case k == nil && sKey != nil:
74 check.softErrorf(sKey, InvalidIterVar, "range over %s permits no iteration variables", &x)
75 case v == nil && sValue != nil:
76 check.softErrorf(sValue, InvalidIterVar, "range over %s permits only one iteration variable", &x)
77 case sExtra != nil:
78 check.softErrorf(sExtra, InvalidIterVar, "range clause permits at most two iteration variables")
79 }
80 key, val = k, v
81 }
82
83
84
85 check.openScope(rangeStmt, "range")
86 defer check.closeScope()
87
88
89
90
91
92 lhs := [2]syntax.Expr{sKey, sValue}
93 rhs := [2]Type{key, val}
94
95 rangeOverInt := isInteger(x.typ)
96
97 if isDef {
98
99 var vars []*Var
100 for i, lhs := range lhs {
101 if lhs == nil {
102 continue
103 }
104
105
106 var obj *Var
107 if ident, _ := lhs.(*syntax.Name); ident != nil {
108
109 name := ident.Value
110 obj = newVar(LocalVar, ident.Pos(), check.pkg, name, nil)
111 check.recordDef(ident, obj)
112
113 if name != "_" {
114 vars = append(vars, obj)
115 }
116 } else {
117 check.errorf(lhs, InvalidSyntaxTree, "cannot declare %s", lhs)
118 obj = newVar(LocalVar, lhs.Pos(), check.pkg, "_", nil)
119 }
120 assert(obj.typ == nil)
121
122
123 typ := rhs[i]
124 if typ == nil || typ == Typ[Invalid] {
125
126 obj.typ = Typ[Invalid]
127 check.usedVars[obj] = true
128 continue
129 }
130
131 if rangeOverInt {
132 assert(i == 0)
133 check.initVar(obj, &x, "range clause")
134 } else {
135 var y operand
136 y.mode = value
137 y.expr = lhs
138 y.typ = typ
139 check.initVar(obj, &y, "assignment")
140 }
141 assert(obj.typ != nil)
142 }
143
144
145 if len(vars) > 0 {
146 scopePos := rangeStmt.Body.Pos()
147 for _, obj := range vars {
148 check.declare(check.scope, nil , obj, scopePos)
149 }
150 } else {
151 check.error(noNewVarPos, NoNewVar, "no new variables on left side of :=")
152 }
153 } else if sKey != nil {
154
155 for i, lhs := range lhs {
156 if lhs == nil {
157 continue
158 }
159
160
161 typ := rhs[i]
162 if typ == nil || typ == Typ[Invalid] {
163 continue
164 }
165
166 if rangeOverInt {
167 assert(i == 0)
168 check.assignVar(lhs, nil, &x, "range clause")
169
170
171
172 if x.mode != invalid && !isInteger(x.typ) {
173 check.softErrorf(lhs, InvalidRangeExpr, "cannot use iteration variable of type %s", x.typ)
174 }
175 } else {
176 var y operand
177 y.mode = value
178 y.expr = lhs
179 y.typ = typ
180 check.assignVar(lhs, nil, &y, "assignment")
181 }
182 }
183 } else if rangeOverInt {
184
185
186
187
188
189
190 check.assignment(&x, nil, "range clause")
191 }
192
193 check.stmt(inner, rangeStmt.Body)
194 }
195
196
197
198
199
200
201
202 func rangeKeyVal(check *Checker, orig Type, allowVersion func(goVersion) bool) (key, val Type, cause string, ok bool) {
203 bad := func(cause string) (Type, Type, string, bool) {
204 return Typ[Invalid], Typ[Invalid], cause, false
205 }
206
207 rtyp, err := commonUnder(orig, func(t, u Type) *typeError {
208
209 if ch, _ := u.(*Chan); ch != nil && ch.dir == SendOnly {
210 return typeErrorf("receive from send-only channel %s", t)
211 }
212 return nil
213 })
214 if rtyp == nil {
215 return bad(err.format(check))
216 }
217
218 switch typ := arrayPtrDeref(rtyp).(type) {
219 case *Basic:
220 if isString(typ) {
221 return Typ[Int], universeRune, "", true
222 }
223 if isInteger(typ) {
224 if allowVersion != nil && !allowVersion(go1_22) {
225 return bad("requires go1.22 or later")
226 }
227 return orig, nil, "", true
228 }
229 case *Array:
230 return Typ[Int], typ.elem, "", true
231 case *Slice:
232 return Typ[Int], typ.elem, "", true
233 case *Map:
234 return typ.key, typ.elem, "", true
235 case *Chan:
236 assert(typ.dir != SendOnly)
237 return typ.elem, nil, "", true
238 case *Signature:
239 if allowVersion != nil && !allowVersion(go1_23) {
240 return bad("requires go1.23 or later")
241 }
242
243 switch {
244 case typ.Params().Len() != 1:
245 return bad("func must be func(yield func(...) bool): wrong argument count")
246 case typ.Results().Len() != 0:
247 return bad("func must be func(yield func(...) bool): unexpected results")
248 }
249 assert(typ.Recv() == nil)
250
251 u, err := commonUnder(typ.Params().At(0).Type(), nil)
252 cb, _ := u.(*Signature)
253 switch {
254 case cb == nil:
255 if err != nil {
256 return bad(check.sprintf("func must be func(yield func(...) bool): in yield type, %s", err.format(check)))
257 } else {
258 return bad("func must be func(yield func(...) bool): argument is not func")
259 }
260 case cb.Params().Len() > 2:
261 return bad("func must be func(yield func(...) bool): yield func has too many parameters")
262 case cb.Results().Len() != 1 || !Identical(cb.Results().At(0).Type(), universeBool):
263
264 if cb.Results().Len() == 1 && isBoolean(cb.Results().At(0).Type()) {
265 return bad("func must be func(yield func(...) bool): yield func returns user-defined boolean, not bool")
266 } else {
267 return bad("func must be func(yield func(...) bool): yield func does not return bool")
268 }
269 }
270 assert(cb.Recv() == nil)
271
272 if cb.Params().Len() >= 1 {
273 key = cb.Params().At(0).Type()
274 }
275 if cb.Params().Len() >= 2 {
276 val = cb.Params().At(1).Type()
277 }
278 return key, val, "", true
279 }
280 return
281 }
282
View as plain text