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  }