Recognize some unsupported functions

Some functions are called without the use of $(call),
since $(call) is not necessary when the function doesn't
take any arguments. mk2rbc thinks these function calls
are local variables, and converts them as such. This
leads to undefined variable errors when trying to load
(before even executing) the starlark file.

Hardcode a known function that should not be converted
to a local variable.

Bug: 226974242
Test: go test
Change-Id: I5567a34fcc282b181a7e78ac3d5cc9b40bd025a2
diff --git a/mk2rbc/expr.go b/mk2rbc/expr.go
index 9266520..6a6eb46 100644
--- a/mk2rbc/expr.go
+++ b/mk2rbc/expr.go
@@ -741,8 +741,8 @@
 	return starlarkTypeUnknown
 }
 
-func (_ *badExpr) emitListVarCopy(_ *generationContext) {
-	panic("implement me")
+func (b *badExpr) emitListVarCopy(gctx *generationContext) {
+	b.emit(gctx)
 }
 
 func (b *badExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 8f4fea4..073c2ed 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -130,6 +130,14 @@
 	"foreach":                   &foreachCallNodeParser{},
 }
 
+// These look like variables, but are actually functions, and would give
+// undefined variable errors if we converted them as variables. Instead,
+// emit an error instead of converting them.
+var unsupportedFunctions = map[string]bool{
+	"local-generated-sources-dir": true,
+	"local-intermediates-dir":     true,
+}
+
 // These are functions that we don't implement conversions for, but
 // we allow seeing their definitions in the product config files.
 var ignoredDefines = map[string]bool{
@@ -556,9 +564,6 @@
 	if lhs.valueType() == starlarkTypeUnknown {
 		// Try to divine variable type from the RHS
 		asgn.value = ctx.parseMakeString(a, a.Value)
-		if xBad, ok := asgn.value.(*badExpr); ok {
-			return []starlarkNode{&exprNode{xBad}}
-		}
 		inferred_type := asgn.value.typ()
 		if inferred_type != starlarkTypeUnknown {
 			lhs.setValueType(inferred_type)
@@ -567,21 +572,19 @@
 	if lhs.valueType() == starlarkTypeList {
 		xConcat, xBad := ctx.buildConcatExpr(a)
 		if xBad != nil {
-			return []starlarkNode{&exprNode{expr: xBad}}
-		}
-		switch len(xConcat.items) {
-		case 0:
-			asgn.value = &listExpr{}
-		case 1:
-			asgn.value = xConcat.items[0]
-		default:
-			asgn.value = xConcat
+			asgn.value = xBad
+		} else {
+			switch len(xConcat.items) {
+			case 0:
+				asgn.value = &listExpr{}
+			case 1:
+				asgn.value = xConcat.items[0]
+			default:
+				asgn.value = xConcat
+			}
 		}
 	} else {
 		asgn.value = ctx.parseMakeString(a, a.Value)
-		if xBad, ok := asgn.value.(*badExpr); ok {
-			return []starlarkNode{&exprNode{expr: xBad}}
-		}
 	}
 
 	if asgn.lhs.valueType() == starlarkTypeString &&
@@ -1262,6 +1265,12 @@
 		return ctx.newBadExpr(node, "reference is too complex: %s", refDump)
 	}
 
+	if name, _, ok := ctx.maybeParseFunctionCall(node, ref); ok {
+		if _, unsupported := unsupportedFunctions[name]; unsupported {
+			return ctx.newBadExpr(node, "%s is not supported", refDump)
+		}
+	}
+
 	// If it is a single word, it can be a simple variable
 	// reference or a function call
 	if len(words) == 1 && !isMakeControlFunc(refDump) && refDump != "shell" && refDump != "eval" {
@@ -1309,9 +1318,8 @@
 		} else {
 			return ctx.newBadExpr(node, "cannot handle invoking %s", name)
 		}
-	} else {
-		return ctx.newBadExpr(node, "cannot handle %s", refDump)
 	}
+	return ctx.newBadExpr(node, "cannot handle %s", refDump)
 }
 
 type simpleCallParser struct {
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index de75129..e851278 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -117,8 +117,8 @@
 
 def init(g, handle):
   cfg = rblf.cfg(handle)
-  rblf.mk2rbc_error("product.mk:2", "cannot handle invoking foo1")
-  rblf.mk2rbc_error("product.mk:3", "cannot handle invoking foo0")
+  cfg["PRODUCT_NAME"] = rblf.mk2rbc_error("product.mk:2", "cannot handle invoking foo1")
+  cfg["PRODUCT_NAME"] = rblf.mk2rbc_error("product.mk:3", "cannot handle invoking foo0")
 `,
 	},
 	{
@@ -975,7 +975,7 @@
   rblf.soong_config_namespace(g, "cvd")
   rblf.soong_config_set(g, "cvd", "launch_configs", "cvd_config_auto.json")
   rblf.soong_config_append(g, "cvd", "grub_config", "grub.cfg")
-  rblf.mk2rbc_error("product.mk:7", "SOONG_CONFIG_ variables cannot be referenced, use soong_config_get instead: SOONG_CONFIG_cvd_grub_config")
+  _x = rblf.mk2rbc_error("product.mk:7", "SOONG_CONFIG_ variables cannot be referenced, use soong_config_get instead: SOONG_CONFIG_cvd_grub_config")
 `,
 	}, {
 		desc:   "soong namespace accesses",
@@ -1269,6 +1269,7 @@
 		in: `
 ifeq (,$(call foobar))
 endif
+my_sources := $(local-generated-sources-dir)
 `,
 		expected: `load("//build/make/core:product_config.rbc", "rblf")
 
@@ -1276,6 +1277,7 @@
   cfg = rblf.cfg(handle)
   if rblf.mk2rbc_error("build/product.mk:2", "cannot handle invoking foobar"):
     pass
+  _my_sources = rblf.mk2rbc_error("build/product.mk:4", "local-generated-sources-dir is not supported")
 `,
 	},
 	{