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  }