github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/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 final := x.typ 50 if isUntyped(x.typ) { 51 final = T 52 // - For conversions to interfaces, use the argument's default type. 53 // - For conversions of untyped constants to non-constant types, also 54 // use the default type (e.g., []byte("foo") should report string 55 // not []byte as type for the constant "foo"). 56 // - Keep untyped nil for untyped nil arguments. 57 if IsInterface(T) || constArg && !isConstType(T) { 58 final = Default(x.typ) 59 } 60 check.updateExprType(x.expr, final, true) 61 } 62 63 x.typ = T 64 } 65 66 func (x *operand) convertibleTo(conf *Config, T Type) bool { 67 // "x is assignable to T" 68 if x.assignableTo(conf, T, nil) { 69 return true 70 } 71 72 // "x's type and T have identical underlying types if tags are ignored" 73 V := x.typ 74 Vu := V.Underlying() 75 Tu := T.Underlying() 76 if IdenticalIgnoreTags(Vu, Tu) { 77 return true 78 } 79 80 // "x's type and T are unnamed pointer types and their pointer base types 81 // have identical underlying types if tags are ignored" 82 if V, ok := V.(*Pointer); ok { 83 if T, ok := T.(*Pointer); ok { 84 if IdenticalIgnoreTags(V.base.Underlying(), T.base.Underlying()) { 85 return true 86 } 87 } 88 } 89 90 // "x's type and T are both integer or floating point types" 91 if (isInteger(V) || isFloat(V)) && (isInteger(T) || isFloat(T)) { 92 return true 93 } 94 95 // "x's type and T are both complex types" 96 if isComplex(V) && isComplex(T) { 97 return true 98 } 99 100 // "x is an integer or a slice of bytes or runes and T is a string type" 101 if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) { 102 return true 103 } 104 105 // "x is a string and T is a slice of bytes or runes" 106 if isString(V) && isBytesOrRunes(Tu) { 107 return true 108 } 109 110 // package unsafe: 111 // "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer" 112 if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(T) { 113 return true 114 } 115 // "and vice versa" 116 if isUnsafePointer(V) && (isPointer(Tu) || isUintptr(Tu)) { 117 return true 118 } 119 120 return false 121 } 122 123 func isUintptr(typ Type) bool { 124 t, ok := typ.Underlying().(*Basic) 125 return ok && t.kind == Uintptr 126 } 127 128 func isUnsafePointer(typ Type) bool { 129 // TODO(gri): Is this (typ.Underlying() instead of just typ) correct? 130 // The spec does not say so, but gc claims it is. See also 131 // issue 6326. 132 t, ok := typ.Underlying().(*Basic) 133 return ok && t.kind == UnsafePointer 134 } 135 136 func isPointer(typ Type) bool { 137 _, ok := typ.Underlying().(*Pointer) 138 return ok 139 } 140 141 func isBytesOrRunes(typ Type) bool { 142 if s, ok := typ.(*Slice); ok { 143 t, ok := s.elem.Underlying().(*Basic) 144 return ok && (t.kind == Byte || t.kind == Rune) 145 } 146 return false 147 }