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