Source file src/go/types/conversions.go

     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  

View as plain text