configs/configupgrade: Fix up internal HIL conversion functions
HIL implemented its type conversions by rewriting its AST to include calls to some undocumented builtin functions. Unfortunately those functions were still explicitly callable if you could figure out the name for them, and so they may have been used in the wild. In particular, __builtin_StringToFloat was used as part of a workaround for a HIL design flaw where it would prefer to convert strings to integers rather than floats when performing arithmetic operations. This issue was, indeed, the main reason for unifying int ant float into a single number type in HCL. Since we published that as a suggested workaround, the upgrade tool ought to fix it up. The other cases have never been documented as a workaround, so they are less likely to appear in the wild, but we might as well fix them up anyway since we already have the conversion functions required to get the same result in the new language. To be safe/conservative, most of these convert to _two_ function calls rather than just one, which ensures that these new expressions retain the behavior of implicitly converting to the source type before running the conversion. The new conversion functions only specify target type, and so cannot guarantee identical results if the argument type does not exactly match what was previously given as the parameter type in HIL.
This commit is contained in:
parent
d7641c0816
commit
1d35233a03
|
@ -13,4 +13,14 @@ locals {
|
||||||
|
|
||||||
lookup_literal = "${lookup(map("a", "b"), "a")}"
|
lookup_literal = "${lookup(map("a", "b"), "a")}"
|
||||||
lookup_ref = "${lookup(local.map, "a")}"
|
lookup_ref = "${lookup(local.map, "a")}"
|
||||||
|
|
||||||
|
# Undocumented HIL implementation details that some users nonetheless relied on.
|
||||||
|
conv_bool_to_string = "${__builtin_BoolToString(true)}"
|
||||||
|
conv_float_to_int = "${__builtin_FloatToInt(1.5)}"
|
||||||
|
conv_float_to_string = "${__builtin_FloatToString(1.5)}"
|
||||||
|
conv_int_to_float = "${__builtin_IntToFloat(1)}"
|
||||||
|
conv_int_to_string = "${__builtin_IntToString(1)}"
|
||||||
|
conv_string_to_int = "${__builtin_StringToInt("1")}"
|
||||||
|
conv_string_to_float = "${__builtin_StringToFloat("1.5")}"
|
||||||
|
conv_string_to_bool = "${__builtin_StringToBool("true")}"
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,4 +31,14 @@ locals {
|
||||||
"a" = "b"
|
"a" = "b"
|
||||||
}["a"]
|
}["a"]
|
||||||
lookup_ref = local.map["a"]
|
lookup_ref = local.map["a"]
|
||||||
|
|
||||||
|
# Undocumented HIL implementation details that some users nonetheless relied on.
|
||||||
|
conv_bool_to_string = tostring(tobool(true))
|
||||||
|
conv_float_to_int = floor(1.5)
|
||||||
|
conv_float_to_string = tostring(tonumber(1.5))
|
||||||
|
conv_int_to_float = floor(1)
|
||||||
|
conv_int_to_string = tostring(floor(1))
|
||||||
|
conv_string_to_int = floor(tostring("1"))
|
||||||
|
conv_string_to_float = tonumber(tostring("1.5"))
|
||||||
|
conv_string_to_bool = tobool(tostring("true"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,7 +207,7 @@ Value:
|
||||||
case int:
|
case int:
|
||||||
buf.WriteString(strconv.Itoa(tl))
|
buf.WriteString(strconv.Itoa(tl))
|
||||||
case float64:
|
case float64:
|
||||||
buf.WriteString(strconv.FormatFloat(tl, 'f', 64, 64))
|
buf.WriteString(strconv.FormatFloat(tl, 'f', -1, 64))
|
||||||
case bool:
|
case bool:
|
||||||
if tl {
|
if tl {
|
||||||
buf.WriteString("true")
|
buf.WriteString("true")
|
||||||
|
@ -398,6 +398,49 @@ Value:
|
||||||
buf.WriteByte(']')
|
buf.WriteByte(']')
|
||||||
break Value
|
break Value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HIL used some undocumented special functions to implement certain
|
||||||
|
// operations, but since those were actually callable in real expressions
|
||||||
|
// some users inevitably depended on them, so we'll fix them up here.
|
||||||
|
// These each become two function calls to preserve the old behavior
|
||||||
|
// of implicitly converting to the source type first. Usage of these
|
||||||
|
// is relatively rare, so the result doesn't need to be too pretty.
|
||||||
|
case "__builtin_BoolToString":
|
||||||
|
buf.WriteString("tostring(tobool(")
|
||||||
|
buf.Write(argExprs[0])
|
||||||
|
buf.WriteString("))")
|
||||||
|
break Value
|
||||||
|
case "__builtin_FloatToString":
|
||||||
|
buf.WriteString("tostring(tonumber(")
|
||||||
|
buf.Write(argExprs[0])
|
||||||
|
buf.WriteString("))")
|
||||||
|
break Value
|
||||||
|
case "__builtin_IntToString":
|
||||||
|
buf.WriteString("tostring(floor(")
|
||||||
|
buf.Write(argExprs[0])
|
||||||
|
buf.WriteString("))")
|
||||||
|
break Value
|
||||||
|
case "__builtin_StringToInt":
|
||||||
|
buf.WriteString("floor(tostring(")
|
||||||
|
buf.Write(argExprs[0])
|
||||||
|
buf.WriteString("))")
|
||||||
|
break Value
|
||||||
|
case "__builtin_StringToFloat":
|
||||||
|
buf.WriteString("tonumber(tostring(")
|
||||||
|
buf.Write(argExprs[0])
|
||||||
|
buf.WriteString("))")
|
||||||
|
break Value
|
||||||
|
case "__builtin_StringToBool":
|
||||||
|
buf.WriteString("tobool(tostring(")
|
||||||
|
buf.Write(argExprs[0])
|
||||||
|
buf.WriteString("))")
|
||||||
|
break Value
|
||||||
|
case "__builtin_FloatToInt", "__builtin_IntToFloat":
|
||||||
|
// Since "floor" already has an implicit conversion of its argument
|
||||||
|
// to number, and the result is a whole number in either case,
|
||||||
|
// these ones are easier. (We no longer distinguish int and float
|
||||||
|
// as types in HCL2, even though HIL did.)
|
||||||
|
name = "floor"
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.WriteString(name)
|
buf.WriteString(name)
|
||||||
|
|
Loading…
Reference in New Issue