...

Source file src/go/types/conversions.go

Documentation: go/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 (
		10  	"go/constant"
		11  	"unicode"
		12  )
		13  
		14  // Conversion type-checks the conversion T(x).
		15  // The result is in x.
		16  func (check *Checker) conversion(x *operand, T Type) {
		17  	constArg := x.mode == constant_
		18  
		19  	var ok bool
		20  	var reason string
		21  	switch {
		22  	case constArg && isConstType(T):
		23  		// constant conversion
		24  		switch t := asBasic(T); {
		25  		case representableConst(x.val, check, t, &x.val):
		26  			ok = true
		27  		case isInteger(x.typ) && isString(t):
		28  			codepoint := unicode.ReplacementChar
		29  			if i, ok := constant.Uint64Val(x.val); ok && i <= unicode.MaxRune {
		30  				codepoint = rune(i)
		31  			}
		32  			x.val = constant.MakeString(string(codepoint))
		33  			ok = true
		34  		}
		35  	case x.convertibleTo(check, T, &reason):
		36  		// non-constant conversion
		37  		x.mode = value
		38  		ok = true
		39  	}
		40  
		41  	if !ok {
		42  		if reason != "" {
		43  			check.errorf(x, _InvalidConversion, "cannot convert %s to %s (%s)", x, T, reason)
		44  		} else {
		45  			check.errorf(x, _InvalidConversion, "cannot convert %s to %s", x, T)
		46  		}
		47  		x.mode = invalid
		48  		return
		49  	}
		50  
		51  	// The conversion argument types are final. For untyped values the
		52  	// conversion provides the type, per the spec: "A constant may be
		53  	// given a type explicitly by a constant declaration or conversion,...".
		54  	if isUntyped(x.typ) {
		55  		final := T
		56  		// - For conversions to interfaces, use the argument's default type.
		57  		// - For conversions of untyped constants to non-constant types, also
		58  		//	 use the default type (e.g., []byte("foo") should report string
		59  		//	 not []byte as type for the constant "foo").
		60  		// - Keep untyped nil for untyped nil arguments.
		61  		// - For integer to string conversions, keep the argument type.
		62  		//	 (See also the TODO below.)
		63  		if IsInterface(T) || constArg && !isConstType(T) || x.isNil() {
		64  			final = Default(x.typ) // default type of untyped nil is untyped nil
		65  		} else if isInteger(x.typ) && isString(T) {
		66  			final = x.typ
		67  		}
		68  		check.updateExprType(x.expr, final, true)
		69  	}
		70  
		71  	x.typ = T
		72  }
		73  
		74  // TODO(gri) convertibleTo checks if T(x) is valid. It assumes that the type
		75  // of x is fully known, but that's not the case for say string(1<<s + 1.0):
		76  // Here, the type of 1<<s + 1.0 will be UntypedFloat which will lead to the
		77  // (correct!) refusal of the conversion. But the reported error is essentially
		78  // "cannot convert untyped float value to string", yet the correct error (per
		79  // the spec) is that we cannot shift a floating-point value: 1 in 1<<s should
		80  // be converted to UntypedFloat because of the addition of 1.0. Fixing this
		81  // is tricky because we'd have to run updateExprType on the argument first.
		82  // (Issue #21982.)
		83  
		84  // convertibleTo reports whether T(x) is valid.
		85  // The check parameter may be nil if convertibleTo is invoked through an
		86  // exported API call, i.e., when all methods have been type-checked.
		87  func (x *operand) convertibleTo(check *Checker, T Type, reason *string) bool {
		88  	// "x is assignable to T"
		89  	if ok, _ := x.assignableTo(check, T, nil); ok {
		90  		return true
		91  	}
		92  
		93  	// "x's type and T have identical underlying types if tags are ignored"
		94  	V := x.typ
		95  	Vu := under(V)
		96  	Tu := under(T)
		97  	if check.identicalIgnoreTags(Vu, Tu) {
		98  		return true
		99  	}
	 100  
	 101  	// "x's type and T are unnamed pointer types and their pointer base types
	 102  	// have identical underlying types if tags are ignored"
	 103  	if V, ok := V.(*Pointer); ok {
	 104  		if T, ok := T.(*Pointer); ok {
	 105  			if check.identicalIgnoreTags(under(V.base), under(T.base)) {
	 106  				return true
	 107  			}
	 108  		}
	 109  	}
	 110  
	 111  	// "x's type and T are both integer or floating point types"
	 112  	if isIntegerOrFloat(V) && isIntegerOrFloat(T) {
	 113  		return true
	 114  	}
	 115  
	 116  	// "x's type and T are both complex types"
	 117  	if isComplex(V) && isComplex(T) {
	 118  		return true
	 119  	}
	 120  
	 121  	// "x is an integer or a slice of bytes or runes and T is a string type"
	 122  	if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) {
	 123  		return true
	 124  	}
	 125  
	 126  	// "x is a string and T is a slice of bytes or runes"
	 127  	if isString(V) && isBytesOrRunes(Tu) {
	 128  		return true
	 129  	}
	 130  
	 131  	// package unsafe:
	 132  	// "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer"
	 133  	if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(T) {
	 134  		return true
	 135  	}
	 136  	// "and vice versa"
	 137  	if isUnsafePointer(V) && (isPointer(Tu) || isUintptr(Tu)) {
	 138  		return true
	 139  	}
	 140  
	 141  	// "x is a slice, T is a pointer-to-array type,
	 142  	// and the slice and array types have identical element types."
	 143  	if s := asSlice(V); s != nil {
	 144  		if p := asPointer(T); p != nil {
	 145  			if a := asArray(p.Elem()); a != nil {
	 146  				if check.identical(s.Elem(), a.Elem()) {
	 147  					if check == nil || check.allowVersion(check.pkg, 1, 17) {
	 148  						return true
	 149  					}
	 150  					if reason != nil {
	 151  						*reason = "conversion of slices to array pointers requires go1.17 or later"
	 152  					}
	 153  				}
	 154  			}
	 155  		}
	 156  	}
	 157  
	 158  	return false
	 159  }
	 160  
	 161  func isUintptr(typ Type) bool {
	 162  	t := asBasic(typ)
	 163  	return t != nil && t.kind == Uintptr
	 164  }
	 165  
	 166  func isUnsafePointer(typ Type) bool {
	 167  	// TODO(gri): Is this asBasic(typ) instead of typ.(*Basic) correct?
	 168  	//						(The former calls under(), while the latter doesn't.)
	 169  	//						The spec does not say so, but gc claims it is. See also
	 170  	//						issue 6326.
	 171  	t := asBasic(typ)
	 172  	return t != nil && t.kind == UnsafePointer
	 173  }
	 174  
	 175  func isPointer(typ Type) bool {
	 176  	return asPointer(typ) != nil
	 177  }
	 178  
	 179  func isBytesOrRunes(typ Type) bool {
	 180  	if s := asSlice(typ); s != nil {
	 181  		t := asBasic(s.elem)
	 182  		return t != nil && (t.kind == Byte || t.kind == Rune)
	 183  	}
	 184  	return false
	 185  }
	 186  

View as plain text