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