conversions.go raw

   1  // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
   2  // Source: ../../cmd/compile/internal/types2/conversions.go
   3  
   4  // Copyright 2012 The Go Authors. All rights reserved.
   5  // Use of this source code is governed by a BSD-style
   6  // license that can be found in the LICENSE file.
   7  
   8  // This file implements typechecking of conversions.
   9  
  10  package types
  11  
  12  import (
  13  	"go/constant"
  14  	. "internal/types/errors"
  15  	"unicode"
  16  )
  17  
  18  // conversion type-checks the conversion T(x).
  19  // The result is in x.
  20  func (check *Checker) conversion(x *operand, T Type) {
  21  	constArg := x.mode == constant_
  22  
  23  	constConvertibleTo := func(T Type, val *constant.Value) bool {
  24  		switch t, _ := under(T).(*Basic); {
  25  		case t == nil:
  26  			// nothing to do
  27  		case representableConst(x.val, check, t, val):
  28  			return true
  29  		case isInteger(x.typ) && isString(t):
  30  			codepoint := unicode.ReplacementChar
  31  			if i, ok := constant.Uint64Val(x.val); ok && i <= unicode.MaxRune {
  32  				codepoint = rune(i)
  33  			}
  34  			if val != nil {
  35  				*val = constant.MakeString(string(codepoint))
  36  			}
  37  			return true
  38  		}
  39  		return false
  40  	}
  41  
  42  	var ok bool
  43  	var cause string
  44  	switch {
  45  	case constArg && isConstType(T):
  46  		// constant conversion
  47  		ok = constConvertibleTo(T, &x.val)
  48  		// A conversion from an integer constant to an integer type
  49  		// can only fail if there's overflow. Give a concise error.
  50  		// (go.dev/issue/63563)
  51  		if !ok && isInteger(x.typ) && isInteger(T) {
  52  			check.errorf(x, InvalidConversion, "constant %s overflows %s", x.val, T)
  53  			x.mode = invalid
  54  			return
  55  		}
  56  	case constArg && isTypeParam(T):
  57  		// x is convertible to T if it is convertible
  58  		// to each specific type in the type set of T.
  59  		// If T's type set is empty, or if it doesn't
  60  		// have specific types, constant x cannot be
  61  		// converted.
  62  		ok = underIs(T, func(u Type) bool {
  63  			// u is nil if there are no specific type terms
  64  			if u == nil {
  65  				cause = check.sprintf("%s does not contain specific types", T)
  66  				return false
  67  			}
  68  			if isString(x.typ) && isBytesOrRunes(u) {
  69  				return true
  70  			}
  71  			if !constConvertibleTo(u, nil) {
  72  				if isInteger(x.typ) && isInteger(u) {
  73  					// see comment above on constant conversion
  74  					cause = check.sprintf("constant %s overflows %s (in %s)", x.val, u, T)
  75  				} else {
  76  					cause = check.sprintf("cannot convert %s to type %s (in %s)", x, u, T)
  77  				}
  78  				return false
  79  			}
  80  			return true
  81  		})
  82  		x.mode = value // type parameters are not constants
  83  	case x.convertibleTo(check, T, &cause):
  84  		// non-constant conversion
  85  		ok = true
  86  		x.mode = value
  87  	}
  88  
  89  	if !ok {
  90  		if cause != "" {
  91  			check.errorf(x, InvalidConversion, "cannot convert %s to type %s: %s", x, T, cause)
  92  		} else {
  93  			check.errorf(x, InvalidConversion, "cannot convert %s to type %s", x, T)
  94  		}
  95  		x.mode = invalid
  96  		return
  97  	}
  98  
  99  	// The conversion argument types are final. For untyped values the
 100  	// conversion provides the type, per the spec: "A constant may be
 101  	// given a type explicitly by a constant declaration or conversion,...".
 102  	if isUntyped(x.typ) {
 103  		final := T
 104  		// - For conversions to interfaces, except for untyped nil arguments
 105  		//   and isTypes2, use the argument's default type.
 106  		// - For conversions of untyped constants to non-constant types, also
 107  		//   use the default type (e.g., []byte("foo") should report string
 108  		//   not []byte as type for the constant "foo").
 109  		// - If !isTypes2, keep untyped nil for untyped nil arguments.
 110  		// - For constant integer to string conversions, keep the argument type.
 111  		//   (See also the TODO below.)
 112  		if isTypes2 && x.typ == Typ[UntypedNil] {
 113  			// ok
 114  		} else if isNonTypeParamInterface(T) || constArg && !isConstType(T) || !isTypes2 && x.isNil() {
 115  			final = Default(x.typ) // default type of untyped nil is untyped nil
 116  		} else if x.mode == constant_ && isInteger(x.typ) && allString(T) {
 117  			final = x.typ
 118  		}
 119  		check.updateExprType(x.expr, final, true)
 120  	}
 121  
 122  	x.typ = T
 123  }
 124  
 125  // TODO(gri) convertibleTo checks if T(x) is valid. It assumes that the type
 126  // of x is fully known, but that's not the case for say string(1<<s + 1.0):
 127  // Here, the type of 1<<s + 1.0 will be UntypedFloat which will lead to the
 128  // (correct!) refusal of the conversion. But the reported error is essentially
 129  // "cannot convert untyped float value to string", yet the correct error (per
 130  // the spec) is that we cannot shift a floating-point value: 1 in 1<<s should
 131  // be converted to UntypedFloat because of the addition of 1.0. Fixing this
 132  // is tricky because we'd have to run updateExprType on the argument first.
 133  // (go.dev/issue/21982.)
 134  
 135  // convertibleTo reports whether T(x) is valid. In the failure case, *cause
 136  // may be set to the cause for the failure.
 137  // The check parameter may be nil if convertibleTo is invoked through an
 138  // exported API call, i.e., when all methods have been type-checked.
 139  func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
 140  	// "x is assignable to T"
 141  	if ok, _ := x.assignableTo(check, T, cause); ok {
 142  		return true
 143  	}
 144  
 145  	origT := T
 146  	V := Unalias(x.typ)
 147  	T = Unalias(T)
 148  	Vu := under(V)
 149  	Tu := under(T)
 150  	Vp, _ := V.(*TypeParam)
 151  	Tp, _ := T.(*TypeParam)
 152  
 153  	// "V and T have identical underlying types if tags are ignored
 154  	// and V and T are not type parameters"
 155  	if IdenticalIgnoreTags(Vu, Tu) && Vp == nil && Tp == nil {
 156  		return true
 157  	}
 158  
 159  	// "V and T are unnamed pointer types and their pointer base types
 160  	// have identical underlying types if tags are ignored
 161  	// and their pointer base types are not type parameters"
 162  	if V, ok := V.(*Pointer); ok {
 163  		if T, ok := T.(*Pointer); ok {
 164  			if IdenticalIgnoreTags(under(V.base), under(T.base)) && !isTypeParam(V.base) && !isTypeParam(T.base) {
 165  				return true
 166  			}
 167  		}
 168  	}
 169  
 170  	// "V and T are both integer or floating point types"
 171  	if isIntegerOrFloat(Vu) && isIntegerOrFloat(Tu) {
 172  		return true
 173  	}
 174  
 175  	// "V and T are both complex types"
 176  	if isComplex(Vu) && isComplex(Tu) {
 177  		return true
 178  	}
 179  
 180  	// "V is an integer or a slice of bytes or runes and T is a string type"
 181  	if (isInteger(Vu) || isBytesOrRunes(Vu)) && isString(Tu) {
 182  		return true
 183  	}
 184  
 185  	// "V is a string and T is a slice of bytes or runes"
 186  	if isString(Vu) && isBytesOrRunes(Tu) {
 187  		return true
 188  	}
 189  
 190  	// package unsafe:
 191  	// "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer"
 192  	if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(Tu) {
 193  		return true
 194  	}
 195  	// "and vice versa"
 196  	if isUnsafePointer(Vu) && (isPointer(Tu) || isUintptr(Tu)) {
 197  		return true
 198  	}
 199  
 200  	// "V is a slice, T is an array or pointer-to-array type,
 201  	// and the slice and array types have identical element types."
 202  	if s, _ := Vu.(*Slice); s != nil {
 203  		switch a := Tu.(type) {
 204  		case *Array:
 205  			if Identical(s.Elem(), a.Elem()) {
 206  				if check == nil || check.allowVersion(go1_20) {
 207  					return true
 208  				}
 209  				// check != nil
 210  				if cause != nil {
 211  					// TODO(gri) consider restructuring versionErrorf so we can use it here and below
 212  					*cause = "conversion of slice to array requires go1.20 or later"
 213  				}
 214  				return false
 215  			}
 216  		case *Pointer:
 217  			if a, _ := under(a.Elem()).(*Array); a != nil {
 218  				if Identical(s.Elem(), a.Elem()) {
 219  					if check == nil || check.allowVersion(go1_17) {
 220  						return true
 221  					}
 222  					// check != nil
 223  					if cause != nil {
 224  						*cause = "conversion of slice to array pointer requires go1.17 or later"
 225  					}
 226  					return false
 227  				}
 228  			}
 229  		}
 230  	}
 231  
 232  	// optimization: if we don't have type parameters, we're done
 233  	if Vp == nil && Tp == nil {
 234  		return false
 235  	}
 236  
 237  	errorf := func(format string, args ...any) {
 238  		if check != nil && cause != nil {
 239  			msg := check.sprintf(format, args...)
 240  			if *cause != "" {
 241  				msg += "\n\t" + *cause
 242  			}
 243  			*cause = msg
 244  		}
 245  	}
 246  
 247  	// generic cases with specific type terms
 248  	// (generic operands cannot be constants, so we can ignore x.val)
 249  	switch {
 250  	case Vp != nil && Tp != nil:
 251  		x := *x // don't clobber outer x
 252  		return Vp.is(func(V *term) bool {
 253  			if V == nil {
 254  				return false // no specific types
 255  			}
 256  			x.typ = V.typ
 257  			return Tp.is(func(T *term) bool {
 258  				if T == nil {
 259  					return false // no specific types
 260  				}
 261  				if !x.convertibleTo(check, T.typ, cause) {
 262  					errorf("cannot convert %s (in %s) to type %s (in %s)", V.typ, Vp, T.typ, Tp)
 263  					return false
 264  				}
 265  				return true
 266  			})
 267  		})
 268  	case Vp != nil:
 269  		x := *x // don't clobber outer x
 270  		return Vp.is(func(V *term) bool {
 271  			if V == nil {
 272  				return false // no specific types
 273  			}
 274  			x.typ = V.typ
 275  			if !x.convertibleTo(check, T, cause) {
 276  				errorf("cannot convert %s (in %s) to type %s", V.typ, Vp, origT)
 277  				return false
 278  			}
 279  			return true
 280  		})
 281  	case Tp != nil:
 282  		return Tp.is(func(T *term) bool {
 283  			if T == nil {
 284  				return false // no specific types
 285  			}
 286  			if !x.convertibleTo(check, T.typ, cause) {
 287  				errorf("cannot convert %s to type %s (in %s)", x.typ, T.typ, Tp)
 288  				return false
 289  			}
 290  			return true
 291  		})
 292  	}
 293  
 294  	return false
 295  }
 296  
 297  func isUintptr(typ Type) bool {
 298  	t, _ := under(typ).(*Basic)
 299  	return t != nil && t.kind == Uintptr
 300  }
 301  
 302  func isUnsafePointer(typ Type) bool {
 303  	t, _ := under(typ).(*Basic)
 304  	return t != nil && t.kind == UnsafePointer
 305  }
 306  
 307  func isPointer(typ Type) bool {
 308  	_, ok := under(typ).(*Pointer)
 309  	return ok
 310  }
 311  
 312  func isBytesOrRunes(typ Type) bool {
 313  	if s, _ := under(typ).(*Slice); s != nil {
 314  		t, _ := under(s.elem).(*Basic)
 315  		return t != nil && (t.kind == Byte || t.kind == Rune)
 316  	}
 317  	return false
 318  }
 319