LEFT | RIGHT |
1 // Copyright 2012 The Go Authors. All rights reserved. | 1 // Copyright 2012 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // This file implements typechecking of builtin function calls. | 5 // This file implements typechecking of builtin function calls. |
6 | 6 |
7 package types | 7 package types |
8 | 8 |
9 import ( | 9 import ( |
10 "go/ast" | 10 "go/ast" |
11 "go/token" | 11 "go/token" |
12 ) | 12 ) |
13 | 13 |
14 // builtin typechecks a built-in call. The built-in type is bin, and iota is the
current | 14 // builtin typechecks a built-in call. The built-in type is bin, and iota is the
current |
15 // value of iota or -1 if iota doesn't have a value in the current context. The
result | 15 // value of iota or -1 if iota doesn't have a value in the current context. The
result |
16 // of the call is returned via x. If the call has type errors, the returned x is
marked | 16 // of the call is returned via x. If the call has type errors, the returned x is
marked |
17 // as invalid (x.mode == invalid). | 17 // as invalid (x.mode == invalid). |
18 // | 18 // |
19 func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
int) { | 19 func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
int) { |
20 args := call.Args | 20 args := call.Args |
21 id := bin.id | 21 id := bin.id |
22 | 22 |
23 // declare before goto's | 23 // declare before goto's |
24 var arg0 ast.Expr // first argument, if present | 24 var arg0 ast.Expr // first argument, if present |
25 var utyp0 Type // underlying type of first argument (nil for _Make, _
New, _Trace) | |
26 | 25 |
27 // check argument count | 26 // check argument count |
28 n := len(args) | 27 n := len(args) |
29 msg := "" | 28 msg := "" |
30 if n < bin.nargs { | 29 if n < bin.nargs { |
31 msg = "not enough" | 30 msg = "not enough" |
32 } else if !bin.isVariadic && n > bin.nargs { | 31 } else if !bin.isVariadic && n > bin.nargs { |
33 msg = "too many" | 32 msg = "too many" |
34 } | 33 } |
35 if msg != "" { | 34 if msg != "" { |
36 check.invalidOp(call.Pos(), msg+" arguments for %s (expected %d,
found %d)", call, bin.nargs, n) | 35 check.invalidOp(call.Pos(), msg+" arguments for %s (expected %d,
found %d)", call, bin.nargs, n) |
37 goto Error | 36 goto Error |
38 } | 37 } |
39 | 38 |
40 // common case: evaluate first argument if present; | 39 // common case: evaluate first argument if present; |
41 // if it is an expression, x has the expression value | 40 // if it is an expression, x has the expression value |
42 if n > 0 { | 41 if n > 0 { |
43 arg0 = args[0] | 42 arg0 = args[0] |
44 switch id { | 43 switch id { |
45 case _Make, _New, _Trace: | 44 case _Make, _New, _Trace: |
46 // respective cases below do the work | 45 // respective cases below do the work |
47 default: | 46 default: |
48 // argument must be an expression | 47 // argument must be an expression |
49 check.expr(x, arg0, nil, iota) | 48 check.expr(x, arg0, nil, iota) |
50 if x.mode == invalid { | 49 if x.mode == invalid { |
51 goto Error | 50 goto Error |
52 } | 51 } |
53 utyp0 = underlying(x.typ) | |
54 } | 52 } |
55 } | 53 } |
56 | 54 |
57 switch id { | 55 switch id { |
58 case _Append: | 56 case _Append: |
59 » » if _, ok := utyp0.(*Slice); !ok { | 57 » » if _, ok := underlying(x.typ).(*Slice); !ok { |
60 check.invalidArg(x.pos(), "%s is not a typed slice", x) | 58 check.invalidArg(x.pos(), "%s is not a typed slice", x) |
61 goto Error | 59 goto Error |
62 } | 60 } |
63 resultTyp := x.typ | 61 resultTyp := x.typ |
64 for _, arg := range args[1:] { | 62 for _, arg := range args[1:] { |
65 check.expr(x, arg, nil, iota) | 63 check.expr(x, arg, nil, iota) |
66 if x.mode == invalid { | 64 if x.mode == invalid { |
67 goto Error | 65 goto Error |
68 } | 66 } |
69 // TODO(gri) check assignability | 67 // TODO(gri) check assignability |
70 } | 68 } |
71 x.mode = value | 69 x.mode = value |
72 x.typ = resultTyp | 70 x.typ = resultTyp |
73 | 71 |
74 case _Cap, _Len: | 72 case _Cap, _Len: |
75 mode := invalid | 73 mode := invalid |
76 var val interface{} | 74 var val interface{} |
77 » » switch typ := implicitDeref(utyp0).(type) { | 75 » » switch typ := implicitDeref(underlying(x.typ)).(type) { |
78 case *Basic: | 76 case *Basic: |
79 if isString(typ) && id == _Len { | 77 if isString(typ) && id == _Len { |
80 if x.mode == constant { | 78 if x.mode == constant { |
81 mode = constant | 79 mode = constant |
82 val = int64(len(x.val.(string))) | 80 val = int64(len(x.val.(string))) |
83 } else { | 81 } else { |
84 mode = value | 82 mode = value |
85 } | 83 } |
86 } | 84 } |
87 | 85 |
(...skipping 15 matching lines...) Expand all Loading... |
103 | 101 |
104 if mode == invalid { | 102 if mode == invalid { |
105 check.invalidArg(x.pos(), "%s for %s", x, bin.name) | 103 check.invalidArg(x.pos(), "%s for %s", x, bin.name) |
106 goto Error | 104 goto Error |
107 } | 105 } |
108 x.mode = mode | 106 x.mode = mode |
109 x.typ = Typ[Int] | 107 x.typ = Typ[Int] |
110 x.val = val | 108 x.val = val |
111 | 109 |
112 case _Close: | 110 case _Close: |
113 » » ch, ok := utyp0.(*Chan) | 111 » » ch, ok := underlying(x.typ).(*Chan) |
114 if !ok { | 112 if !ok { |
115 check.invalidArg(x.pos(), "%s is not a channel", x) | 113 check.invalidArg(x.pos(), "%s is not a channel", x) |
116 goto Error | 114 goto Error |
117 } | 115 } |
118 if ch.Dir&ast.SEND == 0 { | 116 if ch.Dir&ast.SEND == 0 { |
119 check.invalidArg(x.pos(), "%s must not be a receive-only
channel", x) | 117 check.invalidArg(x.pos(), "%s must not be a receive-only
channel", x) |
120 goto Error | 118 goto Error |
121 } | 119 } |
122 x.mode = novalue | 120 x.mode = novalue |
123 | 121 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 } | 167 } |
170 | 168 |
171 case _Copy: | 169 case _Copy: |
172 var y operand | 170 var y operand |
173 check.expr(&y, args[1], nil, iota) | 171 check.expr(&y, args[1], nil, iota) |
174 if y.mode == invalid { | 172 if y.mode == invalid { |
175 goto Error | 173 goto Error |
176 } | 174 } |
177 | 175 |
178 var dst, src Type | 176 var dst, src Type |
179 » » if t, ok := utyp0.(*Slice); ok { | 177 » » if t, ok := underlying(x.typ).(*Slice); ok { |
180 dst = t.Elt | 178 dst = t.Elt |
181 } | 179 } |
182 switch t := underlying(y.typ).(type) { | 180 switch t := underlying(y.typ).(type) { |
183 case *Basic: | 181 case *Basic: |
184 if isString(y.typ) { | 182 if isString(y.typ) { |
185 src = Typ[Byte] | 183 src = Typ[Byte] |
186 } | 184 } |
187 case *Slice: | 185 case *Slice: |
188 src = t.Elt | 186 src = t.Elt |
189 } | 187 } |
190 | 188 |
191 if dst == nil || src == nil { | 189 if dst == nil || src == nil { |
192 check.invalidArg(x.pos(), "copy expects slice arguments;
found %s and %s", x, &y) | 190 check.invalidArg(x.pos(), "copy expects slice arguments;
found %s and %s", x, &y) |
193 goto Error | 191 goto Error |
194 } | 192 } |
195 | 193 |
196 if !isIdentical(dst, src) { | 194 if !isIdentical(dst, src) { |
197 check.invalidArg(x.pos(), "arguments to copy %s and %s h
ave different element types %s and %s", x, &y, dst, src) | 195 check.invalidArg(x.pos(), "arguments to copy %s and %s h
ave different element types %s and %s", x, &y, dst, src) |
198 goto Error | 196 goto Error |
199 } | 197 } |
200 | 198 |
201 x.mode = value | 199 x.mode = value |
202 x.typ = Typ[Int] | 200 x.typ = Typ[Int] |
203 | 201 |
204 case _Delete: | 202 case _Delete: |
205 » » m, ok := utyp0.(*Map) | 203 » » m, ok := underlying(x.typ).(*Map) |
206 if !ok { | 204 if !ok { |
207 check.invalidArg(x.pos(), "%s is not a map", x) | 205 check.invalidArg(x.pos(), "%s is not a map", x) |
208 goto Error | 206 goto Error |
209 } | 207 } |
210 check.expr(x, args[1], nil, iota) | 208 check.expr(x, args[1], nil, iota) |
211 if x.mode == invalid { | 209 if x.mode == invalid { |
212 goto Error | 210 goto Error |
213 } | 211 } |
214 if !x.isAssignable(m.Key) { | 212 if !x.isAssignable(m.Key) { |
215 check.invalidArg(x.pos(), "%s is not assignable to %s",
x, m.Key) | 213 check.invalidArg(x.pos(), "%s is not assignable to %s",
x, m.Key) |
216 goto Error | 214 goto Error |
217 } | 215 } |
218 x.mode = novalue | 216 x.mode = novalue |
219 | 217 |
220 case _Imag, _Real: | 218 case _Imag, _Real: |
221 » » if !isComplex(utyp0) { | 219 » » if !isComplex(x.typ) { |
222 check.invalidArg(x.pos(), "%s must be a complex number",
x) | 220 check.invalidArg(x.pos(), "%s must be a complex number",
x) |
223 goto Error | 221 goto Error |
224 } | 222 } |
225 if x.mode == constant { | 223 if x.mode == constant { |
226 // nothing to do for x.val == 0 | 224 // nothing to do for x.val == 0 |
227 if !isZeroConst(x.val) { | 225 if !isZeroConst(x.val) { |
228 c := x.val.(Complex) | 226 c := x.val.(Complex) |
229 if id == _Real { | 227 if id == _Real { |
230 x.val = c.Re | 228 x.val = c.Re |
231 } else { | 229 } else { |
232 x.val = c.Im | 230 x.val = c.Im |
233 } | 231 } |
234 } | 232 } |
235 } else { | 233 } else { |
236 x.mode = value | 234 x.mode = value |
237 } | 235 } |
238 k := Invalid | 236 k := Invalid |
239 » » switch utyp0.(*Basic).Kind { | 237 » » switch underlying(x.typ).(*Basic).Kind { |
240 case Complex64: | 238 case Complex64: |
241 k = Float32 | 239 k = Float32 |
242 case Complex128: | 240 case Complex128: |
243 k = Float64 | 241 k = Float64 |
244 case UntypedComplex: | 242 case UntypedComplex: |
245 k = UntypedFloat | 243 k = UntypedFloat |
246 default: | 244 default: |
247 unreachable() | 245 unreachable() |
248 } | 246 } |
249 x.typ = Typ[k] | 247 x.typ = Typ[k] |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
331 | 329 |
332 case _Sizeof: | 330 case _Sizeof: |
333 x.mode = constant | 331 x.mode = constant |
334 x.val = sizeof(check.ctxt, x.typ) | 332 x.val = sizeof(check.ctxt, x.typ) |
335 x.typ = Typ[Uintptr] | 333 x.typ = Typ[Uintptr] |
336 | 334 |
337 case _Assert: | 335 case _Assert: |
338 // assert(pred) causes a typechecker error if pred is false. | 336 // assert(pred) causes a typechecker error if pred is false. |
339 // The result of assert is the value of pred if there is no erro
r. | 337 // The result of assert is the value of pred if there is no erro
r. |
340 // Note: assert is only available in self-test mode. | 338 // Note: assert is only available in self-test mode. |
341 » » if x.mode != constant || !isBoolean(utyp0) { | 339 » » if x.mode != constant || !isBoolean(x.typ) { |
342 check.invalidArg(x.pos(), "%s is not a boolean constant"
, x) | 340 check.invalidArg(x.pos(), "%s is not a boolean constant"
, x) |
343 goto Error | 341 goto Error |
344 } | 342 } |
345 pred, ok := x.val.(bool) | 343 pred, ok := x.val.(bool) |
346 if !ok { | 344 if !ok { |
347 check.errorf(x.pos(), "internal error: value of %s shoul
d be a boolean constant", x) | 345 check.errorf(x.pos(), "internal error: value of %s shoul
d be a boolean constant", x) |
348 goto Error | 346 goto Error |
349 } | 347 } |
350 if !pred { | 348 if !pred { |
351 check.errorf(call.Pos(), "%s failed", call) | 349 check.errorf(call.Pos(), "%s failed", call) |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 return sizeof(ctxt, typ.Elt) * typ.Len | 448 return sizeof(ctxt, typ.Elt) * typ.Len |
451 case *Struct: | 449 case *Struct: |
452 var size int64 | 450 var size int64 |
453 for _, f := range typ.Fields { | 451 for _, f := range typ.Fields { |
454 size += sizeof(ctxt, f.Type) | 452 size += sizeof(ctxt, f.Type) |
455 } | 453 } |
456 return size | 454 return size |
457 } | 455 } |
458 return ctxt.PtrSize // good enough | 456 return ctxt.PtrSize // good enough |
459 } | 457 } |
LEFT | RIGHT |