// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. // Source: ../../cmd/compile/internal/types2/conversions.go // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // This file implements typechecking of conversions. package types import ( "go/constant" . "internal/types/errors" "unicode" ) // conversion type-checks the conversion T(x). // The result is in x. func (check *Checker) conversion(x *operand, T Type) { constArg := x.mode() == constant_ var ok bool var cause string switch { case constArg && isConstType(T): // constant conversion ok = x.constConvertibleTo(check, T, &x.val, &cause) case constArg && isTypeParam(T): // x is convertible to T if it is convertible // to each specific type in the type set of T. // If T's type set is empty, or if it doesn't // have specific types, constant x cannot be // converted. ok = underIs(T, func(u Type) bool { // u is nil if there are no specific type terms if u == nil { cause = check.sprintf("%s does not contain specific types", T) return false } if isString(x.typ()) && isBytesOrRunes(u) { return true } if !x.constConvertibleTo(check, u, nil, &cause) { if cause == "" { cause = check.sprintf("cannot convert %s to type %s", x, u) } cause = check.sprintf("%s (in %s)", cause, T) return false } return true }) x.mode_ = value // type parameters are not constants case x.convertibleTo(check, T, &cause): // non-constant conversion ok = true x.mode_ = value } if !ok { if cause != "" { check.errorf(x, InvalidConversion, "cannot convert %s to type %s: %s", x, T, cause) } else { check.errorf(x, InvalidConversion, "cannot convert %s to type %s", x, T) } x.invalidate() return } // The conversion argument types are final. For untyped values the // conversion provides the type, per the spec: "A constant may be // given a type explicitly by a constant declaration or conversion,...". if isUntyped(x.typ()) { final := T // - For conversions to interfaces, except for untyped nil arguments // and isTypes2, use the argument's default type. // - For conversions of untyped constants to non-constant types, also // use the default type (e.g., []byte("foo") should report string // not []byte as type for the constant "foo"). // - If !isTypes2, keep untyped nil for untyped nil arguments. // - For constant integer to string conversions, keep the argument type. // (See also the TODO below.) if isTypes2 && x.typ() == Typ[UntypedNil] { // ok } else if isNonTypeParamInterface(T) || constArg && !isConstType(T) || !isTypes2 && x.isNil() { final = Default(x.typ()) // default type of untyped nil is untyped nil } else if x.mode() == constant_ && isInteger(x.typ()) && allString(T) { final = x.typ() } check.updateExprType(x.expr, final, true) } x.typ_ = T } // constConvertibleTo reports whether constant operand x can be converted // to a constant value of type T. If true, and a non-nil val is provided, // the function sets *val to the respective constant value as a side-effect. // If false, a non-empty *cause string explains the failure; cause must not be nil. func (x *operand) constConvertibleTo(check *Checker, T Type, val *constant.Value, cause *string) bool { assert(x.mode() == constant_) // T must be a constant type t, ok := T.Underlying().(*Basic) if !ok { *cause = check.sprintf("%s is not a valid constant type", T) return false } // string(x) if isInteger(x.typ()) && isString(t) { if check.allowVersion(go1_28) && !isByteOrRune(x.typ()) { *cause = check.sprintf("argument must be untyped rune constant or have type byte or rune with %s or later", go1_28) return false } codepoint := unicode.ReplacementChar if i, ok := constant.Uint64Val(x.val); ok && i <= unicode.MaxRune { codepoint = rune(i) } if val != nil { *val = constant.MakeString(string(codepoint)) } return true } // T(x) if !representableConst(x.val, check, t, val) { // provide a cause if possible var msg string switch { case isInteger(x.typ()) && isInteger(t): // A conversion from an integer constant to an integer type // can only fail if there's overflow (go.dev/issue/63563). msg = "%s overflows %s" case isNumeric(x.typ()) && isNumeric(t): // A conversion from a numeric type to another numeric type // where at least one of them is not an integer can only fail // because of truncation. msg = "%s truncated to %s" } if msg != "" { *cause = check.sprintf(msg, x.val, T) } return false } return true } // TODO(gri) convertibleTo checks if T(x) is valid. It assumes that the type // of x is fully known, but that's not the case for say string(1<