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