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