diff --git a/compiler/kernel/expr.go b/compiler/kernel/expr.go index 7acf7e28cb..80d5dae6d4 100644 --- a/compiler/kernel/expr.go +++ b/compiler/kernel/expr.go @@ -13,7 +13,6 @@ import ( "github.com/brimdata/zed/runtime/op/traverse" "github.com/brimdata/zed/zbuf" "github.com/brimdata/zed/zson" - "golang.org/x/exp/slices" "golang.org/x/text/unicode/norm" ) @@ -398,9 +397,6 @@ func (b *Builder) compileRecordExpr(record *dag.RecordExpr) (expr.Evaluator, err for _, elem := range record.Elems { switch elem := elem.(type) { case *dag.Field: - if slices.ContainsFunc(elems, func(r expr.RecordElem) bool { return r.Name == elem.Name }) { - return nil, fmt.Errorf("record expression: %w", &zed.DuplicateFieldError{Name: elem.Name}) - } e, err := b.compileExpr(elem.Value) if err != nil { return nil, err diff --git a/compiler/semantic/expr.go b/compiler/semantic/expr.go index fd9ea551f0..68c21341eb 100644 --- a/compiler/semantic/expr.go +++ b/compiler/semantic/expr.go @@ -155,10 +155,15 @@ func (a *analyzer) semExpr(e ast.Expr) (dag.Expr, error) { Where: where, }, nil case *ast.RecordExpr: + fields := map[string]struct{}{} var out []dag.RecordElem for _, elem := range e.Elems { switch elem := elem.(type) { case *ast.Field: + if _, ok := fields[elem.Name]; ok { + return nil, fmt.Errorf("record expression: %w", &zed.DuplicateFieldError{Name: elem.Name}) + } + fields[elem.Name] = struct{}{} e, err := a.semExpr(elem.Value) if err != nil { return nil, err @@ -169,6 +174,10 @@ func (a *analyzer) semExpr(e ast.Expr) (dag.Expr, error) { Value: e, }) case *ast.ID: + if _, ok := fields[elem.Name]; ok { + return nil, fmt.Errorf("record expression: %w", &zed.DuplicateFieldError{Name: elem.Name}) + } + fields[elem.Name] = struct{}{} v, err := a.semID(elem) if err != nil { return nil, err