github.com/AndrienkoAleksandr/go@v0.0.19/src/go/types/conversions.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // This file implements typechecking of conversions. 6 7 package types 8 9 import ( 10 "go/constant" 11 . "internal/types/errors" 12 "unicode" 13 ) 14 15 // conversion type-checks the conversion T(x). 16 // The result is in x. 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 // nothing to do 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 // constant conversion 44 ok = constConvertibleTo(T, &x.val) 45 case constArg && isTypeParam(T): 46 // x is convertible to T if it is convertible 47 // to each specific type in the type set of T. 48 // If T's type set is empty, or if it doesn't 49 // have specific types, constant x cannot be 50 // converted. 51 ok = T.(*TypeParam).underIs(func(u Type) bool { 52 // u is nil if there are no specific type terms 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 type %s (in %s)", x, u, T) 62 return false 63 } 64 return true 65 }) 66 x.mode = value // type parameters are not constants 67 case x.convertibleTo(check, T, &cause): 68 // non-constant conversion 69 ok = true 70 x.mode = value 71 } 72 73 if !ok { 74 if cause != "" { 75 check.errorf(x, InvalidConversion, "cannot convert %s to type %s: %s", x, T, cause) 76 } else { 77 check.errorf(x, InvalidConversion, "cannot convert %s to type %s", x, T) 78 } 79 x.mode = invalid 80 return 81 } 82 83 // The conversion argument types are final. For untyped values the 84 // conversion provides the type, per the spec: "A constant may be 85 // given a type explicitly by a constant declaration or conversion,...". 86 if isUntyped(x.typ) { 87 final := T 88 // - For conversions to interfaces, use the argument's default type. 89 // - For conversions of untyped constants to non-constant types, also 90 // use the default type (e.g., []byte("foo") should report string 91 // not []byte as type for the constant "foo"). 92 // - Keep untyped nil for untyped nil arguments. 93 // - For constant integer to string conversions, keep the argument type. 94 // (See also the TODO below.) 95 if isNonTypeParamInterface(T) || constArg && !isConstType(T) || x.isNil() { 96 final = Default(x.typ) // default type of untyped nil is untyped nil 97 } else if x.mode == constant_ && isInteger(x.typ) && allString(T) { 98 final = x.typ 99 } 100 check.updateExprType(x.expr, final, true) 101 } 102 103 x.typ = T 104 } 105 106 // TODO(gri) convertibleTo checks if T(x) is valid. It assumes that the type 107 // of x is fully known, but that's not the case for say string(1<<s + 1.0): 108 // Here, the type of 1<<s + 1.0 will be UntypedFloat which will lead to the 109 // (correct!) refusal of the conversion. But the reported error is essentially 110 // "cannot convert untyped float value to string", yet the correct error (per 111 // the spec) is that we cannot shift a floating-point value: 1 in 1<<s should 112 // be converted to UntypedFloat because of the addition of 1.0. Fixing this 113 // is tricky because we'd have to run updateExprType on the argument first. 114 // (go.dev/issue/21982.) 115 116 // convertibleTo reports whether T(x) is valid. In the failure case, *cause 117 // may be set to the cause for the failure. 118 // The check parameter may be nil if convertibleTo is invoked through an 119 // exported API call, i.e., when all methods have been type-checked. 120 func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool { 121 // "x is assignable to T" 122 if ok, _ := x.assignableTo(check, T, cause); ok { 123 return true 124 } 125 126 // "V and T have identical underlying types if tags are ignored 127 // and V and T are not type parameters" 128 V := x.typ 129 Vu := under(V) 130 Tu := under(T) 131 Vp, _ := V.(*TypeParam) 132 Tp, _ := T.(*TypeParam) 133 if IdenticalIgnoreTags(Vu, Tu) && Vp == nil && Tp == nil { 134 return true 135 } 136 137 // "V and T are unnamed pointer types and their pointer base types 138 // have identical underlying types if tags are ignored 139 // and their pointer base types are not type parameters" 140 if V, ok := V.(*Pointer); ok { 141 if T, ok := T.(*Pointer); ok { 142 if IdenticalIgnoreTags(under(V.base), under(T.base)) && !isTypeParam(V.base) && !isTypeParam(T.base) { 143 return true 144 } 145 } 146 } 147 148 // "V and T are both integer or floating point types" 149 if isIntegerOrFloat(Vu) && isIntegerOrFloat(Tu) { 150 return true 151 } 152 153 // "V and T are both complex types" 154 if isComplex(Vu) && isComplex(Tu) { 155 return true 156 } 157 158 // "V is an integer or a slice of bytes or runes and T is a string type" 159 if (isInteger(Vu) || isBytesOrRunes(Vu)) && isString(Tu) { 160 return true 161 } 162 163 // "V is a string and T is a slice of bytes or runes" 164 if isString(Vu) && isBytesOrRunes(Tu) { 165 return true 166 } 167 168 // package unsafe: 169 // "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer" 170 if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(Tu) { 171 return true 172 } 173 // "and vice versa" 174 if isUnsafePointer(Vu) && (isPointer(Tu) || isUintptr(Tu)) { 175 return true 176 } 177 178 // "V is a slice, T is an array or pointer-to-array type, 179 // and the slice and array types have identical element types." 180 if s, _ := Vu.(*Slice); s != nil { 181 switch a := Tu.(type) { 182 case *Array: 183 if Identical(s.Elem(), a.Elem()) { 184 if check == nil || check.allowVersion(check.pkg, x, go1_20) { 185 return true 186 } 187 // check != nil 188 if cause != nil { 189 // TODO(gri) consider restructuring versionErrorf so we can use it here and below 190 *cause = "conversion of slices to arrays requires go1.20 or later" 191 } 192 return false 193 } 194 case *Pointer: 195 if a, _ := under(a.Elem()).(*Array); a != nil { 196 if Identical(s.Elem(), a.Elem()) { 197 if check == nil || check.allowVersion(check.pkg, x, go1_17) { 198 return true 199 } 200 // check != nil 201 if cause != nil { 202 *cause = "conversion of slices to array pointers requires go1.17 or later" 203 } 204 return false 205 } 206 } 207 } 208 } 209 210 // optimization: if we don't have type parameters, we're done 211 if Vp == nil && Tp == nil { 212 return false 213 } 214 215 errorf := func(format string, args ...any) { 216 if check != nil && cause != nil { 217 msg := check.sprintf(format, args...) 218 if *cause != "" { 219 msg += "\n\t" + *cause 220 } 221 *cause = msg 222 } 223 } 224 225 // generic cases with specific type terms 226 // (generic operands cannot be constants, so we can ignore x.val) 227 switch { 228 case Vp != nil && Tp != nil: 229 x := *x // don't clobber outer x 230 return Vp.is(func(V *term) bool { 231 if V == nil { 232 return false // no specific types 233 } 234 x.typ = V.typ 235 return Tp.is(func(T *term) bool { 236 if T == nil { 237 return false // no specific types 238 } 239 if !x.convertibleTo(check, T.typ, cause) { 240 errorf("cannot convert %s (in %s) to type %s (in %s)", V.typ, Vp, T.typ, Tp) 241 return false 242 } 243 return true 244 }) 245 }) 246 case Vp != nil: 247 x := *x // don't clobber outer x 248 return Vp.is(func(V *term) bool { 249 if V == nil { 250 return false // no specific types 251 } 252 x.typ = V.typ 253 if !x.convertibleTo(check, T, cause) { 254 errorf("cannot convert %s (in %s) to type %s", V.typ, Vp, T) 255 return false 256 } 257 return true 258 }) 259 case Tp != nil: 260 return Tp.is(func(T *term) bool { 261 if T == nil { 262 return false // no specific types 263 } 264 if !x.convertibleTo(check, T.typ, cause) { 265 errorf("cannot convert %s to type %s (in %s)", x.typ, T.typ, Tp) 266 return false 267 } 268 return true 269 }) 270 } 271 272 return false 273 } 274 275 func isUintptr(typ Type) bool { 276 t, _ := under(typ).(*Basic) 277 return t != nil && t.kind == Uintptr 278 } 279 280 func isUnsafePointer(typ Type) bool { 281 t, _ := under(typ).(*Basic) 282 return t != nil && t.kind == UnsafePointer 283 } 284 285 func isPointer(typ Type) bool { 286 _, ok := under(typ).(*Pointer) 287 return ok 288 } 289 290 func isBytesOrRunes(typ Type) bool { 291 if s, _ := under(typ).(*Slice); s != nil { 292 t, _ := under(s.elem).(*Basic) 293 return t != nil && (t.kind == Byte || t.kind == Rune) 294 } 295 return false 296 }