Tags: luau-lang/luau
Tags
Sync to upstream/release/704 (#2180) Hello everyone and a happy New Year! The first sync of 2026 is already here with improvements to new type solver and native code generation. # Analysis * Explicit type instantiation is now ready for production use (Fixes #2114, Fixes #2144, Fixes #2113, and Fixes #2119) * When subtyping extern types and tables, we now check indexers as well as properties, which fixes a soundness bug where tables without properties but clearly incompatible indexers were considered super types of extern types: ```luau local function f(c: Color3): { Color3 } return c -- This used to not error and now does end ``` * Using bound generics as type annotations on nested functions or lambdas now no longer leak into the quantified generics of said lambda / inner function: ```luau local function makeApplier<A..., R...>(f: (A...) -> (R...)) return function (... : A...): R... f(...) end end local function add(x: number, y: number): number return x + y end -- Prior, `f` would have the (incorrect) type of `<A..., R...>(A...) -> (R...)`, as it -- erroneously picked up the generics from `makeApplier`. Now it will have -- the correct type of `(number, number) -> number` local f = makeApplier(add) ``` * Lambda bidirectional inference is now slightly less sensitive to generics; prior _any_ generic in the lambda type would prevent "pushing in" the type, but now this is restricted to potentially unbound generics that are from the function type we are pushing in, as in: ```luau type testsuite = { case: (self: testsuite, <T>(T) -> T) -> () } local test1: { suite: (string, (testsuite) -> ()) -> () } = nil :: any -- Prior we would error on the _entire_ lambda ... test1.suite("LuteTestCommand", function(suite) -- but now we only error here suite:case(42) end) ``` * Generic polarity inference has been reworked to be significantly faster, especially for large mutually recursive type aliases * Generic type packs now more consistently infer the correct type for function calls, most importantly for `pcall` and its siblings. (Fixes #2109. Fixes #2143) ```luau local function makestr(n: number): string return tostring(n) end -- `s` now has type `string` and not `unknown` local success, s = pcall(makestr, 42) ``` * Bidirectional inference of constants (especially booleans) should be more consistent, such as in: ```luau type Good = { success: true, result: string } type Bad = { success: false, error: string } type Result = Good | Bad -- This errors before and after, but we now recognize that you -- meant this to be `Bad` and will note the lack of the `error` member local a: Result = { success = false, result = 'something' } ``` * The mechanism for generating "Recursive type being used with different parameters" has been reworked. This should mean less false positives, and we will now consistently highlight the erroneous type alias instance, but we now adhere closer to the [very strict RFC](https://rfcs.luau.org/recursive-type-restriction.html). ```luau -- Not only did this line error, but it errored even in nonstrict mode type A = { B<any> } type B<T> = { method: (B<T>) -> () } -- This used to _not_ error under the new solver but now does, despite being fairly benign type B<T = number> = { B<number> } ``` # Native Codegen * `vector` library operations are now performed with 32-bit floating-point precision, matching the results of the interpreter and improving performance by skipping unnecessary 32-bit to 64-bit conversions * 2-argument `vector.create` constructor will now use native lowering instead of calling out to a slower C++ fastcall function * Added native support for vector flooring division operator `//` instead of calling out to a slower C++ VM utility function * Identical calls to the math library (`math.cos`, `math.sin` and many others) are now eliminated * A larger set of identical operations on vector values are now eliminated * Buffer length checks are now merged together when possible ```luau -- only one range check return buffer.readf64(b, i) * buffer.readf64(b, i + 8) * buffer.readf64(b, i + 16) -- when stride multiplier is used, it still produces only a single range check return buffer.readf64(b, i * 8) * buffer.readf64(b, (i + 1) * 8) * buffer.readf64(b, (i + 2) * 8) ``` * Fixed missing constant fold of `TRUNCATE_UINT` which could cause a lowering failure under 'LuauCodegenNumIntFolds2' flag # Autocomplete * Fixed a crash when indexing write-only properties # Internal Contributors Co-authored-by: Andy Friesen <[email protected]> Co-authored-by: Annie Tang <[email protected]> Co-authored-by: Ariel Weiss <[email protected]> Co-authored-by: Hunter Goldstein <[email protected]> Co-authored-by: Varun Saini <[email protected]> Co-authored-by: Vighnesh Vijay <[email protected]> Co-authored-by: Vyacheslav Egorov <[email protected]>
Sync to upstream/release/703 (#2146) This will be Luau's last release for the year! Happy holidays and we'll see y'all in 2026. # Analysis * Fix a bug in type checking functions where oversaturation (passing too many arguments to a function) was sometimes missed, for example: ```luau type T = { method: (T, number) -> number } local function onT(a: T) a:method(5, 7) -- This would not error prior end ``` * Type mismatch error wording has been improved: instead of talking about "X could not be converted into Y," we talk about "expecting X" but "getting Y." * Builtin type functions now use improved logic for overload resolution. * Type annotations on for-in loops are now respected, for example: ```luau function my_iter(): any return {} end for index: number, value: string in my_iter() do -- This now errors, whereas prior we'd infer `index` to be of type `any` local ohno: boolean = index end ``` * Function statements for table members now have their types checked, for example the following used to not error: ```luau local Library: { isnan: (number) -> number } = {} :: any function Library.isnan(s: string): boolean return s == "NaN" end ``` * Nil-able lambdas can now participate in bidirectional inference, for example: ```luau local listdir: (string, ((string) -> boolean)?) -> { string } = nil :: any listdir("my_directory", function (path) -- `path` will now have type `string` here end) ``` * Internal compiler errors when operating on exceptionally large types should be less common, thanks to some non-recursive implementations of common visitors. * Fix a crash that could occur when deserializing user defined type functions, one such example being: ```luau type function identity(t: type) return t end type func<parameters...> = typeof(function(...: parameters...) end) local whomp: <T>(arg1: T) -> identity<T> whomp(function(...) end :: func<any>) ``` * Fix instantiation picking unhelpful (and sometimes plain incorrect) bounds. Fixes #2125. Fixes #2118. ```luau local foo: <P>(constructor: (P) -> any) -> (P) -> any = (nil :: any) -- Prior `fn` would be of type `(never) -> any`, and will now be the more useful -- ({ test: true }) -> any local fn = foo(function (value: { test: true }) return value.test end) ``` * Fix a class of constraint solving incomplete errors that could occur when referencing globals inside lambdas. * `types.unionof` and `types.intersectionof` will now attempt to simplify their arguments, avoiding producing nested intersections and unions, as well as removing identity types like `never` and `unknown`. * The `setmetatable` type function now waits for its arguments before resolving, fixing a class of constraint ordering bugs. Fixes #2106: ```luau local MyClass = {} local MyClassMetatable = table.freeze({ __index = MyClass }) type MyClass = setmetatable<{ name: string }, typeof(MyClassMetatable)> function MyClass.new(name: string): MyClass return setmetatable({ name = name }, MyClassMetatable) end function MyClass.hello(self: MyClass): string return `Hello, {self.name}!` end local instance = MyClass.new("World") -- This would sometimes be inferred as `any` due to constraint ordering bugs. local g = instance:hello() ``` # Native Codegen We now internally encode true float registers, as opposed to treating all floats as doubles (as Luau does). This allows us to skip conversions to and from a double when lowering operations on floats. Additionally, we've added several optimizations for converting in between different kinds of numbers (32-bit integers, 32-bit unsigned integers, floats, doubles, etc.). Consequently, an important notice for users of `CodeGen::HostIrHooks`: we are updating the behavior of `LOAD_FLOAT`, `DOT_VEC`, `EXTRACT_VEC`, `BUFFER_READF32`, `BUFFER_WRITEF32`, and `STORE_VECTOR` to produce or consume single floating-point number instead of a double. When `FFlag::LuauCodegenSplitFloat` is enabled, `FLOAT_TO_NUM` and `NUM_TO_FLOAT` have to be used for explicit conversions. * Double the amount of registers that are spilt for ints and floats on x64. This fixes NCG failing to compile snippets that end up generating many transient numbers. Fixes #1468. * Fix a bug where NCG might improperly claim a stored value (and its tag) can be elided after a GC check. * NCG now optimizes buffer and userdata loads that can be computed from previous stores (e.g. if you write `42` to the nth byte in a buffer and then immediately read said byte). * NCG will now try to remove unused temporary userdata allocations * Fix a bug where NCG might claim a spilt register has been restored but not actually do so, causing a garbage read from a register. * NCG now optimizes upvalue loads and stores. * NCG now optimizes `and` and `or` without generating basic blocks, allowing more optimizations to occur. * Fix a bug where NCG on arm64, restoring spilling registers may require using an (already occupied) temporary register. * Runtime type checks internal to a function that are redundant with type checks added through annotations are now elided. * NCG had an off-by-one bug where loop step detection was not kicking in for non-constant end ranges in for-in loops: `i = 1,10` would be optimized and `i = 1,#t` would not be. # Require * Added a `to_alias_override` callback: this allows embedders to provide an alias that _cannot_ be overridden by users.
Sync to upstream/release/702 (#2126) Hello! This week, we've made a bunch of improvements to the performance and stability of the analysis system. We've also made some small improvements to inlining and native codegen. # Autocomplete * Suggest singleton string keys from indexers # General * Reduce stack utilization of the parser # Analysis * User-defined type functions don't need separate irreducible errors when they error. * Fix a performance problem that could occur when selecting an overload for a function call. * Fix a hang that could occur in function generalization. * Delete EqSat. It was a very promising experiment but it didn't work out. * Properly treat negation types as being contravariant in their operands. (ie if `A <: B`, then `~B <: ~A`) * Add a new C++ utility function `Frontend::parseType`. This function allocates a `TypeId` from a string that contains a valid Luau type annotation. * Correctly infer the type of a property lookup on a table which contains an indexer which is a union of string singletons. (eg `{["foo"|"bar"]: number}`) # VM * Reevaluate the inlining cost model using constant function arguments. * Constant-fold `string.char` and `string.sub`. # Native Codegen * Fix a perfermance regression that could happen when running out of registers. * 32-bit integer addition and subtraction using bit32 library can be performed by integer instructions without extra double conversions # Internal Contributors Co-authored-by: Andy Friesen <[email protected]> Co-authored-by: Ariel Weiss <[email protected]> Co-authored-by: Hunter Goldstein <[email protected]> Co-authored-by: Sora Kanosue <[email protected]> Co-authored-by: Vyacheslav Egorov <[email protected]> --------- Co-authored-by: Hunter Goldstein <[email protected]> Co-authored-by: Varun Saini <[email protected]> Co-authored-by: Alexander Youngblood <[email protected]> Co-authored-by: Menarul Alam <[email protected]> Co-authored-by: Aviral Goel <[email protected]> Co-authored-by: Vighnesh <[email protected]> Co-authored-by: Vyacheslav Egorov <[email protected]> Co-authored-by: Ariel Weiss <[email protected]> Co-authored-by: Ilya Rezvov <[email protected]>
Sync to upstream/release/701 (#2099) Hello everyone! This week we have type inference improvements for refinements and user-defined type functions as well as new optimizations in Native Code Generation. Merged earlier, but now available in the release are implementations of [math.isnan, math.isinf and math.isfinite for Math Library](https://rfcs.luau.org/math-isnan-isfinite-isinf.html) RFC and long awaited [Explicit type parameter instantiation](https://rfcs.luau.org/explicit-type-parameter-instantiation.html) RFC! ### What's New - Fixed a bug that incorrectly allowed chained aliases to depend on aliases defined in deeper directories - Added an optional `to_alias_fallback` C API to natively support host-injected aliases - Fixed building fuzzers using make - Fixed serialization of userdata type mappings from `userdataTypes` compiler option which caused a crash on bytecode load ## Analysis - Recursion counters have been added to the non-strict mode typechecker to prevent crashes - Irreducible user-defined type functions are now marked as solved, improving consistency of type inference results - Refinements against `unknown` type now work more consistently, resulting in more accurate inference ```luau --!strict local Class = {} Class.__index = Class type Class = setmetatable<{ A: number }, typeof(Class)> function Class.Foo(x: Class, y: Class, z: Class) if y == z then return end local bar = y.A -- correctly infers number instead of any end ``` ## Runtime - Added load-store optimizations for loading components of a vector in Native Code Generation (NCG). This should reduce the need to place repeatedly accessed vector components in locals and improve vector component shuffling - NCG will exit to VM earlier when unsafe environment is detected, reducing work it has to throw away - NCG will now optimize better across interrupt callback invocations; interrupts are to observe state and error/yield, general modification of VM state is not allowed in it ## Internal Contributors Co-authored-by: Andy Friesen <[email protected]> Co-authored-by: Annie Tang <[email protected]> Co-authored-by: Ariel Weiss <[email protected]> Co-authored-by: Hunter Goldstein <[email protected]> Co-authored-by: Ilya Rezvov <[email protected]> Co-authored-by: Sora Kanosue <[email protected]> Co-authored-by: Varun Saini <[email protected]> Co-authored-by: Vyacheslav Egorov <[email protected]>
Infra: validate version format before creating draft release (#2091) This should help us catch the (somewhat common) case where a release gets tagged `xyz` instead of `0.xyz`.
Sync to upstream/release/699 (#2082) Hello all! Another week, another release! # Analysis * Fixed `table.clone` in the old solver to ensure intersections of tables were being entirely cloned: prior only the _first_ table in the intersection would be copied: ```luau type FIRST = { some: string } type SECOND = FIRST & { thing: string } local b: SECOND -- c's type used to be FIRST, but should be the full type of SECOND local c = table.clone(b) ``` * Fixed `table.clone` in the old solver to be more permissive and treat a variadic return as having _at least_ one element. This works around some unfortunate behavior in the old solver version of nonstrict mode, see: ```luau -- A.luau --!nonstrict return function() return {} end -- B.luau local A = require("A") -- This line would previously error as `A` has type `() -> (...any)`, so -- we might not be providing enough parameters to `table.clone`. local _ = table.clone(A()) ``` * Fixed a bug in the new solver where error suppression was not kicking in for indexing, as in: ```luau local function f(value: any) if value ~= nil then for k = 1, #value do -- Previously this would error, claiming you cannot index into a `*error-type* | ~nil` local _ = value[k] end end end ``` * Fix the `getmetatable` type function in the new solver to accept `*error-type*` and `table` as valid type inputs. * Changed how error reporting for invalid `for ... in` loops works: for now this may result in slightly worse error messages (see the example below), but should mean error suppression is more consistent going forward: ```luau function my_iter(state: string, index: number) return state, index end local my_state = {} local first_index = "first" -- Prior we would claim `my_state` and `first_index` are of the incorrect types, -- now we claim that `my_iter` is of the incorrect type, which can be considered -- true, but is less helpful. for a, b in my_iter, my_state, first_index do end ``` # Runtime * Introduced `lua_rawgetptagged` and `lua_rawsetptagged`, as well as Lua 5.2+ compatibility macros `lua_rawgetp` and `lua_rawsetp`, to be able to perform lookups into tables using tagged or untagged `lightuserdata` without additional calls and stack manipulation. This enables a more efficient lookup way for `lightuserdata` keys similar to how `lua_rawgetfield` and `lua_rawgeti` avoid extra operations for their corresponding types. --- Co-authored-by: Andy Friesen <[email protected]> Co-authored-by: Annie Tang <[email protected]> Co-authored-by: Ariel Weiss <[email protected]> Co-authored-by: Hunter Goldstein <[email protected]> Co-authored-by: Varun Saini <[email protected]> Co-authored-by: Vyacheslav Egorov <[email protected]> --------- Co-authored-by: Varun Saini <[email protected]> Co-authored-by: Alexander Youngblood <[email protected]> Co-authored-by: Menarul Alam <[email protected]> Co-authored-by: Aviral Goel <[email protected]> Co-authored-by: Vighnesh <[email protected]> Co-authored-by: Vyacheslav Egorov <[email protected]> Co-authored-by: Ariel Weiss <[email protected]> Co-authored-by: Andy Friesen <[email protected]>
Sync to upstream/release/698 (#2070) # General Another week, another release. Happy Halloween! 🎃 ## Require - Integrate support for `.config.luau` files into `Luau.Require` as part of the [Luau-syntax configuration files RFC](https://rfcs.luau.org/config-luauconfig.html). - `is_config_present` has been replaced with `get_config_status`. - `get_luau_config_timeout` has been added to configure extraction timeouts at runtime. - Enable support for `.config.luau` files in `luau` and `luau-analyze`. - Merge the `Luau.RequireNavigator` static library into `Luau.Require`. ## Analysis - Add fuel-based limits for normalization: normalization will now take a set number of steps (the "fuel") and stop when we hit a certain number of steps ("run out of fuel"). This is in lieu of trying to check static limits on the size of its inputs. This may result in seeing more "code too complex" errors but should dramatically reduce the number of cases where Luau becomes unresponsive and uses several gigabytes of memory. We plan to tune this limit over time to find the right balance between responsiveness and completeness. - Fix a case where refining a variable with the type `any` would cause it to become `unknown` instead due to normalization not preserving `any` in the top type position. - Improve the wording of type errors in the new non-strict mode. - Fix #1910. - Fix #2065. - Fix #1483. - Fix #2018. ## Miscellaneous - Introduce `Luau::overloaded` to facilitate interacting with `Luau::Variant`. - Add type checking support to the [Luau demo](https://luau.org/demo)! --- Co-authored-by: Annie Tang <[email protected]> Co-authored-by: Ariel Weiss <[email protected]> Co-authored-by: Hunter Goldstein <[email protected]> Co-authored-by: Ilya Rezvov <[email protected]> Co-authored-by: Sora Kanosue <[email protected]> Co-authored-by: Varun Saini <[email protected]>
Sync to upstream/release/697 (#2058) Another somewhat small release as we work our way up to the next stage of the new type solver! # General * Implement configuration extraction as per the [Luau-syntax configuration files RFC](https://github.com/luau-lang/rfcs/blob/master/docs/config-luauconfig.md): we now expose a low-level `extractConfig` API and a higher level `extractLuauConfig` API for extracting configurations from these files. The runtime and analysis integrations with `require`, for this feature, are coming in a later release. # Analysis * Implemented native stack guards: on Windows and MacOS spots where we attempt to guard against stack overflows by using a counter now _also_ check whether we are close to hitting the runtime stack limit via OS specific APIs. * Fix a performance issue that could occur when trying to reduce type functions for math operations in the new solver, causing the new solver to fail to solve all constraints and take a disproportionate amount of time to finish solving. * Improve the new solver's non-strict checking performance when checking exceptionally large function calls and function definitions. --------- Co-authored-by: Varun Saini <[email protected]> Co-authored-by: Alexander Youngblood <[email protected]> Co-authored-by: Menarul Alam <[email protected]> Co-authored-by: Aviral Goel <[email protected]> Co-authored-by: Vighnesh <[email protected]> Co-authored-by: Vyacheslav Egorov <[email protected]> Co-authored-by: Ariel Weiss <[email protected]> Co-authored-by: Andy Friesen <[email protected]>
Sync to upstream/release/696 (#2050) Hey everyone. In preparation for the next phase of the New Type Solver rollout, we have another round of important bugfixes. We've also got a few improvements to the new require alias machinery and a little optimization to native codegen. ## New Type Solver * Fix a case where Luau would erroneously simplify `{} & { p: number | string }` to `number`. * Fix a crash that could occur within generic substitution. TODO: Sora to help word this. * Fix a case where Luau would infer a spurious union type as the result of a `setmetatable` call. * Fix #1803 * Improve bidirectional inference of table literals in the case that the expected type has an indexer. ## Luau.Require * Zero-initialize `luarequire_Configuration` function pointers before user initialization * Error if ambiguity is detected during alias discovery ## Native Codegen * Do not replace known constant value with a load propagation in STORE_TVALUE --------- Co-authored-by: Annie Tang <[email protected]> Co-authored-by: Hunter Goldstein <[email protected]> Co-authored-by: Sora Kanosue <[email protected]> Co-authored-by: Varun Saini <[email protected]> Co-authored-by: Vyacheslav Egorov <[email protected]>
Sync to upstream/release/696 (#2050) Hey everyone. In preparation for the next phase of the New Type Solver rollout, we have another round of important bugfixes. We've also got a few improvements to the new require alias machinery and a little optimization to native codegen. ## New Type Solver * Fix a case where Luau would erroneously simplify `{} & { p: number | string }` to `number`. * Fix a crash that could occur within generic substitution. TODO: Sora to help word this. * Fix a case where Luau would infer a spurious union type as the result of a `setmetatable` call. * Fix #1803 * Improve bidirectional inference of table literals in the case that the expected type has an indexer. ## Luau.Require * Zero-initialize `luarequire_Configuration` function pointers before user initialization * Error if ambiguity is detected during alias discovery ## Native Codegen * Do not replace known constant value with a load propagation in STORE_TVALUE --------- Co-authored-by: Annie Tang <[email protected]> Co-authored-by: Hunter Goldstein <[email protected]> Co-authored-by: Sora Kanosue <[email protected]> Co-authored-by: Varun Saini <[email protected]> Co-authored-by: Vyacheslav Egorov <[email protected]>
PreviousNext