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