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