news-2022-07-07-luau-recap-june-2022.md
July 7, 2022
A common problem that Luau has is that it primarily works by inspecting expressions in your program and narrowing the upper bounds of the values that can inhabit particular variables. In other words, each time we see a variable used, we eliminate possible sets of values from that variable’s domain.
There are some important cases where this doesn’t produce a helpful result. Take this function for instance:
Luau scans the function from top to bottom and first sees the line return i. It draws from this the inference that find_first_if must return the type of i, namely number.
This is fine, but things go sour when we see the line return nil. Since we are always narrowing, we take from this line the judgement that the return type of the function is nil. Since we have already concluded that the function must return number, Luau reports an error.
What we actually want to do in this case is to take these return statements as inferences about the lower bound of the function’s return type. Instead of saying “this function must return values of type nil,” we should instead say “this function may also return values of type nil.”
Lower bounds calculation does precisely this. Moving forward, Luau will instead infer the type number? for the above function.
This does have one unfortunate consequence: If a function has no return type annotation, we will no longer ever report a type error on a return statement. We think this is the right balance but we’ll be keeping an eye on things just to be sure.
Lower-bounds calculation is larger and a little bit riskier than other things we’ve been working on so we’ve set up a beta feature in Roblox Studio to enable them. It is called “Experimental Luau language features.”
Please try it out and let us know what you think!
We have a known bug with certain kinds of cyclic types when lower-bounds calculation is enabled. The following, for instance, is known to be problematic.
We hope to have this fixed soon.
Previously, the only way to create a sealed table was by with a literal empty table. We have relaxed this somewhat: Any table created by a {} expression is considered to be unsealed within the scope where it was created:
function foo() -> ReturnType (the correct syntax is function foo(): ReturnType)function keyword to start a type eg type T = functionA very special thanks to all of our open source contributors: