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