Source file
src/go/types/const.go
1
2
3
4
5
6
7
8
9
10 package types
11
12 import (
13 "go/constant"
14 "go/token"
15 . "internal/types/errors"
16 "math"
17 )
18
19
20
21
22 func (check *Checker) overflow(x *operand, opPos token.Pos) {
23 assert(x.mode() == constant_)
24
25 if x.val.Kind() == constant.Unknown {
26
27
28
29 check.error(atPos(opPos), InvalidConstVal, "constant result is not representable")
30 return
31 }
32
33
34
35
36
37 if isTyped(x.typ()) {
38 check.representable(x, x.typ().Underlying().(*Basic))
39 return
40 }
41
42
43 const prec = 512
44 if x.val.Kind() == constant.Int && constant.BitLen(x.val) > prec {
45 op := opName(x.expr)
46 if op != "" {
47 op += " "
48 }
49 check.errorf(atPos(opPos), InvalidConstVal, "constant %soverflow", op)
50 x.val = constant.MakeUnknown()
51 return
52 }
53
54 const maxLen = 10 * 1024 * 1024
55 if x.val.Kind() == constant.String && len(constant.StringVal(x.val)) > maxLen {
56 check.error(atPos(opPos), InvalidConstVal, "constant string too long")
57 x.val = constant.MakeUnknown()
58 return
59 }
60 }
61
62
63
64
65
66
67
68
69
70
71
72
73
74 func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *constant.Value) bool {
75 if x.Kind() == constant.Unknown {
76 return true
77 }
78
79 var conf *Config
80 if check != nil {
81 conf = check.conf
82 }
83
84 sizeof := func(T Type) int64 {
85 s := conf.sizeof(T)
86 return s
87 }
88
89 switch {
90 case isInteger(typ):
91 x := constant.ToInt(x)
92 if x.Kind() != constant.Int {
93 return false
94 }
95 if rounded != nil {
96 *rounded = x
97 }
98 if x, ok := constant.Int64Val(x); ok {
99 switch typ.kind {
100 case Int:
101 var s = uint(sizeof(typ)) * 8
102 return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
103 case Int8:
104 const s = 8
105 return -1<<(s-1) <= x && x <= 1<<(s-1)-1
106 case Int16:
107 const s = 16
108 return -1<<(s-1) <= x && x <= 1<<(s-1)-1
109 case Int32:
110 const s = 32
111 return -1<<(s-1) <= x && x <= 1<<(s-1)-1
112 case Int64, UntypedInt:
113 return true
114 case Uint, Uintptr:
115 if s := uint(sizeof(typ)) * 8; s < 64 {
116 return 0 <= x && x <= int64(1)<<s-1
117 }
118 return 0 <= x
119 case Uint8:
120 const s = 8
121 return 0 <= x && x <= 1<<s-1
122 case Uint16:
123 const s = 16
124 return 0 <= x && x <= 1<<s-1
125 case Uint32:
126 const s = 32
127 return 0 <= x && x <= 1<<s-1
128 case Uint64:
129 return 0 <= x
130 default:
131 panic("unreachable")
132 }
133 }
134
135 switch n := constant.BitLen(x); typ.kind {
136 case Uint, Uintptr:
137 var s = uint(sizeof(typ)) * 8
138 return constant.Sign(x) >= 0 && n <= int(s)
139 case Uint64:
140 return constant.Sign(x) >= 0 && n <= 64
141 case UntypedInt:
142 return true
143 }
144
145 case isFloat(typ):
146 x := constant.ToFloat(x)
147 if x.Kind() != constant.Float {
148 return false
149 }
150 switch typ.kind {
151 case Float32:
152 if rounded == nil {
153 return fitsFloat32(x)
154 }
155 r := roundFloat32(x)
156 if r != nil {
157 *rounded = r
158 return true
159 }
160 case Float64:
161 if rounded == nil {
162 return fitsFloat64(x)
163 }
164 r := roundFloat64(x)
165 if r != nil {
166 *rounded = r
167 return true
168 }
169 case UntypedFloat:
170 return true
171 default:
172 panic("unreachable")
173 }
174
175 case isComplex(typ):
176 x := constant.ToComplex(x)
177 if x.Kind() != constant.Complex {
178 return false
179 }
180 switch typ.kind {
181 case Complex64:
182 if rounded == nil {
183 return fitsFloat32(constant.Real(x)) && fitsFloat32(constant.Imag(x))
184 }
185 re := roundFloat32(constant.Real(x))
186 im := roundFloat32(constant.Imag(x))
187 if re != nil && im != nil {
188 *rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
189 return true
190 }
191 case Complex128:
192 if rounded == nil {
193 return fitsFloat64(constant.Real(x)) && fitsFloat64(constant.Imag(x))
194 }
195 re := roundFloat64(constant.Real(x))
196 im := roundFloat64(constant.Imag(x))
197 if re != nil && im != nil {
198 *rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
199 return true
200 }
201 case UntypedComplex:
202 return true
203 default:
204 panic("unreachable")
205 }
206
207 case isString(typ):
208 return x.Kind() == constant.String
209
210 case isBoolean(typ):
211 return x.Kind() == constant.Bool
212 }
213
214 return false
215 }
216
217 func fitsFloat32(x constant.Value) bool {
218 f32, _ := constant.Float32Val(x)
219 f := float64(f32)
220 return !math.IsInf(f, 0)
221 }
222
223 func roundFloat32(x constant.Value) constant.Value {
224 f32, _ := constant.Float32Val(x)
225 f := float64(f32)
226 if !math.IsInf(f, 0) {
227 return constant.MakeFloat64(f)
228 }
229 return nil
230 }
231
232 func fitsFloat64(x constant.Value) bool {
233 f, _ := constant.Float64Val(x)
234 return !math.IsInf(f, 0)
235 }
236
237 func roundFloat64(x constant.Value) constant.Value {
238 f, _ := constant.Float64Val(x)
239 if !math.IsInf(f, 0) {
240 return constant.MakeFloat64(f)
241 }
242 return nil
243 }
244
245
246
247 func (check *Checker) representable(x *operand, typ *Basic) {
248 v, code := check.representation(x, typ)
249 if code != 0 {
250 check.invalidConversion(code, x, typ)
251 x.invalidate()
252 return
253 }
254 assert(v != nil)
255 x.val = v
256 }
257
258
259
260
261
262 func (check *Checker) representation(x *operand, typ *Basic) (constant.Value, Code) {
263 assert(x.mode() == constant_)
264 v := x.val
265 if !representableConst(x.val, check, typ, &v) {
266 if isNumeric(x.typ()) && isNumeric(typ) {
267
268
269
270
271
272
273
274 if !isInteger(x.typ()) && isInteger(typ) {
275 return nil, TruncatedFloat
276 } else {
277 return nil, NumericOverflow
278 }
279 }
280 return nil, InvalidConstVal
281 }
282 return v, 0
283 }
284
285 func (check *Checker) invalidConversion(code Code, x *operand, target Type) {
286 msg := "cannot convert %s to type %s"
287 switch code {
288 case TruncatedFloat:
289 msg = "%s truncated to %s"
290 case NumericOverflow:
291 msg = "%s overflows %s"
292 }
293 check.errorf(x, code, msg, x, target)
294 }
295
296
297 func (check *Checker) convertUntyped(x *operand, target Type) {
298 newType, val, code := check.implicitTypeAndValue(x, target)
299 if code != 0 {
300 t := target
301 if !isTypeParam(target) {
302 t = safeUnderlying(target)
303 }
304 check.invalidConversion(code, x, t)
305 x.invalidate()
306 return
307 }
308 if val != nil {
309 x.val = val
310 check.updateExprVal(x.expr, val)
311 }
312 if newType != x.typ() {
313 x.typ_ = newType
314 check.updateExprType(x.expr, newType, false)
315 }
316 }
317
View as plain text