Luau Recap: August 2021

Luau is our new language that you can read more about at We have some new editor features and more typechecking, linter, and performance improvements for you this month!

Editor features

The Roblox Studio Luau-Powered Autocomplete & Language Features Beta that our team has been working on has finally been released! Be sure to check that out and leave your feedback for things we can improve.

To support that feature, a lot of work went into:

  • Improving fault-tolerant parser recovery scenarios
  • Storing additional information in the AST, including comments, better location information and partial syntax data
  • Tracking additional information about types and their fields, including tracking definition locations, function argument names, deprecation state and custom Roblox-specific tags
  • Updating reflection information to provide more specific Instance types and correct previously missing or wrong type annotations
  • Hybrid typechecking mode which tries to infer types even in scripts with no typechecking enabled
  • Support for types that are attached to the DataModel tree elements to provide instance member information
  • Placing limits to finish typechecking in a finite space/time
  • Adding Autocomplete API for the Roblox Studio to get location-based entity information and appropriate suggestions
  • Additional type inference engine improvements and fixes

While our work continues to respond to the feedback we receive, our team members are shifting focus to add generic functions, improve type refinements in conditionals, extend Parallel Luau, improve Lua VM performance and provide documentation.

Typechecking improvements

Type constraint resolver now remembers constraints placed on individual table fields.

This should fix false-positive errors reported after making sure the optional table field is present:

local t: {value: number?} = {value = 2}

if t.value then
    local v: number = t.value -- ok

And it can also refine field type to a more specific one:

local t: {value: string|number} = {value = 2}

if type(t.value) == "number" then
    return t.value * 2 -- ok

Like before, combining multiple conditions using ‘and’ and ‘not’ is also supported.

Constructing arrays with different values for optional/union types are now also supported for individual table fields and in functions call arguments:

type Foo = {x: number | string, b: number?}

local function foo(l: {Foo}) end

    {x = 1234567},
    {x = "hello"}, -- now ok

type Bar = {a: {Foo}}

