Source file
src/go/types/conversions.go
1
2
3
4
5
6
7
8
9
10 package types
11
12 import (
13 "go/constant"
14 . "internal/types/errors"
15 "unicode"
16 )
17
18
19
20 func (check *Checker) conversion(x *operand, T Type) {
21 constArg := x.mode == constant_
22
23 constConvertibleTo := func(T Type, val *constant.Value) bool {
24 switch t, _ := under(T).(*Basic); {
25 case t == nil:
26
27 case representableConst(x.val, check, t, val):
28 return true
29 case isInteger(x.typ) && isString(t):
30 codepoint := unicode.ReplacementChar
31 if i, ok := constant.Uint64Val(x.val); ok && i <= unicode.MaxRune {
32 codepoint = rune(i)
33 }
34 if val != nil {
35 *val = constant.MakeString(string(codepoint))
36 }
37 return true
38 }
39 return false
40 }
41
42 var ok bool
43 var cause string
44 switch {
45 case constArg && isConstType(T):
46
47 ok = constConvertibleTo(T, &x.val)
48
49
50
51 if !ok && isInteger(x.typ) && isInteger(T) {
52 check.errorf(x, InvalidConversion, "constant %s overflows %s", x.val, T)
53 x.mode = invalid
54 return
55 }
56 case constArg && isTypeParam(T):
57
58
59
60
61
62 ok = T.(*TypeParam).underIs(func(u Type) bool {
63
64 if u == nil {
65 cause = check.sprintf("%s does not contain specific types", T)
66 return false
67 }
68 if isString(x.typ) && isBytesOrRunes(u) {
69 return true
70 }
71 if !constConvertibleTo(u, nil) {
72 if isInteger(x.typ) && isInteger(u) {
73
74 cause = check.sprintf("constant %s overflows %s (in %s)", x.val, u, T)
75 } else {
76 cause = check.sprintf("cannot convert %s to type %s (in %s)", x, u, T)
77 }
78 return false
79 }
80 return true
81 })
82 x.mode = value
83 case x.convertibleTo(check, T, &cause):
84
85 ok = true
86 x.mode = value
87 }
88
89 if !ok {
90 if cause != "" {
91 check.errorf(x, InvalidConversion, "cannot convert %s to type %s: %s", x, T, cause)
92 } else {
93 check.errorf(x, InvalidConversion, "cannot convert %s to type %s", x, T)
94 }
95 x.mode = invalid
96 return
97 }
98
99
100
101
102 if isUntyped(x.typ) {
103 final := T
104
105
106
107
108
109
110
111
112 if isTypes2 && x.typ == Typ[UntypedNil] {
113
114 } else if isNonTypeParamInterface(T) || constArg && !isConstType(T) || !isTypes2 && x.isNil() {
115 final = Default(x.typ)
116 } else if x.mode == constant_ && isInteger(x.typ) && allString(T) {
117 final = x.typ
118 }
119 check.updateExprType(x.expr, final, true)
120 }
121
122 x.typ = T
123 }
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139 func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
140
141 if ok, _ := x.assignableTo(check, T, cause); ok {
142 return true
143 }
144
145
146
147 V := x.typ
148 Vu := under(V)
149 Tu := under(T)
150 Vp, _ := V.(*TypeParam)
151 Tp, _ := T.(*TypeParam)
152 if IdenticalIgnoreTags(Vu, Tu) && Vp == nil && Tp == nil {
153 return true
154 }
155
156
157
158
159 if V, ok := V.(*Pointer); ok {
160 if T, ok := T.(*Pointer); ok {
161 if IdenticalIgnoreTags(under(V.base), under(T.base)) && !isTypeParam(V.base) && !isTypeParam(T.base) {
162 return true
163 }
164 }
165 }
166
167
168 if isIntegerOrFloat(Vu) && isIntegerOrFloat(Tu) {
169 return true
170 }
171
172
173 if isComplex(Vu) && isComplex(Tu) {
174 return true
175 }
176
177
178 if (isInteger(Vu) || isBytesOrRunes(Vu)) && isString(Tu) {
179 return true
180 }
181
182
183 if isString(Vu) && isBytesOrRunes(Tu) {
184 return true
185 }
186
187
188
189 if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(Tu) {
190 return true
191 }
192
193 if isUnsafePointer(Vu) && (isPointer(Tu) || isUintptr(Tu)) {
194 return true
195 }
196
197
198
199 if s, _ := Vu.(*Slice); s != nil {
200 switch a := Tu.(type) {
201 case *Array:
202 if Identical(s.Elem(), a.Elem()) {
203 if check == nil || check.allowVersion(x, go1_20) {
204 return true
205 }
206
207 if cause != nil {
208
209 *cause = "conversion of slice to array requires go1.20 or later"
210 }
211 return false
212 }
213 case *Pointer:
214 if a, _ := under(a.Elem()).(*Array); a != nil {
215 if Identical(s.Elem(), a.Elem()) {
216 if check == nil || check.allowVersion(x, go1_17) {
217 return true
218 }
219
220 if cause != nil {
221 *cause = "conversion of slice to array pointer requires go1.17 or later"
222 }
223 return false
224 }
225 }
226 }
227 }
228
229
230 if Vp == nil && Tp == nil {
231 return false
232 }
233
234 errorf := func(format string, args ...any) {
235 if check != nil && cause != nil {
236 msg := check.sprintf(format, args...)
237 if *cause != "" {
238 msg += "\n\t" + *cause
239 }
240 *cause = msg
241 }
242 }
243
244
245
246 switch {
247 case Vp != nil && Tp != nil:
248 x := *x
249 return Vp.is(func(V *term) bool {
250 if V == nil {
251 return false
252 }
253 x.typ = V.typ
254 return Tp.is(func(T *term) bool {
255 if T == nil {
256 return false
257 }
258 if !x.convertibleTo(check, T.typ, cause) {
259 errorf("cannot convert %s (in %s) to type %s (in %s)", V.typ, Vp, T.typ, Tp)
260 return false
261 }
262 return true
263 })
264 })
265 case Vp != nil:
266 x := *x
267 return Vp.is(func(V *term) bool {
268 if V == nil {
269 return false
270 }
271 x.typ = V.typ
272 if !x.convertibleTo(check, T, cause) {
273 errorf("cannot convert %s (in %s) to type %s", V.typ, Vp, T)
274 return false
275 }
276 return true
277 })
278 case Tp != nil:
279 return Tp.is(func(T *term) bool {
280 if T == nil {
281 return false
282 }
283 if !x.convertibleTo(check, T.typ, cause) {
284 errorf("cannot convert %s to type %s (in %s)", x.typ, T.typ, Tp)
285 return false
286 }
287 return true
288 })
289 }
290
291 return false
292 }
293
294 func isUintptr(typ Type) bool {
295 t, _ := under(typ).(*Basic)
296 return t != nil && t.kind == Uintptr
297 }
298
299 func isUnsafePointer(typ Type) bool {
300 t, _ := under(typ).(*Basic)
301 return t != nil && t.kind == UnsafePointer
302 }
303
304 func isPointer(typ Type) bool {
305 _, ok := under(typ).(*Pointer)
306 return ok
307 }
308
309 func isBytesOrRunes(typ Type) bool {
310 if s, _ := under(typ).(*Slice); s != nil {
311 t, _ := under(s.elem).(*Basic)
312 return t != nil && (t.kind == Byte || t.kind == Rune)
313 }
314 return false
315 }
316
View as plain text