github.com/aloncn/graphics-go@v0.0.1/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 = defaultType(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" 73 V := x.typ 74 Vu := V.Underlying() 75 Tu := T.Underlying() 76 if Identical(Vu, Tu) { 77 return true 78 } 79 80 // "x's type and T are unnamed pointer types and their pointer base types have identical underlying types" 81 if V, ok := V.(*Pointer); ok { 82 if T, ok := T.(*Pointer); ok { 83 if Identical(V.base.Underlying(), T.base.Underlying()) { 84 return true 85 } 86 } 87 } 88 89 // "x's type and T are both integer or floating point types" 90 if (isInteger(V) || isFloat(V)) && (isInteger(T) || isFloat(T)) { 91 return true 92 } 93 94 // "x's type and T are both complex types" 95 if isComplex(V) && isComplex(T) { 96 return true 97 } 98 99 // "x is an integer or a slice of bytes or runes and T is a string type" 100 if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) { 101 return true 102 } 103 104 // "x is a string and T is a slice of bytes or runes" 105 if isString(V) && isBytesOrRunes(Tu) { 106 return true 107 } 108 109 // package unsafe: 110 // "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer" 111 if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(T) { 112 return true 113 } 114 // "and vice versa" 115 if isUnsafePointer(V) && (isPointer(Tu) || isUintptr(Tu)) { 116 return true 117 } 118 119 return false 120 } 121 122 func isUintptr(typ Type) bool { 123 t, ok := typ.Underlying().(*Basic) 124 return ok && t.kind == Uintptr 125 } 126 127 func isUnsafePointer(typ Type) bool { 128 // TODO(gri): Is this (typ.Underlying() instead of just typ) correct? 129 // The spec does not say so, but gc claims it is. See also 130 // issue 6326. 131 t, ok := typ.Underlying().(*Basic) 132 return ok && t.kind == UnsafePointer 133 } 134 135 func isPointer(typ Type) bool { 136 _, ok := typ.Underlying().(*Pointer) 137 return ok 138 } 139 140 func isBytesOrRunes(typ Type) bool { 141 if s, ok := typ.(*Slice); ok { 142 t, ok := s.elem.Underlying().(*Basic) 143 return ok && (t.kind == Byte || t.kind == Rune) 144 } 145 return false 146 }