Skip to content

Commit df90bcb

Browse files
committed
fix bug with type checking case/cond branches
This commit fixes a type checking problem where the type checker was too aggresive in checking all branches of conditional expressions. Instead, we require that just one branch is clean. If all the branches have errors, then we report the errors and the query fails to compile. We will later at a strict-mode of type checking that requires type assertions when needed and all the branches must pass similar to the relational model. Fixes #6563
1 parent 6f4f1a6 commit df90bcb

File tree

3 files changed

+87
-1
lines changed

3 files changed

+87
-1
lines changed

compiler/semantic/expr.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,31 @@ func (t *translator) expr(e ast.Expr, inType super.Type) (sem.Expr, super.Type)
7171
case *ast.CaseExpr:
7272
return t.semCaseExpr(e, inType)
7373
case *ast.CondExpr:
74+
var errlocs [][]errloc
7475
cond, condType := t.expr(e.Cond, inType)
76+
t.checker.boolean(e.Cond, condType)
77+
t.checker.pushErrs()
7578
thenExpr, thenType := t.expr(e.Then, inType)
79+
if errs := t.checker.popErrs(); len(errs) != 0 {
80+
errlocs = append(errlocs, errs)
81+
}
7682
var elseExpr sem.Expr
7783
var elseType super.Type
7884
if e.Else != nil {
85+
t.checker.pushErrs()
7986
elseExpr, elseType = t.expr(e.Else, inType)
87+
if errs := t.checker.popErrs(); len(errs) != 0 {
88+
errlocs = append(errlocs, errs)
89+
}
8090
} else {
8191
elseExpr = sem.NewStringError(e, "missing")
8292
elseType = t.checker.unknown
8393
}
84-
t.checker.boolean(e.Cond, condType)
94+
if len(errlocs) == 2 {
95+
for _, errs := range errlocs {
96+
t.checker.keepErrs(errs)
97+
}
98+
}
8599
return &sem.CondExpr{
86100
Node: e,
87101
Cond: cond,
@@ -664,6 +678,7 @@ func (t *translator) semCaseExpr(c *ast.CaseExpr, inType super.Type) (sem.Expr,
664678
elseType = t.checker.unknown
665679
}
666680
types := []super.Type{elseType}
681+
var thenErrs [][]errloc
667682
for _, when := range slices.Backward(c.Whens) {
668683
cond, condType := t.expr(when.Cond, inType)
669684
if e != nil {
@@ -672,15 +687,27 @@ func (t *translator) semCaseExpr(c *ast.CaseExpr, inType super.Type) (sem.Expr,
672687
} else {
673688
t.checker.boolean(when.Cond, condType)
674689
}
690+
t.checker.pushErrs()
675691
then, thenType := t.expr(when.Then, inType)
676692
out = &sem.CondExpr{
677693
Node: c,
678694
Cond: cond,
679695
Then: then,
680696
Else: out,
681697
}
698+
if errs := t.checker.popErrs(); len(errs) != 0 {
699+
thenErrs = append(thenErrs, errs)
700+
}
682701
types = append(types, thenType)
683702
}
703+
if len(thenErrs) == len(c.Whens) {
704+
// All the paths have errors so report them.
705+
// If at least one path is ok, then we deem the overall expression valid
706+
// an do not report any errors.
707+
for _, errs := range thenErrs {
708+
t.checker.keepErrs(errs)
709+
}
710+
}
684711
return out, t.checker.fuse(types)
685712
}
686713

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
script: |
2+
super -s -I walk.spq in.sup
3+
! super -s -I fail.spq in.sup
4+
5+
inputs:
6+
- name: walk.spq
7+
data: |
8+
fn walk(node, visit):
9+
case kind(node)
10+
when "array" then
11+
[unnest node | walk(this, visit)]
12+
when "record" then
13+
unflatten([unnest flatten(node) | {key,value:walk(value, visit)}])
14+
when "union" then
15+
walk(under(node), visit)
16+
else visit(node)
17+
end
18+
fn addOne(node): case typeof(node) when <int64> then node+1 else node end
19+
values walk(this, &addOne)
20+
- name: fail.spq
21+
data: |
22+
values
23+
case typeof(this)
24+
when <string> then this+1
25+
else this+2
26+
end
27+
- name: in.sup
28+
data: |
29+
{n:1}
30+
31+
outputs:
32+
- name: stdout
33+
data: |
34+
{n:2}
35+
- name: stderr
36+
data: |
37+
type mismatch: {n:int64} + int64 in fail.spq at line 4, column 8:
38+
else this+2
39+
~~~~~~
40+
type mismatch: {n:int64} + int64 in fail.spq at line 3, column 22:
41+
when <string> then this+1
42+
~~~~~~
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
script: |
2+
! super -s -c "values has(n) ? this+1 : this+2" in.sup
3+
4+
inputs:
5+
- name: in.sup
6+
data: |
7+
{n:1}
8+
9+
outputs:
10+
- name: stderr
11+
data: |
12+
type mismatch: {n:int64} + int64 at line 1, column 17:
13+
values has(n) ? this+1 : this+2
14+
~~~~~~
15+
type mismatch: {n:int64} + int64 at line 1, column 26:
16+
values has(n) ? this+1 : this+2
17+
~~~~~~

0 commit comments

Comments
 (0)