Repository: openllb/hlb
Pull request #297 (2022-02-11 20:53:10)

Check references on nested call expr
- Broken from #290
- Added test to catch future regressions


Patch:
diff --git a/checker/checker.go b/checker/checker.go
index 1aace19..483cbc6 100644
--- a/checker/checker.go
+++ b/checker/checker.go
@@ -273,6 +273,18 @@ func (c *checker) CheckReferences(mod *ast.Module, name string) error {
 				c.err(err)
 			}
 		},
+		func(block *ast.BlockStmt, callStmt *ast.CallStmt, callExpr *ast.CallExpr) {
+			err := c.checkNestedCallExpr(block.Scope, callStmt.Name, callStmt.Args, callStmt.Signature, callStmt.WithClause, callExpr, name)
+			if err != nil {
+				c.err(err)
+			}
+		},
+		func(block *ast.BlockStmt, parentCallExpr, callExpr *ast.CallExpr) {
+			err := c.checkNestedCallExpr(block.Scope, parentCallExpr.Name, parentCallExpr.Args(), parentCallExpr.Signature, nil, callExpr, name)
+			if err != nil {
+				c.err(err)
+			}
+		},
 	)
 	c.checkBinds(mod)
 	if len(c.errs) > 0 {
@@ -281,6 +293,35 @@ func (c *checker) CheckReferences(mod *ast.Module, name string) error {
 	return nil
 }
 
+func (c *checker) checkNestedCallExpr(scope *ast.Scope, ie *ast.IdentExpr, args []*ast.Expr, signature []ast.Kind, with *ast.WithClause, call *ast.CallExpr, name string) error {
+	if call.Name.Ident.Text != name {
+		return nil
+	}
+	if len(args) != len(signature) {
+		return errdefs.WithInternalErrorf(call, "expected %d args but got %d", len(signature), len(args))
+	}
+
+	index := -1
+	for i, arg := range args {
+		if arg.CallExpr == call {
+			index = i
+			break
+		}
+	}
+
+	var kset *ast.KindSet
+	if index < 0 {
+		// If its not within args, check with clause.
+		if with == nil || with.Expr == nil || with.Expr.CallExpr != call || ie.Reference != nil {
+			return errdefs.WithInternalErrorf(call, "expected to find %q in %q", call.Name, args)
+		}
+		kset = ast.NewKindSet(ast.Kind("option::" + ie.Ident.Text))
+	} else {
+		kset = ast.NewKindSet(signature[index])
+	}
+	return c.checkCallExpr(scope, kset, call)
+}
+
 func (c *checker) err(err error) {
 	c.errs = append(c.errs, err)
 }


Test patch:
diff --git a/codegen/codegen_test.go b/codegen/codegen_test.go
index 2927c4c..23efd79 100644
--- a/codegen/codegen_test.go
+++ b/codegen/codegen_test.go
@@ -1159,7 +1159,11 @@ func TestCodeGenImport(t *testing.T) {
 		`
 		import other from "./other.hlb"
 
-		fs default(string bar) {
+		fs default() {
+			baz "hello"
+		}
+
+		fs baz(string bar) {
 			other.foo bar
 		}
 		`,
@@ -1171,12 +1175,31 @@ func TestCodeGenImport(t *testing.T) {
 			`,
 		}},
 		nil,
+	}, {
+		"able to use imported function in arg",
+		`
+		import other from "./other.hlb"
+
+		fs default() {
+			image other.foo("alpine")
+		}
+		`,
+		[]testImport{{
+			"other.hlb",
+			`
+			export foo
+			string foo(string name) {
+				name
+			}
+			`,
+		}},
+		nil,
 	}, {
 		"able to use imported option",
 		`
 		import other from "./other.hlb"
 
-		fs default(string bar) {
+		fs default() {
 			image "busybox" with other.foo
 		}
 		`,
@@ -1193,7 +1216,7 @@ func TestCodeGenImport(t *testing.T) {
 		`
 		import other from "./other.hlb"
 
-		fs default(string bar) {
+		fs default() {
 			image "busybox" with option {
 				other.foo
 			}
@@ -1278,11 +1301,18 @@ func TestCodeGenImport(t *testing.T) {
 				}
 			}
 
-			var expected error
 			if tc.fn != nil {
-				expected = tc.fn(mod)
+				expected := tc.fn(mod)
+				validateError(t, ctx, expected, actual, tc.name)
+			} else {
+				cg, err := codegen.New(nil, nil)
+				require.NoError(t, err, tc.name)
+
+				ctx = codegen.WithSessionID(ctx, identity.NewID())
+				targets := []codegen.Target{{Name: "default"}}
+				_, err = cg.Generate(ctx, mod, targets)
+				validateError(t, ctx, nil, err, tc.name)
 			}
-			validateError(t, ctx, expected, actual, tc.name)
 		})
 	}
 }