github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/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, 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, 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 // convertibleTo reports whether T(x) is valid. 80 // The check parameter may be nil if convertibleTo is invoked through an 81 // exported API call, i.e., when all methods have been type-checked. 82 func (x *operand) convertibleTo(check *Checker, T Type) bool { 83 // "x is assignable to T" 84 if x.assignableTo(check, T, nil) { 85 return true 86 } 87 88 // "x's type and T have identical underlying types if tags are ignored" 89 V := x.typ 90 Vu := V.Underlying() 91 Tu := T.Underlying() 92 if IdenticalIgnoreTags(Vu, Tu) { 93 return true 94 } 95 96 // "x's type and T are unnamed pointer types and their pointer base types 97 // have identical underlying types if tags are ignored" 98 if V, ok := V.(*Pointer); ok { 99 if T, ok := T.(*Pointer); ok { 100 if IdenticalIgnoreTags(V.base.Underlying(), T.base.Underlying()) { 101 return true 102 } 103 } 104 } 105 106 // "x's type and T are both integer or floating point types" 107 if (isInteger(V) || isFloat(V)) && (isInteger(T) || isFloat(T)) { 108 return true 109 } 110 111 // "x's type and T are both complex types" 112 if isComplex(V) && isComplex(T) { 113 return true 114 } 115 116 // "x is an integer or a slice of bytes or runes and T is a string type" 117 if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) { 118 return true 119 } 120 121 // "x is a string and T is a slice of bytes or runes" 122 if isString(V) && isBytesOrRunes(Tu) { 123 return true 124 } 125 126 // package unsafe: 127 // "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer" 128 if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(T) { 129 return true 130 } 131 // "and vice versa" 132 if isUnsafePointer(V) && (isPointer(Tu) || isUintptr(Tu)) { 133 return true 134 } 135 136 return false 137 } 138 139 func isUintptr(typ Type) bool { 140 t, ok := typ.Underlying().(*Basic) 141 return ok && t.kind == Uintptr 142 } 143 144 func isUnsafePointer(typ Type) bool { 145 // TODO(gri): Is this (typ.Underlying() instead of just typ) correct? 146 // The spec does not say so, but gc claims it is. See also 147 // issue 6326. 148 t, ok := typ.Underlying().(*Basic) 149 return ok && t.kind == UnsafePointer 150 } 151 152 func isPointer(typ Type) bool { 153 _, ok := typ.Underlying().(*Pointer) 154 return ok 155 } 156 157 func isBytesOrRunes(typ Type) bool { 158 if s, ok := typ.(*Slice); ok { 159 t, ok := s.elem.Underlying().(*Basic) 160 return ok && (t.kind == Byte || t.kind == Rune) 161 } 162 return false 163 }