// 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" "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 reason string switch { case constArg && isConstType(T): // constant conversion switch t := asBasic(T); { case representableConst(x.val, check, t, &x.val): ok = true case isInteger(x.typ) && isString(t): codepoint := unicode.ReplacementChar if i, ok := constant.Uint64Val(x.val); ok && i <= unicode.MaxRune { codepoint = rune(i) } x.val = constant.MakeString(string(codepoint)) ok = true } case x.convertibleTo(check, T, &reason): // non-constant conversion x.mode = value ok = true } if !ok { if reason != "" { check.errorf(x, _InvalidConversion, "cannot convert %s to %s (%s)", x, T, reason) } else { check.errorf(x, _InvalidConversion, "cannot convert %s to %s", x, T) } x.mode = invalid 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, 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"). // - Keep untyped nil for untyped nil arguments. // - For integer to string conversions, keep the argument type. // (See also the TODO below.) if IsInterface(T) || constArg && !isConstType(T) || x.isNil() { final = Default(x.typ) // default type of untyped nil is untyped nil } else if isInteger(x.typ) && isString(T) { final = x.typ } check.updateExprType(x.expr, final, true) } x.typ = T } // 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<