Check switches on syntax.Expr for exhaustiveness. (#11113)

**What this PR does / why we need it**:
In preparation to serlialize the LogQL AST as JSON we are declaring the
`syntax.Expr` as a "sum type" and test all switch statements on it to be
exhaustive.

**Special notes for your reviewer**:

**Checklist**
- [ ] Reviewed the
[`CONTRIBUTING.md`](https://github.com/grafana/loki/blob/main/CONTRIBUTING.md)
guide (**required**)
- [ ] Documentation added
- [ ] Tests updated
- [ ] `CHANGELOG.md` updated
- [ ] If the change is worth mentioning in the release notes, add
`add-to-release-notes` label
- [ ] Changes that require user attention or interaction to upgrade are
documented in `docs/sources/setup/upgrade/_index.md`
- [ ] For Helm chart changes bump the Helm chart version in
`production/helm/loki/Chart.yaml` and update
`production/helm/loki/CHANGELOG.md` and
`production/helm/loki/README.md`. [Example
PR](d10549e3ec)
- [ ] If the change is deprecating or removing a configuration option,
update the `deprecated-config.yaml` and `deleted-config.yaml` files
respectively in the `tools/deprecated-config-checker` directory.
[Example
PR](0d4416a4b0)
pull/10829/head
Karsten Jeschkies 2 years ago committed by GitHub
parent 4ed3b117d2
commit 1c56aa91ef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      .golangci.yml
  2. 2
      pkg/logql/engine.go
  3. 2
      pkg/logql/evaluator.go
  4. 4
      pkg/logql/optimize.go
  5. 8
      pkg/logql/rangemapper.go
  6. 6
      pkg/logql/syntax/ast.go
  7. 2
      pkg/logql/syntax/walk.go
  8. 4
      pkg/logql/syntax/walk_test.go
  9. 2
      pkg/querier/multi_tenant_querier.go
  10. 2
      pkg/querier/queryrange/split_by_interval.go

@ -79,6 +79,7 @@ linters:
- goimports
- gosimple
- staticcheck
- gochecksumtype
disable:
- unused
- unparam

@ -430,7 +430,7 @@ func (q *query) evalSample(ctx context.Context, expr syntax.SampleExpr) (promql_
func (q *query) checkIntervalLimit(expr syntax.SampleExpr, limit time.Duration) error {
var err error
expr.Walk(func(e interface{}) {
expr.Walk(func(e syntax.Expr) {
switch e := e.(type) {
case *syntax.RangeAggregationExpr:
if e.Left == nil || e.Left.Interval <= limit {

@ -112,7 +112,7 @@ func Sortable(q Params) (bool, error) {
if err != nil {
return false, err
}
expr.Walk(func(e interface{}) {
expr.Walk(func(e syntax.Expr) {
rangeExpr, ok := e.(*syntax.VectorAggregationExpr)
if !ok {
return

@ -6,7 +6,7 @@ import "github.com/grafana/loki/pkg/logql/syntax"
func optimizeSampleExpr(expr syntax.SampleExpr) (syntax.SampleExpr, error) {
var skip bool
// we skip sharding AST for now, it's not easy to clone them since they are not part of the language.
expr.Walk(func(e interface{}) {
expr.Walk(func(e syntax.Expr) {
switch e.(type) {
case *ConcatSampleExpr, *DownstreamSampleExpr:
skip = true
@ -28,7 +28,7 @@ func optimizeSampleExpr(expr syntax.SampleExpr) (syntax.SampleExpr, error) {
// removeLineformat removes unnecessary line_format within a SampleExpr.
func removeLineformat(expr syntax.SampleExpr) {
expr.Walk(func(e interface{}) {
expr.Walk(func(e syntax.Expr) {
rangeExpr, ok := e.(*syntax.RangeAggregationExpr)
if !ok {
return

@ -177,7 +177,7 @@ func (m RangeMapper) Map(expr syntax.SampleExpr, vectorAggrPushdown *syntax.Vect
// Example: expression `count_over_time({app="foo"}[10m])` returns 10m
func getRangeInterval(expr syntax.SampleExpr) time.Duration {
var rangeInterval time.Duration
expr.Walk(func(e interface{}) {
expr.Walk(func(e syntax.Expr) {
switch concrete := e.(type) {
case *syntax.RangeAggregationExpr:
rangeInterval = concrete.Left.Interval
@ -190,7 +190,7 @@ func getRangeInterval(expr syntax.SampleExpr) time.Duration {
// such as `| json` or `| logfmt`, that would result in an exploding amount of series in downstream queries.
func hasLabelExtractionStage(expr syntax.SampleExpr) bool {
found := false
expr.Walk(func(e interface{}) {
expr.Walk(func(e syntax.Expr) {
switch concrete := e.(type) {
case *syntax.LogfmtParserExpr:
found = true
@ -278,7 +278,7 @@ func (m RangeMapper) vectorAggrWithRangeDownstreams(expr *syntax.RangeAggregatio
// Returns the updated downstream ConcatSampleExpr.
func appendDownstream(downstreams *ConcatSampleExpr, expr syntax.SampleExpr, interval time.Duration, offset time.Duration) *ConcatSampleExpr {
sampleExpr := clone(expr)
sampleExpr.Walk(func(e interface{}) {
sampleExpr.Walk(func(e syntax.Expr) {
switch concrete := e.(type) {
case *syntax.RangeAggregationExpr:
concrete.Left.Interval = interval
@ -300,7 +300,7 @@ func getOffsets(expr syntax.SampleExpr) []time.Duration {
// Expect to always find at most 1 offset, so preallocate it accordingly
offsets := make([]time.Duration, 0, 1)
expr.Walk(func(e interface{}) {
expr.Walk(func(e syntax.Expr) {
switch concrete := e.(type) {
case *syntax.RangeAggregationExpr:
offsets = append(offsets, concrete.Left.Offset)

@ -22,6 +22,8 @@ import (
)
// Expr is the root expression which can be a SampleExpr or LogSelectorExpr
//
//sumtype:decl
type Expr interface {
logQLExpr() // ensure it's not implemented accidentally
Shardable() bool // A recursive check on the AST to see if it's shardable.
@ -2106,7 +2108,7 @@ func (e *VectorExpr) MatcherGroups() ([]MatcherRange, error) { return nil, e.er
func (e *VectorExpr) Extractor() (log.SampleExtractor, error) { return nil, nil }
func ReducesLabels(e Expr) (conflict bool) {
e.Walk(func(e interface{}) {
e.Walk(func(e Expr) {
switch expr := e.(type) {
case *RangeAggregationExpr:
if groupingReducesLabels(expr.Grouping) {
@ -2135,6 +2137,8 @@ func ReducesLabels(e Expr) (conflict bool) {
break
}
}
default:
return
}
})
return

@ -1,6 +1,6 @@
package syntax
type WalkFn = func(e interface{})
type WalkFn = func(e Expr)
func walkAll(f WalkFn, xs ...Walkable) {
for _, x := range xs {

@ -32,7 +32,7 @@ func Test_Walkable(t *testing.T) {
require.Nil(t, err)
var cnt int
expr.Walk(func(_ interface{}) { cnt++ })
expr.Walk(func(_ Expr) { cnt++ })
require.Equal(t, test.want, cnt)
})
}
@ -77,7 +77,7 @@ func Test_AppendMatchers(t *testing.T) {
expr, err := ParseExpr(test.expr)
require.NoError(t, err)
expr.Walk(func(e interface{}) {
expr.Walk(func(e Expr) {
switch me := e.(type) {
case *MatchersExpr:
me.AppendMatchers(test.matchers)

@ -227,7 +227,7 @@ func removeTenantSelector(params logql.SelectSampleParams, tenantIDs []string) (
// replaceMatchers traverses the passed expression and replaces all matchers.
func replaceMatchers(expr syntax.Expr, matchers []*labels.Matcher) syntax.Expr {
expr, _ = syntax.Clone(expr)
expr.Walk(func(e interface{}) {
expr.Walk(func(e syntax.Expr) {
switch concrete := e.(type) {
case *syntax.MatchersExpr:
concrete.Mts = matchers

@ -322,7 +322,7 @@ func maxRangeVectorAndOffsetDuration(q string) (time.Duration, time.Duration, er
}
var maxRVDuration, maxOffset time.Duration
expr.Walk(func(e interface{}) {
expr.Walk(func(e syntax.Expr) {
if r, ok := e.(*syntax.LogRange); ok {
if r.Interval > maxRVDuration {
maxRVDuration = r.Interval

Loading…
Cancel
Save