Luau Recap: June 2021

It’s July already?!

Last month, most of our team was busy working on improving Luau interaction with Roblox Studio for an upcoming feature this month, but we also managed to add typechecking and a few performance improvements as well!

Constraint Resolver

To improve type inference under conditional expressions and other dynamic type changes (like assignments) we have introduced a new constraint resolver framework into Luau type checker.

This framework allows us to handle more complex expressions that combine and / not operators and type guards.

Type guards support include expressions like:

  • if instance:IsA("ClassName") then
  • if enum:IsA("EnumName") then
  • if type(v) == "string" then

This framework is extensible and we have plans for future improvements with a == b / a ~= b equality constraints and handling of table field assignments.

It is now also possible to get better type information inside else blocks of an if statement.

A few examples to see the constraint resolver in action:

function say_hello(name: string?)
    -- extra parentheses were enough to trip the old typechecker
    if (name) then 
        print("Hello " .. name .. "!")
        print("Hello mysterious stranger!")
function say_hello(name: string?, surname: string?)
    -- but now we handle that and more complex expressions as well
    if not (name and surname) then
        print("Hello mysterious stranger!")
        print("Hello " .. name .. " " .. surname .. "!")

Please note that constraints are currently placed only on local and global variables.
One of our goals is to include support for table members in the future.

Typechecking improvements

We have improved the way we handled module require calls. Previously, we had a simple pattern match on the local m = require(...) statement, but now we have replaced it with a general handling of the function call in any context.

Handling of union types in equality operators was fixed to remove incorrect error reports.

A new IsA method was introduced to EnumItem to check the type of a Roblox Enum. This is intended to replace the enumItem.EnumType == Enum.NormalId pattern in the code for a construct that allows our constraint resolver to infer better types.

Additional fixes include:

  • table.pack return type was fixed
  • A limit was added for deeply nested code blocks to avoid a crash
  • We have improved the type names that are presented in error messages and Roblox Studio
  • Error recovery was added to field access of a table? type. While you add a check for nil , typechecking can continue with better type information in other expressions.
  • We handled a few internal compiler errors and rare crashes

Editor features

If you have Luau-Powered Type Hover beta feature enabled in Roblox Studio, you will see more function argument names inside function type hovers.

Behavior changes

We no longer allow referencing a function by name inside argument list of that function:

local function f(a: number, b: typeof(f)) -- 'f' is no longer visible here

Performance improvements

As always, we look for ways to improve performance of your scripts:

  • We have fixed memory use of Roblox Actor scripts in Parallel Luau beta feature
  • Performance of table clone through table.move has been greatly improved
  • Table length lookup has been optimized, which also brings improvement to table element insertion speed
  • Built-in Vector3 type support that we mentioned in April is now enabled for everyone

Performance updates are always great.

Are there any updates on generic functions? I don’t believe we have gotten one since they were removed.


Table length lookup has been optimized

Any details on this? You mention ‘lookup’, so is this achieved through interning?


This is cool! I’m still new to coding, so I probably won’t know how useful this will be until I’m advanced. :sweat_smile:


This is amazing, performance updates are great. Very cool, and thank you for this!

This was achieved by micro-optimizing the existing code without changing how length is stored. We do want to explore implementation with a cached value, but that’s not that simple.

In base Lua 5.1/5.2/5.3 implementation, length execution time depends on the length of the table, so the boost is not the same everywhere. But as an example, in a benchmark of inserting table elements in a loop we saw an improvement of 25-40%.


Awesome to see the constraint resolver improving with better type narrowing support!
It seems that the types for :FindFirstChild()/:FindFirstChildWhichIsA() etc. have changed incorrectly:

Notice how it resolves to Instance and not Instance?

Also, is it planned for :FindFirstChildWhichIsA("type") to be able to resolve to type? rather than Instance?. It would mean that you wouldn’t have to have a foo:IsA("type") check afterwards.


Your point stands, but note that you can already do this more ergonomically with:
local value = parent:FindFirstChildWhichIsA("Thing") :: Thing

1 Like

That’s definitely true, but I assumed this would be more of an antipattern. I thought type assertion should be more of an “escape hatch” rather than used frequently.

Anyways, this isn’t a particularly important issue, just would be a nice to have :slight_smile:

1 Like

It is, but if you have to choose between adding actual unnecessary code that has to execute at run-time and adding type annotations that shouldn’t be needed in the long run then you should probably pick the type annotations.

Because the code is also problematic in that it suggests that a condition exists when it actually doesn’t.

1 Like

is that the roblox script update we got yesterday?
the roblox update 07.07.2021 Destroyed some important stuff in my game on the release day -_-

What kind of issues do you have in the recent update?


Are you considering adding Classes to Luau?

Having to use __index and setmetatable is confusing nomatter how many times I do it.

I :heart: this. This will make my life so much easier. THank you for finally adding a useful Luau update!

1 Like

Sorry to reply 4 days later, but this would definitely be interesting… Although I’m not sure how I feel about adding “Class” syntactics yet, or at all… cough C++ is a train wreck cough