Emit mksubst call for $(subst ...)

Bug: 172923994
Test: internal
Change-Id: I7994bee61f6f8bdee6eac50ecb8a6064830447a4
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 55a35e9..abfd082 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -99,7 +99,7 @@
 	// TODO(asmundak): remove it once all calls are removed from configuration makefiles. see b/183161002
 	"shell":    {baseName + ".shell", starlarkTypeString},
 	"strip":    {baseName + ".mkstrip", starlarkTypeString},
-	"subst":    {baseName + ".subst", starlarkTypeString},
+	"subst":    {baseName + ".mksubst", starlarkTypeString},
 	"warning":  {baseName + ".mkwarning", starlarkTypeVoid},
 	"word":     {baseName + "!word", starlarkTypeString},
 	"wildcard": {baseName + ".expand_wildcard", starlarkTypeList},
@@ -509,13 +509,7 @@
 		}
 		inferred_type := asgn.value.typ()
 		if inferred_type != starlarkTypeUnknown {
-			if ogv, ok := lhs.(*otherGlobalVariable); ok {
-				ogv.typ = inferred_type
-			} else if pcv, ok := lhs.(*productConfigVariable); ok {
-				pcv.typ = inferred_type
-			} else {
-				panic(fmt.Errorf("cannot assign new type to a variable %s, its flavor is %T", lhs.name(), lhs))
-			}
+			lhs.setValueType(inferred_type)
 		}
 	}
 	if lhs.valueType() == starlarkTypeList {
@@ -1114,11 +1108,19 @@
 	words[2].TrimLeftSpaces()
 	words[2].TrimRightSpaces()
 	obj := ctx.parseMakeString(node, words[2])
+	typ := obj.typ()
+	if typ == starlarkTypeString {
+		return &callExpr{
+			object:     obj,
+			name:       "replace",
+			args:       []starlarkExpr{&stringLiteralExpr{from}, &stringLiteralExpr{to}},
+			returnType: typ,
+		}
+	}
 	return &callExpr{
-		object:     obj,
-		name:       "replace",
-		args:       []starlarkExpr{&stringLiteralExpr{from}, &stringLiteralExpr{to}},
-		returnType: starlarkTypeString,
+		name:       "subst",
+		args:       []starlarkExpr{&stringLiteralExpr{from}, &stringLiteralExpr{to}, obj},
+		returnType: obj.typ(),
 	}
 }
 
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index 54263b8..bb6484b 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -640,6 +640,22 @@
 `,
 	},
 	{
+		desc:   "subst in list",
+		mkname: "product.mk",
+		in: `
+files = $(call find-copy-subdir-files,*,from,to)
+PRODUCT_COPY_FILES += $(subst foo,bar,$(files))
+`,
+		expected: `load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+  cfg = rblf.cfg(handle)
+  _files = rblf.find_and_copy("*", "from", "to")
+  rblf.setdefault(handle, "PRODUCT_COPY_FILES")
+  cfg["PRODUCT_COPY_FILES"] += rblf.mksubst("foo", "bar", _files)
+`,
+	},
+	{
 		desc:   "assignment flavors",
 		mkname: "product.mk",
 		in: `
diff --git a/mk2rbc/variable.go b/mk2rbc/variable.go
index 56db192..a650453 100644
--- a/mk2rbc/variable.go
+++ b/mk2rbc/variable.go
@@ -26,6 +26,7 @@
 	emitSet(gctx *generationContext, asgn *assignmentNode)
 	emitDefined(gctx *generationContext)
 	valueType() starlarkType
+	setValueType(t starlarkType)
 	defaultValueString() string
 	isPreset() bool
 }
@@ -44,6 +45,10 @@
 	return v.typ
 }
 
+func (v *baseVariable) setValueType(t starlarkType) {
+	v.typ = t
+}
+
 func (v baseVariable) isPreset() bool {
 	return v.preset
 }
@@ -279,7 +284,7 @@
 		} else if name == strings.ToLower(name) {
 			// Heuristics: if variable's name is all lowercase, consider it local
 			// string variable.
-			v = &localVariable{baseVariable{nam: name, typ: starlarkTypeString}}
+			v = &localVariable{baseVariable{nam: name, typ: starlarkTypeUnknown}}
 		} else {
 			vt := starlarkTypeUnknown
 			if strings.HasPrefix(name, "LOCAL_") {