lang: unification: Fix panic in struct/func cmp of partials

This was discovered by user aequitas. I modified his patch slightly, and
added some comments and a test.
This commit is contained in:
James Shubin
2018-02-27 16:39:10 -05:00
parent df1e50e599
commit ff69a82b57
2 changed files with 45 additions and 0 deletions

View File

@@ -154,6 +154,7 @@ func SimpleInvariantSolver(invariants []interfaces.Invariant, logf func(format s
if typ, exists := solved[eq.Expr1]; exists { if typ, exists := solved[eq.Expr1]; exists {
// wow, now known, so tell the partials! // wow, now known, so tell the partials!
// TODO: this assumes typ is a list, is that guaranteed?
listPartials[eq.Expr1][eq.Expr2Val] = typ.Val listPartials[eq.Expr1][eq.Expr2Val] = typ.Val
} }
@@ -211,6 +212,7 @@ func SimpleInvariantSolver(invariants []interfaces.Invariant, logf func(format s
if typ, exists := solved[eq.Expr1]; exists { if typ, exists := solved[eq.Expr1]; exists {
// wow, now known, so tell the partials! // wow, now known, so tell the partials!
// TODO: this assumes typ is a map, is that guaranteed?
mapPartials[eq.Expr1][eq.Expr2Key] = typ.Key mapPartials[eq.Expr1][eq.Expr2Key] = typ.Key
mapPartials[eq.Expr1][eq.Expr2Val] = typ.Val mapPartials[eq.Expr1][eq.Expr2Val] = typ.Val
} }
@@ -281,6 +283,10 @@ func SimpleInvariantSolver(invariants []interfaces.Invariant, logf func(format s
if typ, exists := solved[eq.Expr1]; exists { if typ, exists := solved[eq.Expr1]; exists {
// wow, now known, so tell the partials! // wow, now known, so tell the partials!
// TODO: this assumes typ is a struct, is that guaranteed?
if len(typ.Ord) != len(eq.Expr2Ord) {
return nil, fmt.Errorf("struct field count differs")
}
for i, name := range eq.Expr2Ord { for i, name := range eq.Expr2Ord {
expr := eq.Expr2Map[name] // assume key exists expr := eq.Expr2Map[name] // assume key exists
structPartials[eq.Expr1][expr] = typ.Map[typ.Ord[i]] // assume key exists structPartials[eq.Expr1][expr] = typ.Map[typ.Ord[i]] // assume key exists
@@ -351,6 +357,10 @@ func SimpleInvariantSolver(invariants []interfaces.Invariant, logf func(format s
if typ, exists := solved[eq.Expr1]; exists { if typ, exists := solved[eq.Expr1]; exists {
// wow, now known, so tell the partials! // wow, now known, so tell the partials!
// TODO: this assumes typ is a func, is that guaranteed?
if len(typ.Ord) != len(eq.Expr2Ord) {
return nil, fmt.Errorf("func arg count differs")
}
for i, name := range eq.Expr2Ord { for i, name := range eq.Expr2Ord {
expr := eq.Expr2Map[name] // assume key exists expr := eq.Expr2Map[name] // assume key exists
funcPartials[eq.Expr1][expr] = typ.Map[typ.Ord[i]] // assume key exists funcPartials[eq.Expr1][expr] = typ.Map[typ.Ord[i]] // assume key exists

View File

@@ -473,6 +473,41 @@ func TestUnification1(t *testing.T) {
fail: true, fail: true,
}) })
} }
{
//test "t1" {
// stringptr => getenv("GOPATH", "bug"), # bad (two args vs. one)
//}
expr := &ExprCall{
Name: "getenv",
Args: []interfaces.Expr{
&ExprStr{
V: "GOPATH",
},
&ExprStr{
V: "bug",
},
},
}
stmt := &StmtProg{
Prog: []interfaces.Stmt{
&StmtRes{
Kind: "test",
Name: &ExprStr{V: "t1"},
Fields: []*StmtResField{
{
Field: "stringptr",
Value: expr,
},
},
},
},
}
values = append(values, test{
name: "function, wrong arg count",
ast: stmt,
fail: true,
})
}
for index, test := range values { // run all the tests for index, test := range values { // run all the tests
t.Run(fmt.Sprintf("test #%d (%s)", index, test.name), func(t *testing.T) { t.Run(fmt.Sprintf("test #%d (%s)", index, test.name), func(t *testing.T) {