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