github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/sql/sem/tree/constant.go (about) 1 // Copyright 2016 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package tree 12 13 import ( 14 "context" 15 "go/constant" 16 "go/token" 17 "math" 18 "strings" 19 "time" 20 21 "github.com/cockroachdb/cockroachdb-parser/pkg/sql/lexbase" 22 "github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgcode" 23 "github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgerror" 24 "github.com/cockroachdb/cockroachdb-parser/pkg/sql/types" 25 "github.com/cockroachdb/cockroachdb-parser/pkg/util/intsets" 26 "github.com/cockroachdb/errors" 27 "github.com/lib/pq/oid" 28 ) 29 30 // Constant is an constant literal expression which may be resolved to more than one type. 31 type Constant interface { 32 Expr 33 // AvailableTypes returns the ordered set of types that the Constant is able to 34 // be resolved into. The order of the type slice provides a notion of precedence, 35 // with the first element in the ordering being the Constant's "natural type". 36 AvailableTypes() []*types.T 37 // DesirableTypes returns the ordered set of types that the constant would 38 // prefer to be resolved into. As in AvailableTypes, the order of the returned 39 // type slice provides a notion of precedence, with the first element in the 40 // ordering being the Constant's "natural type." The function is meant to be 41 // differentiated from AvailableTypes in that it will exclude certain types 42 // that are possible, but not desirable. 43 // 44 // An example of this is a floating point numeric constant without a value 45 // past the decimal point. It is possible to resolve this constant as a 46 // decimal, but it is not desirable. 47 DesirableTypes() []*types.T 48 // ResolveAsType resolves the Constant as the specified type, or returns an 49 // error if the Constant could not be resolved as that type. The method should 50 // only be passed a type returned from AvailableTypes and should never be 51 // called more than once for a given Constant. 52 // 53 // The returned expression is either a Datum or a CastExpr wrapping a Datum; 54 // the latter is necessary for cases where the result would depend on the 55 // context (like the timezone or the current time). 56 ResolveAsType(context.Context, *SemaContext, *types.T) (TypedExpr, error) 57 } 58 59 var _ Constant = &NumVal{} 60 var _ Constant = &StrVal{} 61 62 func isConstant(expr Expr) bool { 63 _, ok := expr.(Constant) 64 return ok 65 } 66 67 func isPlaceholder(expr Expr) bool { 68 _, isPlaceholder := StripParens(expr).(*Placeholder) 69 return isPlaceholder 70 } 71 72 func typeCheckConstant( 73 ctx context.Context, semaCtx *SemaContext, c Constant, desired *types.T, 74 ) (ret TypedExpr, err error) { 75 avail := c.AvailableTypes() 76 if !desired.IsAmbiguous() { 77 for _, typ := range avail { 78 if desired.Equivalent(typ) { 79 return c.ResolveAsType(ctx, semaCtx, desired) 80 } 81 } 82 } 83 84 // If a numeric constant will be promoted to a DECIMAL because it was out 85 // of range of an INT, but an INT is desired, throw an error here so that 86 // the error message specifically mentions the overflow. 87 if desired.Family() == types.IntFamily { 88 if n, ok := c.(*NumVal); ok { 89 _, err := n.AsInt64() 90 switch { 91 case errors.Is(err, errConstOutOfRange64): 92 return nil, err 93 case errors.Is(err, errConstNotInt): 94 default: 95 return nil, errors.NewAssertionErrorWithWrappedErrf(err, "unexpected error") 96 } 97 } 98 } 99 100 natural := avail[0] 101 return c.ResolveAsType(ctx, semaCtx, natural) 102 } 103 104 func naturalConstantType(c Constant) *types.T { 105 return c.AvailableTypes()[0] 106 } 107 108 // canConstantBecome returns whether the provided Constant can become resolved 109 // as a type that is Equivalent to the given type. 110 func canConstantBecome(c Constant, typ *types.T) bool { 111 avail := c.AvailableTypes() 112 for _, availTyp := range avail { 113 if availTyp.Equivalent(typ) { 114 return true 115 } 116 } 117 return false 118 } 119 120 // NumVal represents a constant numeric value. 121 type NumVal struct { 122 // value is the constant number, without any sign information. 123 value constant.Value 124 // negative is the sign bit to add to any interpretation of the 125 // value or origString fields. 126 negative bool 127 // origString is the "original" string representation (before 128 // folding). This should remain sign-less. 129 origString string 130 131 // The following fields are used to avoid allocating Datums on type 132 // resolution. 133 resInt64 DInt 134 resInt32 DInt 135 resFloat DFloat 136 resDecimal DDecimal 137 // The following fields indicate whether the NumVal has already been 138 // resolved as the corresponding Datum. 139 resAsInt64 bool 140 resAsInt32 bool 141 resAsFloat bool 142 resAsDecimal bool 143 } 144 145 var _ Constant = &NumVal{} 146 147 // NewNumVal constructs a new NumVal instance. This is used during parsing and 148 // in tests. 149 func NewNumVal(value constant.Value, origString string, negative bool) *NumVal { 150 return &NumVal{value: value, origString: origString, negative: negative} 151 } 152 153 // Kind implements the constant.Value interface. 154 func (expr *NumVal) Kind() constant.Kind { 155 return expr.value.Kind() 156 } 157 158 // ExactString implements the constant.Value interface. 159 func (expr *NumVal) ExactString() string { 160 return expr.value.ExactString() 161 } 162 163 // OrigString returns the origString field. 164 func (expr *NumVal) OrigString() string { 165 return expr.origString 166 } 167 168 // SetNegative sets the negative field to true. The parser calls this when it 169 // identifies a negative constant. 170 func (expr *NumVal) SetNegative() { 171 expr.negative = true 172 } 173 174 // Negate sets the negative field to the opposite of its current value. The 175 // parser calls this to simplify unary negation expressions. 176 func (expr *NumVal) Negate() { 177 expr.negative = !expr.negative 178 } 179 180 // Format implements the NodeFormatter interface. 181 func (expr *NumVal) Format(ctx *FmtCtx) { 182 s := expr.origString 183 if s == "" { 184 s = expr.value.String() 185 } else if strings.EqualFold(s, "NaN") { 186 s = "'NaN'" 187 } 188 if expr.negative { 189 ctx.WriteByte('-') 190 } 191 ctx.WriteString(s) 192 } 193 194 // canBeInt64 checks if it's possible for the value to become an int64: 195 // 196 // 1 = yes 197 // 1.0 = yes 198 // 1.1 = no 199 // 123...overflow...456 = no 200 func (expr *NumVal) canBeInt64() bool { 201 _, err := expr.AsInt64() 202 return err == nil 203 } 204 205 // ShouldBeInt64 checks if the value naturally is an int64: 206 // 207 // 1 = yes 208 // 1.0 = no 209 // 1.1 = no 210 // 123...overflow...456 = no 211 func (expr *NumVal) ShouldBeInt64() bool { 212 return expr.Kind() == constant.Int && expr.canBeInt64() 213 } 214 215 // These errors are statically allocated, because they are returned in the 216 // common path of AsInt64. 217 var errConstNotInt = pgerror.New(pgcode.NumericValueOutOfRange, "cannot represent numeric constant as an int") 218 var errConstOutOfRange64 = pgerror.New(pgcode.NumericValueOutOfRange, "numeric constant out of int64 range") 219 var errConstOutOfRange32 = pgerror.New(pgcode.NumericValueOutOfRange, "numeric constant out of int32 range") 220 221 // AsInt64 returns the value as a 64-bit integer if possible, or returns an 222 // error if not possible. The method will set expr.resInt64 to the value of 223 // this int64 if it is successful, avoiding the need to call the method again. 224 func (expr *NumVal) AsInt64() (int64, error) { 225 if expr.resAsInt64 { 226 return int64(expr.resInt64), nil 227 } 228 intVal, ok := expr.AsConstantInt() 229 if !ok { 230 return 0, errConstNotInt 231 } 232 i, exact := constant.Int64Val(intVal) 233 if !exact { 234 return 0, errConstOutOfRange64 235 } 236 expr.resInt64 = DInt(i) 237 expr.resAsInt64 = true 238 return i, nil 239 } 240 241 // AsInt32 returns the value as 32-bit integer if possible, or returns 242 // an error if not possible. The method will set expr.resInt32 to the 243 // value of this int32 if it is successful, avoiding the need to call 244 // the method again. 245 func (expr *NumVal) AsInt32() (int32, error) { 246 if expr.resAsInt32 { 247 return int32(expr.resInt32), nil 248 } 249 intVal, ok := expr.AsConstantInt() 250 if !ok { 251 return 0, errConstNotInt 252 } 253 i, exact := constant.Int64Val(intVal) 254 if !exact { 255 return 0, errConstOutOfRange32 256 } 257 if i > math.MaxInt32 || i < math.MinInt32 { 258 return 0, errConstOutOfRange32 259 } 260 expr.resInt32 = DInt(i) 261 expr.resAsInt32 = true 262 return int32(i), nil 263 } 264 265 // AsConstantValue returns the value as a constant numerical value, with the proper sign 266 // as given by expr.negative. 267 func (expr *NumVal) AsConstantValue() constant.Value { 268 v := expr.value 269 if expr.negative { 270 v = constant.UnaryOp(token.SUB, v, 0) 271 } 272 return v 273 } 274 275 // AsConstantInt returns the value as an constant.Int if possible, along 276 // with a flag indicating whether the conversion was possible. 277 // The result contains the proper sign as per expr.negative. 278 func (expr *NumVal) AsConstantInt() (constant.Value, bool) { 279 v := expr.AsConstantValue() 280 intVal := constant.ToInt(v) 281 if intVal.Kind() == constant.Int { 282 return intVal, true 283 } 284 return nil, false 285 } 286 287 var ( 288 intLikeTypes = []*types.T{types.Int, types.Oid} 289 decimalLikeTypes = []*types.T{types.Decimal, types.Float} 290 291 // NumValAvailInteger is the set of available integer types. 292 NumValAvailInteger = append(intLikeTypes, decimalLikeTypes...) 293 // NumValAvailIntegerNoOid is the set of available integer types except for OID. 294 NumValAvailIntegerNoOid = append([]*types.T{types.Int}, decimalLikeTypes...) 295 // NumValAvailDecimalNoFraction is the set of available integral numeric types. 296 NumValAvailDecimalNoFraction = append(decimalLikeTypes, intLikeTypes...) 297 // NumValAvailDecimalNoFractionNoOid is the set of available integral numeric types except for OID. 298 NumValAvailDecimalNoFractionNoOid = append(decimalLikeTypes, types.Int) 299 // NumValAvailDecimalWithFraction is the set of available fractional numeric types. 300 NumValAvailDecimalWithFraction = decimalLikeTypes 301 ) 302 303 // AvailableTypes implements the Constant interface. 304 func (expr *NumVal) AvailableTypes() []*types.T { 305 if i, err := expr.AsInt64(); err == nil { 306 noOid := intIsOutOfOIDRange(DInt(i)) 307 intKind := expr.Kind() == constant.Int 308 switch { 309 case noOid && intKind: 310 return NumValAvailIntegerNoOid 311 case noOid && !intKind: 312 return NumValAvailDecimalNoFractionNoOid 313 case !noOid && intKind: 314 return NumValAvailInteger 315 case !noOid && !intKind: 316 return NumValAvailDecimalNoFraction 317 } 318 } 319 return NumValAvailDecimalWithFraction 320 } 321 322 // DesirableTypes implements the Constant interface. 323 func (expr *NumVal) DesirableTypes() []*types.T { 324 if expr.ShouldBeInt64() { 325 return NumValAvailInteger 326 } 327 return NumValAvailDecimalWithFraction 328 } 329 330 // ResolveAsType implements the Constant interface. 331 func (expr *NumVal) ResolveAsType( 332 ctx context.Context, semaCtx *SemaContext, typ *types.T, 333 ) (TypedExpr, error) { 334 switch typ.Family() { 335 case types.IntFamily: 336 // We may have already set expr.resInt64 in AsInt64. 337 if !expr.resAsInt64 { 338 if _, err := expr.AsInt64(); err != nil { 339 return nil, err 340 } 341 } 342 return AdjustValueToType(typ, &expr.resInt64) 343 case types.FloatFamily: 344 if !expr.resAsFloat { 345 if strings.EqualFold(expr.origString, "NaN") { 346 // We need to check NaN separately since expr.value is 347 // unknownVal for NaN. 348 // TODO(sql-sessions): unknownVal is also used for +Inf and 349 // -Inf, so we may need to handle those in the future too. 350 expr.resFloat = DFloat(math.NaN()) 351 } else { 352 f, _ := constant.Float64Val(expr.value) 353 if expr.negative { 354 f = -f 355 } 356 expr.resFloat = DFloat(f) 357 } 358 expr.resAsFloat = true 359 } 360 return &expr.resFloat, nil 361 case types.DecimalFamily: 362 dd := &expr.resDecimal 363 if !expr.resAsDecimal { 364 s := expr.origString 365 if s == "" { 366 // TODO(nvanbenschoten): We should propagate width through 367 // constant folding so that we can control precision on folded 368 // values as well. 369 s = expr.ExactString() 370 } 371 if idx := strings.IndexRune(s, '/'); idx != -1 { 372 // Handle constant.ratVal, which will return a rational string 373 // like 6/7. If only we could call big.Rat.FloatString() on 374 // it... 375 num, den := s[:idx], s[idx+1:] 376 if err := dd.SetString(num); err != nil { 377 return nil, pgerror.Wrapf(err, pgcode.Syntax, 378 "could not evaluate numerator of %v as Datum type DDecimal from string %q", 379 expr, num) 380 } 381 // TODO(nvanbenschoten): Should we try to avoid this allocation? 382 denDec, err := ParseDDecimal(den) 383 if err != nil { 384 return nil, pgerror.Wrapf(err, pgcode.Syntax, 385 "could not evaluate denominator %v as Datum type DDecimal from string %q", 386 expr, den) 387 } 388 if cond, err := DecimalCtx.Quo(&dd.Decimal, &dd.Decimal, &denDec.Decimal); err != nil { 389 if cond.DivisionByZero() { 390 return nil, ErrDivByZero 391 } 392 return nil, err 393 } 394 } else { 395 if err := dd.SetString(s); err != nil { 396 return nil, pgerror.Wrapf(err, pgcode.Syntax, 397 "could not evaluate %v as Datum type DDecimal from string %q", expr, s) 398 } 399 } 400 if !dd.IsZero() { 401 // Negative zero does not exist for DECIMAL, in that case we 402 // ignore the sign. Otherwise XOR the signs of the expr and the 403 // decimal value contained in the expr, since the negative may 404 // have been folded into the inner decimal. 405 dd.Negative = dd.Negative != expr.negative 406 } 407 expr.resAsDecimal = true 408 } 409 return dd, nil 410 case types.OidFamily: 411 d, err := expr.ResolveAsType(ctx, semaCtx, types.Int) 412 if err != nil { 413 return nil, err 414 } 415 dInt := MustBeDInt(d) 416 return IntToOid(dInt) 417 default: 418 return nil, errors.AssertionFailedf("could not resolve %T %v into a %s", expr, expr, typ.SQLStringForError()) 419 } 420 } 421 422 // intersectTypeSlices returns a slice of all the types that are in both of the 423 // input slices that have the same OID. 424 func intersectTypeSlices(xs, ys []*types.T) (out []*types.T) { 425 seen := make(map[oid.Oid]struct{}) 426 for _, x := range xs { 427 for _, y := range ys { 428 _, ok := seen[x.Oid()] 429 if x.Oid() == y.Oid() && !ok { 430 out = append(out, x) 431 } 432 } 433 seen[x.Oid()] = struct{}{} 434 } 435 return out 436 } 437 438 // commonConstantType returns the most constrained type which is mutually 439 // resolvable between a set of provided constants. 440 // 441 // The function takes a slice of Exprs and indexes, but expects all the indexed 442 // Exprs to wrap a Constant. The reason it does no take a slice of Constants 443 // instead is to avoid forcing callers to allocate separate slices of Constant. 444 func commonConstantType(vals []Expr, idxs intsets.Fast) (*types.T, bool) { 445 var candidates []*types.T 446 447 for i, ok := idxs.Next(0); ok; i, ok = idxs.Next(i + 1) { 448 availableTypes := vals[i].(Constant).DesirableTypes() 449 if candidates == nil { 450 candidates = availableTypes 451 } else { 452 candidates = intersectTypeSlices(candidates, availableTypes) 453 } 454 } 455 456 if len(candidates) > 0 { 457 return candidates[0], true 458 } 459 return nil, false 460 } 461 462 // StrVal represents a constant string value. 463 type StrVal struct { 464 // We could embed a constant.Value here (like NumVal) and use the stringVal implementation, 465 // but that would have extra overhead without much of a benefit. However, it would make 466 // constant folding (below) a little more straightforward. 467 s string 468 469 // scannedAsBytes is true iff the input syntax was using b'...' or 470 // x'....'. If false, the string is guaranteed to be a valid UTF-8 471 // sequence. 472 scannedAsBytes bool 473 474 // The following fields are used to avoid allocating Datums on type resolution. 475 resString DString 476 resBytes DBytes 477 } 478 479 // NewStrVal constructs a StrVal instance. This is used during 480 // parsing when interpreting a token of type SCONST, i.e. *not* using 481 // the b'...' or x'...' syntax. 482 func NewStrVal(s string) *StrVal { 483 return &StrVal{s: s} 484 } 485 486 // NewBytesStrVal constructs a StrVal instance suitable as byte array. 487 // This is used during parsing when interpreting a token of type BCONST, 488 // i.e. using the b'...' or x'...' syntax. 489 func NewBytesStrVal(s string) *StrVal { 490 return &StrVal{s: s, scannedAsBytes: true} 491 } 492 493 // RawString retrieves the underlying string of the StrVal. 494 func (expr *StrVal) RawString() string { 495 return expr.s 496 } 497 498 // Format implements the NodeFormatter interface. 499 func (expr *StrVal) Format(ctx *FmtCtx) { 500 buf, f := &ctx.Buffer, ctx.flags 501 if expr.scannedAsBytes { 502 lexbase.EncodeSQLBytes(buf, expr.s) 503 } else { 504 lexbase.EncodeSQLStringWithFlags(buf, expr.s, f.EncodeFlags()) 505 } 506 } 507 508 var ( 509 // StrValAvailAllParsable is the set of parsable string types. 510 StrValAvailAllParsable = []*types.T{ 511 // Note: String is deliberately first, to make sure that "string" is the 512 // default type that raw strings get parsed into, without any casts or type 513 // assertions. 514 types.String, 515 types.Bytes, 516 types.Bool, 517 types.Int, 518 types.Float, 519 types.Decimal, 520 types.Date, 521 types.StringArray, 522 types.BytesArray, 523 types.IntArray, 524 types.FloatArray, 525 types.DecimalArray, 526 types.BoolArray, 527 types.Box2D, 528 types.Geography, 529 types.Geometry, 530 types.Time, 531 types.TimeTZ, 532 types.Timestamp, 533 types.TimestampTZ, 534 types.Interval, 535 types.Uuid, 536 types.DateArray, 537 types.TimeArray, 538 types.TimeTZArray, 539 types.TimestampArray, 540 types.TimestampTZArray, 541 types.IntervalArray, 542 types.UUIDArray, 543 types.INet, 544 types.Jsonb, 545 types.PGLSN, 546 types.PGLSNArray, 547 types.RefCursor, 548 types.RefCursorArray, 549 types.TSQuery, 550 types.TSVector, 551 types.VarBit, 552 types.AnyEnum, 553 types.AnyEnumArray, 554 types.INetArray, 555 types.VarBitArray, 556 types.AnyTuple, 557 types.AnyTupleArray, 558 } 559 // StrValAvailBytes is the set of types convertible to byte array. 560 StrValAvailBytes = []*types.T{types.Bytes, types.Uuid, types.String, types.AnyEnum} 561 ) 562 563 // AvailableTypes implements the Constant interface. 564 // 565 // To fully take advantage of literal type inference, this method would 566 // determine exactly which types are available for a given string. This would 567 // entail attempting to parse the literal string as a date, a timestamp, an 568 // interval, etc. and having more fine-grained results than StrValAvailAllParsable. 569 // However, this is not feasible in practice because of the associated parsing 570 // overhead. 571 // 572 // Conservative approaches like checking the string's length have been investigated 573 // to reduce ambiguity and improve type inference in some cases. When doing so, the 574 // length of the string literal was compared against all valid date and timestamp 575 // formats to quickly gain limited insight into whether parsing the string as the 576 // respective datum types could succeed. The hope was to eliminate impossibilities 577 // and constrain the returned type sets as much as possible. Unfortunately, two issues 578 // were found with this approach: 579 // - date and timestamp formats do not always imply a fixed-length valid input. For 580 // instance, timestamp formats that take fractional seconds can successfully parse 581 // inputs of varied length. 582 // - the set of date and timestamp formats are not disjoint, which means that ambiguity 583 // can not be eliminated when inferring the type of string literals that use these 584 // shared formats. 585 // 586 // While these limitations still permitted improved type inference in many cases, they 587 // resulted in behavior that was ultimately incomplete, resulted in unpredictable levels 588 // of inference, and occasionally failed to eliminate ambiguity. Further heuristics could 589 // have been applied to improve the accuracy of the inference, like checking that all 590 // or some characters were digits, but it would not have circumvented the fundamental 591 // issues here. Fully parsing the literal into each type would be the only way to 592 // concretely avoid the issue of unpredictable inference behavior. 593 func (expr *StrVal) AvailableTypes() []*types.T { 594 if expr.scannedAsBytes { 595 return StrValAvailBytes 596 } 597 return StrValAvailAllParsable 598 } 599 600 // DesirableTypes implements the Constant interface. 601 func (expr *StrVal) DesirableTypes() []*types.T { 602 return expr.AvailableTypes() 603 } 604 605 // ResolveAsType implements the Constant interface. 606 func (expr *StrVal) ResolveAsType( 607 ctx context.Context, semaCtx *SemaContext, typ *types.T, 608 ) (TypedExpr, error) { 609 if expr.scannedAsBytes { 610 // We're looking at typing a byte literal constant into some value type. 611 switch typ.Family() { 612 case types.BytesFamily: 613 expr.resBytes = DBytes(expr.s) 614 return &expr.resBytes, nil 615 case types.EnumFamily: 616 e, err := MakeDEnumFromPhysicalRepresentation(typ, []byte(expr.s)) 617 if err != nil { 618 return nil, err 619 } 620 return NewDEnum(e), nil 621 case types.UuidFamily: 622 return ParseDUuidFromBytes([]byte(expr.s)) 623 case types.StringFamily: 624 expr.resString = DString(expr.s) 625 return &expr.resString, nil 626 } 627 return nil, errors.AssertionFailedf("attempt to type byte array literal to %s", typ.SQLStringForError()) 628 } 629 630 // Typing a string literal constant into some value type. 631 switch typ.Family() { 632 case types.StringFamily: 633 if typ.Oid() == oid.T_name { 634 expr.resString = DString(expr.s) 635 return NewDNameFromDString(&expr.resString), nil 636 } 637 expr.resString = DString(expr.s) 638 return &expr.resString, nil 639 640 case types.BytesFamily: 641 return ParseDByte(expr.s) 642 643 default: 644 ptCtx := &simpleParseContext{ 645 // We can return any time, but not the zero value - it causes an error when 646 // parsing "yesterday". 647 RelativeParseTime: time.Date(2000, time.January, 2, 3, 4, 5, 0, time.UTC), 648 } 649 if semaCtx != nil { 650 ptCtx.DateStyle = semaCtx.DateStyle 651 ptCtx.IntervalStyle = semaCtx.IntervalStyle 652 } 653 if typ.UserDefined() && !typ.IsHydrated() { 654 var err error 655 if semaCtx == nil || semaCtx.TypeResolver == nil { 656 return nil, errors.AssertionFailedf("unable to hydrate type for resolution") 657 } 658 typ, err = semaCtx.TypeResolver.ResolveTypeByOID(ctx, typ.Oid()) 659 if err != nil { 660 return nil, err 661 } 662 } 663 val, dependsOnContext, err := ParseAndRequireString(typ, expr.s, ptCtx) 664 if err != nil { 665 return nil, err 666 } 667 if !dependsOnContext { 668 return val, nil 669 } 670 // Interpreting a string as one of these types may depend on the timezone or 671 // the current time; the value won't be safe to reuse later. So in this case 672 // we return a CastExpr and let the conversion happen at evaluation time. We 673 // still want to error out if the conversion is not possible though (this is 674 // used when resolving overloads). 675 expr.resString = DString(expr.s) 676 c := NewTypedCastExpr(&expr.resString, typ) 677 return c.TypeCheck(ctx, semaCtx, typ) 678 } 679 }