github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/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 "go/constant" 10 11 // Conversion type-checks the conversion T(x). 12 // The result is in x. 13 func (check *Checker) conversion(x *operand, T Type) { 14 constArg := x.mode == constant_ 15 16 var ok bool 17 switch { 18 case constArg && isConstType(T): 19 // constant conversion 20 switch t := T.Underlying().(*Basic); { 21 case representableConst(x.val, check.conf, t, &x.val): 22 ok = true 23 case isInteger(x.typ) && isString(t): 24 codepoint := int64(-1) 25 if i, ok := constant.Int64Val(x.val); ok { 26 codepoint = i 27 } 28 // If codepoint < 0 the absolute value is too large (or unknown) for 29 // conversion. This is the same as converting any other out-of-range 30 // value - let string(codepoint) do the work. 31 x.val = constant.MakeString(string(codepoint)) 32 ok = true 33 } 34 case x.convertibleTo(check.conf, T): 35 // non-constant conversion 36 x.mode = value 37 ok = true 38 } 39 40 if !ok { 41 check.errorf(x.pos(), "cannot convert %s to %s", x, T) 42 x.mode = invalid 43 return 44 } 45 46 // The conversion argument types are final. For untyped values the 47 // conversion provides the type, per the spec: "A constant may be 48 // given a type explicitly by a constant declaration or conversion,...". 49 if isUntyped(x.typ) { 50 final := T 51 // - For conversions to interfaces, use the argument's default type. 52 // - For conversions of untyped constants to non-constant types, also 53 // use the default type (e.g., []byte("foo") should report string 54 // not []byte as type for the constant "foo"). 55 // - Keep untyped nil for untyped nil arguments. 56 // - For integer to string conversions, keep the argument type. 57 // (See also the TODO below.) 58 if IsInterface(T) || constArg && !isConstType(T) { 59 final = Default(x.typ) 60 } else if isInteger(x.typ) && isString(T) { 61 final = x.typ 62 } 63 check.updateExprType(x.expr, final, true) 64 } 65 66 x.typ = T 67 } 68 69 // TODO(gri) convertibleTo checks if T(x) is valid. It assumes that the type 70 // of x is fully known, but that's not the case for say string(1<<s + 1.0): 71 // Here, the type of 1<<s + 1.0 will be UntypedFloat which will lead to the 72 // (correct!) refusal of the conversion. But the reported error is essentially 73 // "cannot convert untyped float value to string", yet the correct error (per 74 // the spec) is that we cannot shift a floating-point value: 1 in 1<<s should 75 // be converted to UntypedFloat because of the addition of 1.0. Fixing this 76 // is tricky because we'd have to run updateExprType on the argument first. 77 // (Issue #21982.) 78 79 func (x *operand) convertibleTo(conf *Config, T Type) bool { 80 // "x is assignable to T" 81 if x.assignableTo(conf, T, nil) { 82 return true 83 } 84 85 // "x's type and T have identical underlying types if tags are ignored" 86 V := x.typ 87 Vu := V.Underlying() 88 Tu := T.Underlying() 89 if IdenticalIgnoreTags(Vu, Tu) { 90 return true 91 } 92 93 // "x's type and T are unnamed pointer types and their pointer base types 94 // have identical underlying types if tags are ignored" 95 if V, ok := V.(*Pointer); ok { 96 if T, ok := T.(*Pointer); ok { 97 if IdenticalIgnoreTags(V.base.Underlying(), T.base.Underlying()) { 98 return true 99 } 100 } 101 } 102 103 // "x's type and T are both integer or floating point types" 104 if (isInteger(V) || isFloat(V)) && (isInteger(T) || isFloat(T)) { 105 return true 106 } 107 108 // "x's type and T are both complex types" 109 if isComplex(V) && isComplex(T) { 110 return true 111 } 112 113 // "x is an integer or a slice of bytes or runes and T is a string type" 114 if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) { 115 return true 116 } 117 118 // "x is a string and T is a slice of bytes or runes" 119 if isString(V) && isBytesOrRunes(Tu) { 120 return true 121 } 122 123 // package unsafe: 124 // "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer" 125 if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(T) { 126 return true 127 } 128 // "and vice versa" 129 if isUnsafePointer(V) && (isPointer(Tu) || isUintptr(Tu)) { 130 return true 131 } 132 133 return false 134 } 135 136 func isUintptr(typ Type) bool { 137 t, ok := typ.Underlying().(*Basic) 138 return ok && t.kind == Uintptr 139 } 140 141 func isUnsafePointer(typ Type) bool { 142 // TODO(gri): Is this (typ.Underlying() instead of just typ) correct? 143 // The spec does not say so, but gc claims it is. See also 144 // issue 6326. 145 t, ok := typ.Underlying().(*Basic) 146 return ok && t.kind == UnsafePointer 147 } 148 149 func isPointer(typ Type) bool { 150 _, ok := typ.Underlying().(*Pointer) 151 return ok 152 } 153 154 func isBytesOrRunes(typ Type) bool { 155 if s, ok := typ.(*Slice); ok { 156 t, ok := s.elem.Underlying().(*Basic) 157 return ok && (t.kind == Byte || t.kind == Rune) 158 } 159 return false 160 }