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 7package types2 8 9import ( 10 "fmt" 11 "go/constant" 12 "unicode" 13) 14 15// Conversion type-checks the conversion T(x). 16// The result is in x. 17func (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 // t 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 !constConvertibleTo(u, nil) { 58 cause = check.sprintf("cannot convert %s to %s (in %s)", x, u, T) 59 return false 60 } 61 return true 62 }) 63 x.mode = value // type parameters are not constants 64 case x.convertibleTo(check, T, &cause): 65 // non-constant conversion 66 ok = true 67 x.mode = value 68 } 69 70 if !ok { 71 var err error_ 72 if check.conf.CompilerErrorMessages { 73 if cause != "" { 74 // Add colon at end of line if we have a following cause. 75 err.errorf(x, "cannot convert %s to type %s:", x, T) 76 err.errorf(nopos, cause) 77 } else { 78 err.errorf(x, "cannot convert %s to type %s", x, T) 79 } 80 } else { 81 err.errorf(x, "cannot convert %s to %s", x, T) 82 if cause != "" { 83 err.errorf(nopos, cause) 84 } 85 } 86 check.report(&err) 87 x.mode = invalid 88 return 89 } 90 91 // The conversion argument types are final. For untyped values the 92 // conversion provides the type, per the spec: "A constant may be 93 // given a type explicitly by a constant declaration or conversion,...". 94 if isUntyped(x.typ) { 95 final := T 96 // - For conversions to interfaces, except for untyped nil arguments, 97 // use the argument's default type. 98 // - For conversions of untyped constants to non-constant types, also 99 // use the default type (e.g., []byte("foo") should report string 100 // not []byte as type for the constant "foo"). 101 // - For integer to string conversions, keep the argument type. 102 // (See also the TODO below.) 103 if x.typ == Typ[UntypedNil] { 104 // ok 105 } else if IsInterface(T) && !isTypeParam(T) || constArg && !isConstType(T) { 106 final = Default(x.typ) 107 } else if isInteger(x.typ) && allString(T) { 108 final = x.typ 109 } 110 check.updateExprType(x.expr, final, true) 111 } 112 113 x.typ = T 114} 115 116// TODO(gri) convertibleTo checks if T(x) is valid. It assumes that the type 117// of x is fully known, but that's not the case for say string(1<<s + 1.0): 118// Here, the type of 1<<s + 1.0 will be UntypedFloat which will lead to the 119// (correct!) refusal of the conversion. But the reported error is essentially 120// "cannot convert untyped float value to string", yet the correct error (per 121// the spec) is that we cannot shift a floating-point value: 1 in 1<<s should 122// be converted to UntypedFloat because of the addition of 1.0. Fixing this 123// is tricky because we'd have to run updateExprType on the argument first. 124// (Issue #21982.) 125 126// convertibleTo reports whether T(x) is valid. In the failure case, *cause 127// may be set to the cause for the failure. 128// The check parameter may be nil if convertibleTo is invoked through an 129// exported API call, i.e., when all methods have been type-checked. 130func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool { 131 // "x is assignable to T" 132 if ok, _ := x.assignableTo(check, T, cause); ok { 133 return true 134 } 135 136 // "V and T have identical underlying types if tags are ignored 137 // and V and T are not type parameters" 138 V := x.typ 139 Vu := under(V) 140 Tu := under(T) 141 Vp, _ := V.(*TypeParam) 142 Tp, _ := T.(*TypeParam) 143 if IdenticalIgnoreTags(Vu, Tu) && Vp == nil && Tp == nil { 144 return true 145 } 146 147 // "V and T are unnamed pointer types and their pointer base types 148 // have identical underlying types if tags are ignored 149 // and their pointer base types are not type parameters" 150 if V, ok := V.(*Pointer); ok { 151 if T, ok := T.(*Pointer); ok { 152 if IdenticalIgnoreTags(under(V.base), under(T.base)) && !isTypeParam(V.base) && !isTypeParam(T.base) { 153 return true 154 } 155 } 156 } 157 158 // "V and T are both integer or floating point types" 159 if isIntegerOrFloat(Vu) && isIntegerOrFloat(Tu) { 160 return true 161 } 162 163 // "V and T are both complex types" 164 if isComplex(Vu) && isComplex(Tu) { 165 return true 166 } 167 168 // "V is an integer or a slice of bytes or runes and T is a string type" 169 if (isInteger(Vu) || isBytesOrRunes(Vu)) && isString(Tu) { 170 return true 171 } 172 173 // "V is a string and T is a slice of bytes or runes" 174 if isString(Vu) && isBytesOrRunes(Tu) { 175 return true 176 } 177 178 // package unsafe: 179 // "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer" 180 if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(Tu) { 181 return true 182 } 183 // "and vice versa" 184 if isUnsafePointer(Vu) && (isPointer(Tu) || isUintptr(Tu)) { 185 return true 186 } 187 188 // "V a slice, T is a pointer-to-array type, 189 // and the slice and array types have identical element types." 190 if s, _ := Vu.(*Slice); s != nil { 191 if p, _ := Tu.(*Pointer); p != nil { 192 if a, _ := under(p.Elem()).(*Array); a != nil { 193 if Identical(s.Elem(), a.Elem()) { 194 if check == nil || check.allowVersion(check.pkg, 1, 17) { 195 return true 196 } 197 // check != nil 198 if cause != nil { 199 *cause = "conversion of slices to array pointers requires go1.17 or later" 200 if check.conf.CompilerErrorMessages { 201 *cause += fmt.Sprintf(" (-lang was set to %s; check go.mod)", check.conf.GoVersion) 202 } 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 ...interface{}) { 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 %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 %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 %s (in %s)", x.typ, T.typ, Tp) 266 return false 267 } 268 return true 269 }) 270 } 271 272 return false 273} 274 275func isUintptr(typ Type) bool { 276 t, _ := under(typ).(*Basic) 277 return t != nil && t.kind == Uintptr 278} 279 280func isUnsafePointer(typ Type) bool { 281 t, _ := under(typ).(*Basic) 282 return t != nil && t.kind == UnsafePointer 283} 284 285func isPointer(typ Type) bool { 286 _, ok := under(typ).(*Pointer) 287 return ok 288} 289 290func 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} 297