Skip to content

Conversation

@aatxe
Copy link
Member

@aatxe aatxe commented Jan 16, 2026

Hello Luaunauts, we're continuing into the second release of the year at a brisk pace! We've got a number of improvements for both native code generation and the new type solver, as well as some other assorted changes, that keep us moving towards the goal of making the best possible scripting language!

Analysis

  • Refinements against a union of tables would sometimes erroneously refine to a narrower type than intended. The root cause here was a bug in the logic that determines how to "simplify" types (for example knowing that true | false is the same as boolean).
    export type States = "Closed" | "Closing" | "Opening" | "Open"
    export type MyType<A = any> = {
        State: States,
        IsOpen: boolean,
        Open: (self: MyType<A>) -> (),
    }
    
    local value = {} :: MyType
    
    function value:Open()
        if self.IsOpen == true then
        elseif self.State == "Closing" or self.State == "Opening" then
            -- Prior, this line errored as we were erroneously refining
            -- `self` with `{ State: "Closing" | "Opening" }` rather
            -- than `{ read State: "Closing" | "Opening" }
            self:Open()
        end
    end
    • Adds an option in ToString.cpp to disable the use of synthetic names, which can be used to improve the quality of hover type.
    • Fixes a bug where table.freeze would incorrectly error on arguments of any type (fixes table.freeze(any) type error: Type 'any' could not be converted into 'table' #2181)
    • Subtyping mistakenly did not allow for us to covariantly check tables with missing properties against table types that gave those properties optional types. This release should fix these issues, including fixes cannot convert '{ }' into '{ a: number? }' bug #2164.
    • Type functions have a global environment that defines all of the type aliases present in the environment around the type function definition, and the API of type functions also allows you to mutate types, specifically table types and function types. Though we never supported the type functions actually mutating the aliases present in the environment around them, the mutable API allowed for users to author type functions that appeared to do so, which could be confusing when they later discover that their mutation did not take place. This release introduces new errors for type functions that attempt to call mutable APIs on types from their environment, e.g.
      type myType = {}
      type function create_table_with_key()
          myType:setproperty(types.singleton "key", types.optional(types.number)) -- this errors now!
          return myType
      end
      local my_tbl: create_table_with_key<> = {key = "123"}
    • Bidirectional inference for lambdas on extern types with generic parameters should work more consistently.
    • Handle AstStatLocalFunction in findBindingAtPosition #2166 fixes a bug with findBindingAtPosition that should enable LSP tools to better support finding references for local functions and their parameters.
    • This release also includes a broad-strokes improvement to error suppression handling. The New Type Solver should now be more consistent about not reporting (or re-reporting) errors involving any or *error-type* or directly downstream of an existing type error.
    • This release removes the experimental DebugLuauStringSingletonBasedOnQuotes flag that trialed basing singleton type inference solely on the usage of different quote styles. We do not think we will be proceeding with this approach at this time.

Native Code Generation

  • Fixes a crash in getOffsetBase when the passed in IrOp is not an IrInst.
  • Improves inlining support by passing the argument value as the initializer for the temporary being allocated in cases like anonymous function arguments or referring to upvalues in a function body.
  • Fixes the function end byte offset value, along side a number of other internal values that could lead to incorrect code size values.
  • Adds a more direct implementation of code generation for vector equality and inequality that leads to fewer instructions in the IR and a smaller number of produced basic blocks.
  • Adds a more optimized code generation flow for situations where we're indexing a table with keys that have unexpected type tags.
  • Fixes a bug where NCG would sometimes mistakenly optimize away necessary entry tag checks.
  • Introduces a customizable per-VM storage for use from "execution callbacks" system, with NCG as its first consumer for extra spill spaces. This adds 32x 8-byte spill slots on arm64 (on top of existing 22) and 64x 8-byte spill slots on x64 (on top of existing 12*).
  • Changes codegen for bit32 operations to use guards, rather than normal control flow, leading to significant (~30%) performance improvements in some benchmarks that heavily leverage these operations.
  • Adds a combined instruction UINT_TO_FLOAT to replace instances where we needed to emit UINT_TO_NUM and NUM_TO_FLOAT paired up. This leads to some very modest performance improvements.

Runtime

Internal Contributors

Co-authored-by: Andy Friesen afriesen@roblox.com
Co-authored-by: Annie Tang annietang@roblox.com
Co-authored-by: Ariel Weiss arielweiss@roblox.com
Co-authored-by: Hunter Goldstein hgoldstein@roblox.com
Co-authored-by: James McNellis jmcnellis@roblox.com
Co-authored-by: Sora Kanosue skanosue@roblox.com
Co-authored-by: Vighnesh Vijay vvijay@roblox.com
Co-authored-by: Vyacheslav Egorov vegorov@roblox.com

hgoldstein and others added 30 commits January 10, 2025 09:13
Note: Fixed conflicts by hand in:
- Analysis/src/ConstraintGenerator.cpp
- CodeGen/src/OptimizeConstProp.cpp
- VM/src/lmathlib.cpp
- tests/Conformance.test.cpp
a03c92095f6 #unflagged CLI-141149 Added lua_clonetable (#97902)
d66c43f36aa #flagged CLI-140903: Do not crash on duplicate keys in table literals (#97833)
8a2687f1690 #nonprod Luau: fix a test configuration issue breaking OSS CI. (#97878)
7add6d9dde9 #nojira CI-debugger revert #unflagged CLI-132461 Luau: refactor subtyping to also include the generic mapping it came up with. (#97872)
0c731fd3cc4 #flag-removal Clip `LuauNewSolverVisitErrorExprLvalues` (#96942)
2fe783b9615 #unflagged CLI-132461 Luau: refactor subtyping to also include the generic mapping it came up with. (#97803)
0cc41a0afae #unflagged CLI-141053 Luau buffer readbits/writebits implementation for big endian machines (#97826)
ae50bf04f99 #nonprod CLI-140027 Simplify require-by-string path resolution, fix bug when running CLI tools on unprefixed path (#97468)
77004599a6f #flag-removal Cleanup Luau VM and Compiler flags (#97799)
86777e269dd #flag-removal Remove LuauUserTypeFunPrintToError, LuauUserTypeFunNoExtraConstraint, LuauUserTypeFunUpdateAllEnvs, LuauUserTypeFunThreadBuffer and LuauUserTypeFunExportedAndLocal (#97624)
349b133fdc4 #nojira CI-debugger revert #unflagged CLI-132461 Luau: refactor subtyping to also include the generic mapping it came up with. (#97759)
2e820646ffa #flagged CLI-139615: Treat user defined type functions as opaque in eqSatSimplify (#96897)
c0845205e37 #flag-removal CLI-140688 Clean up `FFlagLuauIntersectNormalsNeedsToTrackResourceLimits` as `true`. (#97719)
3e07876a043 #flagged CLI-140571: Track interior free table types generated during constraint solving (#97498)
199b558dc36 #unflagged CLI-132461 Luau: refactor subtyping to also include the generic mapping it came up with. (#95646)
fd9255f62d3 #nonprod CLI-140762 unittest for fragment ac crash (#97669)
e9c710e017f #flag-removal FFlagLuauStoreCommentsForDefinitionFiles (#93359)
b184b940d55 CLI-140702 #unflagged Fix most clang-tidy warnings in TypeChecker2 (#97604)
1fc857f1bb3 CLI-140489 #unflagged Fix a potential hash collision bug in StringCache. (#97539)
58f62f900a2 #nonprod Some new unit testing macros for Luau tests. (#97336)
ab43a354b25 #flag-removal Remove LuauVectorMetatable and LuauVectorDefinitionsExtra (#97528)
c4c28694390 #flagged CLI-140485 Do not retain the Def/RefinementKey arenas when retainFullTypeGraphs is false (#97422)
This test fails due to a bad interaction when `FFlagLuauStoreCSTData` is
enabled, whilst `FFlagLexerFixInterpStringStart` is disabled.
The OSS test suite, when run with `--fflags=true`, enables all
flags starting with a `Luau` prefix, but does not enable any other flag.

To resolve this, we explicitly enable both fflags for the failing
interpolated string test cases. As a consequence, we technically lose
the check that these tests pass when all flags are disabled.
@aatxe aatxe merged commit 93c83a4 into master Jan 16, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

10 participants