Source file src/cmd/compile/internal/types2/conversions.go

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

View as plain text