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