// 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 switch { case constArg && isConstType(T): // constant conversion switch t := T.Underlying().(*Basic); { case representableConst(x.val, check.conf, t.kind, &x.val): ok = true case x.isInteger() && isString(t): codepoint := int64(-1) if i, ok := exact.Int64Val(x.val); ok { codepoint = i } // If codepoint < 0 the absolute value is too large (or unknown) for // conversion. This is the same as converting any other out-of-range // value - let string(codepoint) do the work. x.val = exact.MakeString(string(codepoint)) ok = true } case x.convertibleTo(check.conf, T): // non-constant conversion x.mode = value ok = true } if !ok { check.errorf(x.pos(), "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,...". final := x.typ 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. if isInterface(T) || constArg && !isConstType(T) { final = defaultType(x.typ) } check.updateExprType(x.expr, final, true) } x.typ = T }
func (p *importer) value() exact.Value { switch kind := exact.Kind(p.int()); kind { case falseTag: return exact.MakeBool(false) case trueTag: return exact.MakeBool(true) case int64Tag: return exact.MakeInt64(p.int64()) case floatTag: return p.float() case fractionTag: return p.fraction() case complexTag: re := p.fraction() im := p.fraction() return exact.BinaryOp(re, token.ADD, exact.MakeImag(im)) case stringTag: return exact.MakeString(p.string()) default: panic(fmt.Sprintf("unexpected value kind %d", kind)) } }
// ConstValue = string | "false" | "true" | ["-"] (int ["'"] | FloatOrComplex) . // FloatOrComplex = float ["i" | ("+"|"-") float "i"] . func (p *parser) parseConstValue() (val exact.Value, typ types.Type) { switch p.tok { case scanner.String: str := p.parseString() val = exact.MakeString(str) typ = types.Typ[types.UntypedString] return case scanner.Ident: b := false switch p.lit { case "false": case "true": b = true default: p.errorf("expected const value, got %s (%q)", scanner.TokenString(p.tok), p.lit) } p.next() val = exact.MakeBool(b) typ = types.Typ[types.UntypedBool] return } sign := "" if p.tok == '-' { p.next() sign = "-" } switch p.tok { case scanner.Int: val = exact.MakeFromLiteral(sign+p.lit, token.INT) if val == nil { p.error("could not parse integer literal") } p.next() if p.tok == '\'' { p.next() typ = types.Typ[types.UntypedRune] } else { typ = types.Typ[types.UntypedInt] } case scanner.Float: re := sign + p.lit p.next() var im string switch p.tok { case '+': p.next() im = p.expect(scanner.Float) case '-': p.next() im = "-" + p.expect(scanner.Float) case scanner.Ident: // re is in fact the imaginary component. Expect "i" below. im = re re = "0" default: val = exact.MakeFromLiteral(re, token.FLOAT) if val == nil { p.error("could not parse float literal") } typ = types.Typ[types.UntypedFloat] return } p.expectKeyword("i") reval := exact.MakeFromLiteral(re, token.FLOAT) if reval == nil { p.error("could not parse real component of complex literal") } imval := exact.MakeFromLiteral(im+"i", token.IMAG) if imval == nil { p.error("could not parse imag component of complex literal") } val = exact.BinaryOp(reval, token.ADD, imval) typ = types.Typ[types.UntypedComplex] default: p.errorf("expected const value, got %s (%q)", scanner.TokenString(p.tok), p.lit) } return }