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