local foos: Bar = {a = {
    {x = 1234567},
    {x = "hello", b = 2}, -- now ok

Finally, we have fixed an issue with Roblox class field access using indexing like part["Anchored"] = true .

Linter improvements

We have added a new linter check for duplicate local variable definitions.

It is created to find duplicate names in cases like these:

local function foo(a1, a2, a2) -- Function argument 'a2' already defined on column 24
local a1, a2, a2 = f() -- Variable 'a2' already defined on column 11

local bar = {}
function bar:test(self) -- Function argument 'self' already defined implicitly

Our UnknownType linter warning was extended to check for correct class names passed into FindFirstChildOfClass , FindFirstChildWhichIsA , FindFirstAncestorOfClass and FindFirstAncestorWhichIsA functions.

Performance improvements

We have added an optimization to ‘table.unpack’ for 2x performance improvement.

We’ve also implemented an extra optimization for tables to predict required table capacity based on fields that are assigned to it in the code after construction. This can reduce the need to reallocate tables.

Variadic call performance was fine-tuned and is now ~10% faster.

Construction of array literals was optimized for a ~7% improvement.

Another optimization this month changes the location and rate of garbage collection invocations. We now try to avoid calling GC during the script execution and perform all the work in the GcJob part of the frame (it could be seen in the performance profiler). When possible, we can now skip that job in the frame completely, if we have some memory budget available.

Other improvements

For general stability improvements we fixed a crash when strange types like ’ nil?? ’ are used and when users have their own global functions named ’ require '.

Indexing a table with an incompatible type will now show squiggly error lines under the index instead of the whole expression, which was a bit misleading.

An issue with debug information that caused repeat ... until condition line to be skipped when stepping was fixed.

Type output was improved to replace display of types like ’ {<g405>(g405) -> g405} ’ with ’ {<a>(a) -> a} '.


This topic was automatically opened after 10 minutes.

I really like the improvements done to the language itself, but I dislike how new features are added to the editor without fixing the mess that’s been lingering for months. Variable names and children are often incorrectly predicted or not at all, especially when using FindFirstChild and WaitForChild. I’m not trying to discredit these changes that are definitelly amazing, but they are for nothing if the editor itself is a pain to use to the point where projects like Rojo are a must only to be able to properly develop.


This sounds really promising!

I have a question, I know this is just a prediction, therefore not perfect, but do you believe, that in this case, such table would pre-allocate memory for the .Changed field?
I know that this is something a lot of code does, so it’s good to know such thing.

    local self = setmetatable({
        _bindable ="BindableEvent")
    }, Class)

    self.Changed = self._bindable.Event

    return self

My “fear” right now is that using setmetatable this way might deoptimize that behaviour.


Good stuff! Do you guys plan on letting us choose the style of type syntax sometime soon? I really can’t stand pascal syntax and im sure a lot of people can agree with me, I think that C-styled type syntax would be much cleaner :wink:

1 Like
-- current style
local x:((number)->number)->(number)->number
-- more like c style
local number(*(*foo)(number(*)(number)))(number);

So much cleaner…


Your fear is correct, and that’s a very good point. We will take a look at extending the optimization to see past setmetatable.


We don’t plan to make major syntactical changes to the language short of when we’re adding new features. We’ve talked about various changes that might be interesting but they inevitably conclude in:

  • Syntax is a matter of preference
  • The current syntax is pretty good
  • Adding disjoint syntax makes the language feel inconsistent; we’ve tried very hard to avoid that and to add new syntax in a way that matches the existing style
  • Having two different ways to say the same thing syntactically fragments the language which makes learning it more difficult.

The point of the new autocomplete system is precisely to resolve these. They can not be resolved by “fixing” them in the old system because the autocomplete system that works in the editor right now by default is full of special cases and is lacking fundamental features to make it robust. If you have scenarios that you feel are broken wrt autocomplete, please try the new autocomplete beta, and leave feedback on Script Editor: Luau-Powered Autocomplete & Language Features Beta so that we can address it.


We need sg like that but it (was? is?) simply not reliable enough for developing.

I tried it twice.

First time it had so many bugs and missing features that I stopped using it after some minutes. examples: IsA("") gave no suggestions (I think it is solved by now), “elseif” is unknown (not solved) etc.

Some days ago I gave it another chance but I stopped it again, waiting for a more precise one.

In some cases it doesn’t give suggestions for my workspace objects, only for variables.

Keep up developers and beta testers, I hope it will be better soon!

1 Like

Can you please report the bugs you found in that thread. I know it’s time consuming, but without reports it’s hard for us to improve.
We are tracking some bugs, but we actually don’t have ‘many’ of those on our list.

You say that you’re waiting for a more precise one and it seems that the current autocomplete gives you better suggestions (or maybe the new one didn’t suggest anything at all).
We would be happy to see an example like that.


Ty for your answer.
I reactivated this feature.
I’ll report it on Bug thread if I find any showstopper bug that makes me stop using it again.

1 Like

Great changes, and I’m surprised as usual that my 99% strict-mode codebase is unscathed (i.e. no script analysis warnings) as the type checker is improved.

I do have a question about the type checker… I’ve noticed there’s a caching behavior with script analysis warnings. For example, when I switched to my macbook, I got hundreds of “unknown require” warnings in my team create place even though this issue has been ostensibly fixed, and after I went through and opened up the hundred or so modules that emitted this warning, they all went away and I haven’t seen any since. My guess is that these warnings were cached from a previous time I opened studio on an older version of luau, and the type checker just had to be run once again through all these modules to get rid of these cached warnings from that older version of luau.

Is it possible that this caching behavior would cause some script analysis warnings to not show up when they should, even after a major update to Luau like this? And if so, is there a surefire way I can make sure the script analysis is getting run through all of my hundreds of modules when an update to Luau is released? I don’t want to miss a script analysis warning that only shows up when I finally open up a module that I haven’t touched in centuries.

1 Like

We don’t cache warnings across different Studio runs. We do cache them in memory, and I know we had issues with script invalidation in TeamCreate - we’ll investigate.


I love all the improvements to performance and type checking (especially performance), but is there an ETA on when we are going to see new features/syntax added to the language? (specifically anything highly requested or nice in this topic) I know type checking, multithreading, and all the other performance enhancements are massive and time-consuming projects, so there is no rush to finish that but it would be nice to have an ETA or confirmation on what or if anything at all is being considered or getting added to the language from that thread.

1 Like

Note that that thread had hundreds of suggestions and by default you should assume it’s not going to be implemented – we have a point of view on the language evolution and it explicitly doesn’t include adding all features that are being proposed :slight_smile: That said, there are going to be more language and library features, some of them from that thread, both in the shorter term and in the longer term. What you’re really asking for, I think, is a roadmap – we don’t have one to share yet but it’s likely that we’ll start sharing our future plans a bit more in the future. Sorry that this is very vague – we have nothing to announce yet.


So I’m not the only one whose noticed that recently?

Also lately, when I type in “Else” and press enter, it’s been auto completing to something else. I forget what exactly - ElapsedTime() or something I think. Not sure if “El” ever auto completed to “Else”, but I certainly never found myself accidentally checking the time before recently, which makes me think it probably did auto-complete correctly at some point.

Just in general I feel like auto-complete has flat out been missing more than hitting lately.


Why exactly are comments being stored in the AST? I don’t really see how that provides any benefit to the interpreter and just seems like bloat.

1 Like

e.g. annotating code with javadoc-esque comments that the code editor can show when inspecting a symbol

Just spitballing here though.


The interpreter doesn’t use the AST so it doesn’t matter, but the comments are used during autocomplete to not autocomplete words inside comments.