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