...
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 var ok bool
20 var reason string
21 switch {
22 case constArg && isConstType(T):
23
24 switch t := asBasic(T); {
25 case representableConst(x.val, check, t, &x.val):
26 ok = true
27 case isInteger(x.typ) && isString(t):
28 codepoint := unicode.ReplacementChar
29 if i, ok := constant.Uint64Val(x.val); ok && i <= unicode.MaxRune {
30 codepoint = rune(i)
31 }
32 x.val = constant.MakeString(string(codepoint))
33 ok = true
34 }
35 case x.convertibleTo(check, T, &reason):
36
37 x.mode = value
38 ok = true
39 }
40
41 if !ok {
42 if reason != "" {
43 check.errorf(x, _InvalidConversion, "cannot convert %s to %s (%s)", x, T, reason)
44 } else {
45 check.errorf(x, _InvalidConversion, "cannot convert %s to %s", x, T)
46 }
47 x.mode = invalid
48 return
49 }
50
51
52
53
54 if isUntyped(x.typ) {
55 final := T
56
57
58
59
60
61
62
63 if IsInterface(T) || constArg && !isConstType(T) || x.isNil() {
64 final = Default(x.typ)
65 } else if isInteger(x.typ) && isString(T) {
66 final = x.typ
67 }
68 check.updateExprType(x.expr, final, true)
69 }
70
71 x.typ = T
72 }
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 func (x *operand) convertibleTo(check *Checker, T Type, reason *string) bool {
88
89 if ok, _ := x.assignableTo(check, T, nil); ok {
90 return true
91 }
92
93
94 V := x.typ
95 Vu := under(V)
96 Tu := under(T)
97 if check.identicalIgnoreTags(Vu, Tu) {
98 return true
99 }
100
101
102
103 if V, ok := V.(*Pointer); ok {
104 if T, ok := T.(*Pointer); ok {
105 if check.identicalIgnoreTags(under(V.base), under(T.base)) {
106 return true
107 }
108 }
109 }
110
111
112 if isIntegerOrFloat(V) && isIntegerOrFloat(T) {
113 return true
114 }
115
116
117 if isComplex(V) && isComplex(T) {
118 return true
119 }
120
121
122 if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) {
123 return true
124 }
125
126
127 if isString(V) && isBytesOrRunes(Tu) {
128 return true
129 }
130
131
132
133 if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(T) {
134 return true
135 }
136
137 if isUnsafePointer(V) && (isPointer(Tu) || isUintptr(Tu)) {
138 return true
139 }
140
141
142
143 if s := asSlice(V); s != nil {
144 if p := asPointer(T); p != nil {
145 if a := asArray(p.Elem()); a != nil {
146 if check.identical(s.Elem(), a.Elem()) {
147 if check == nil || check.allowVersion(check.pkg, 1, 17) {
148 return true
149 }
150 if reason != nil {
151 *reason = "conversion of slices to array pointers requires go1.17 or later"
152 }
153 }
154 }
155 }
156 }
157
158 return false
159 }
160
161 func isUintptr(typ Type) bool {
162 t := asBasic(typ)
163 return t != nil && t.kind == Uintptr
164 }
165
166 func isUnsafePointer(typ Type) bool {
167
168
169
170
171 t := asBasic(typ)
172 return t != nil && t.kind == UnsafePointer
173 }
174
175 func isPointer(typ Type) bool {
176 return asPointer(typ) != nil
177 }
178
179 func isBytesOrRunes(typ Type) bool {
180 if s := asSlice(typ); s != nil {
181 t := asBasic(s.elem)
182 return t != nil && (t.kind == Byte || t.kind == Rune)
183 }
184 return false
185 }
186
View as plain text