Skip to content
This repository was archived by the owner on Dec 27, 2025. It is now read-only.

sync#2

Open
cheesycod wants to merge 661 commits into
mluau:primaryfrom
luau-lang:primary
Open

sync#2
cheesycod wants to merge 661 commits into
mluau:primaryfrom
luau-lang:primary

Conversation

@cheesycod

Copy link
Copy Markdown

No description provided.

annieetang and others added 30 commits March 25, 2026 09:44
Adds and uses `assert.that(value: unknown, msg: string?): Failure?` in
lieu of places we have `assert.eq(_, true)`

We considered naming this `assert.true` and `assert.truthy`, but agreed
on `assert.that` since it's the [new (suggested) API for
NUnit](https://docs.nunit.org/articles/nunit/writing-tests/assertions/assertion-models/constraint.html)
)

We've defined a version string in CMake, which gets turned into a header
that C++ commands can consume. However, the code in lute uses a
hardcoded version of this string. We need to expose this information to
the cli commands so that they can use the correct version when setting
up new projects or generating type definition files.

This PR sets up a global table called `version` with shape: `{version:
string, versionFull : string, versionSuffix : string}` for consumption
_exclusively_ by the CLI commands. User code and code loaded by various
lute apis in the tests cannot use this global (as those are sandboxed
environments).
Fix #643 `TOML` `deserialization` of quoted keys containing dots, which
were incorrectly split into separate keys.
Adds quote-aware path splitting for `deserialization` and key quoting
for `serialization` so round-trips preserve structure.

Now we can run this code:
```luau
local pp = require("@batteries/pp")
local toml = require("@batteries/toml")

local content = [=[
[assets.package]
assetId = "120786139379662"

[images."icon.png"]
assetId = "95124518202499"
hash = "fac185770cf5e824d4c0a9b59e547df42dc10011c5ad139bfc2c7e1507eef631"
]=]

local deserialized = toml.deserialize(content)
local serialized = toml.serialize(deserialized)

print("\nDeserialized:")
print(pp(deserialized))
print("\nSerialized:")
print(serialized)
```

and get:
```console
Deserialized:
{
  assets = {
    package = {
      assetId = "120786139379662",
    },
  },
  images = {
    ["icon.png"] = {
      assetId = "95124518202499",
      hash = "fac185770cf5e824d4c0a9b59e547df42dc10011c5ad139bfc2c7e1507eef631",
    },
  },
}

Serialized:

[assets.package]
assetId = "120786139379662"

[images."icon.png"]
hash = "fac185770cf5e824d4c0a9b59e547df42dc10011c5ad139bfc2c7e1507eef631"
assetId = "95124518202499"
```
updating path types and query to PascalCase
Right now, users have to write something like this to get `require`
calls([example](https://github.com/luau-lang/lute/blob/e0faf05ee8d274be25c9e686e95c88af42d9589c/examples/query.luau#L7)):
```luau
local requireCalls = query
    .findallfromroot(ast, utils.isExprCall)
    :filter(function(call)
        local calledFunc = call.func
        return calledFunc.tag == "global" and calledFunc.name.text == "require"
    end)
```

writing their own
`helpers`([example](https://github.com/luau-lang/lute/blob/e0faf05ee8d274be25c9e686e95c88af42d9589c/lute/cli/commands/lint/rules/unused_variable.luau#L19)):
```luau
local function isRequireCall(expr: syntax.AstExpr)
  return expr.tag == "call" and expr.func.tag == "global" and expr.func.name.text == "require"
end
```

It would be nice if `utils` had `utils.isRequireCall`. 
Then it would be simplified to:
```luau
local requireCalls = query.findallfromroot(ast, utils.isRequireCall)
```


Thanks to @Vighnesh-V for
[highlighting](https://github.com/luau-lang/lute/pull/878/changes#r2934146238)
the issue and @skberkeley for the `API`
[suggestion](https://github.com/luau-lang/lute/pull/878/changes#r2934155678).

---------

Co-authored-by: Vighnesh Vijay <vvijay@roblox.com>
If you try to run the `process` example, an error throws:
```
0
Hello, lute!

@std/task.luau:60: attempt to index number with 'success'
stacktrace:
@std/task.luau:60 function awaitall
./examples/process.luau:15
```

This occurs as we iterate over `tasks`, which is equal to a `table.pack`
return value. This means `tasks` has an `n` property and is not entirely
array-like. We can use `ipairs` when iterating over `tasks` to avoid the
bug
…ed by `@lute/time` (#900)

We've had a long-standing split between `@std/time` and `@lute/time`
where the former provided an entirely userland implementation of
duration, but the latter provided both durations and instants from C++.
In the interest of getting the standard library generally into shape and
avoiding these confusing duplications (with differences!) between the
runtime and the standard library, this PR eliminates the `@std/time`
that already exists, and replaces it with one that re-exports the
runtime functionality. Making this a proper replacement required both
implementing `__mul` and `__div`, as well as fixing a number of smaller
bugs that were scattered throughout the runtime implementation of
duration.
Adds explicit `jumpToAlias` implementations to support FileVfs handling
unprefixed relative paths in configuration files.

Earlier, we were able to get away with reusing the same `resetToPath`
function for both resetting to a path (such as when initializing FileVfs
to point to the project entry point script) and for jumping to aliases.
We now need to split these back into two different implementations
(although, there is a good amount of logic reused) because the "reset"
path requires us to resolve relative paths from the current working
directory, but the "jumpToAlias" path requires us to resolve them
relative to the .luaurc/.config.luau in which they were defined.

This must be done here and not in Luau.Require, as Luau.Require relies
on prefixes to determine path type. The absence of a prefix in this case
means that the embedder (Lute) must be responsible for path resolution.
…heck` (#862)

This PR ensures that `lute check` correctly resolves and uses embedded
source code for the `@std`, `@lute`, and `@batteries` namespaces during
static analysis.

Previously, `lute check` used a basic file resolver that only searched
the physical disk. Since Lute's standard library and runtime definitions
are embedded directly into the executable, `require` calls to these
namespaces would fail to resolve. This caused Luau to treat standard
modules as `any`, effectively disabling typechecking for code that
relied on Lute's built-in APIs.

- **Refactored `resolveRequire`**: Updated the core resolution logic in
`lute/luau/src/resolverequire.cpp` to support both physical disk and
virtual embedded paths.
- **Implemented `readSourceFromVfs`**: Added a utility to retrieve
source code directly from Lute's internal memory buffers when an `@`
alias is used.
- **Updated Resolvers**: Integrated the new resolution and reading logic
into `LuteModuleResolver` and `LuteFileResolver`.
- **Build System Integration**: Updated `lute/luau/CMakeLists.txt` to
link the analysis library against `Lute.Std`, `Lute.Lute`, and
`Lute.Batteries`, ensuring the embedded sources are available at compile
time.
- **Improved Global Registry**: Ensured the `require` function is
correctly recognized as a built-in global during the analysis phase.

Fixes #773

---------

Co-authored-by: Master Oogway <ActualMasterOogway@users.noreply.github.com>
Co-authored-by: Vighnesh Vijay <vvijay@roblox.com>
This PR adds documentation that summarizes a) how to write tests, b) how
to run tests, c) how to organize your tests using suites.

I've also explicitly called out testing as part of the cool developer
tooling we've built, and linked it in the CLI reference. The plan for
the Developer Tooling section is to extend it with blurbs about `lute
lint`, `lute check`, and `lute compile` (and any others that we add).
When working on cleaning up `lute doc` with `typeofmodule` API
integration, I noticed that function type serialization was missing the
`argNames` fields, so we weren't preserving the argument names of the
parameters in function types. This makes it hard for users (aka the
`lute doc` command) to use the type serialization on function types
because our output would be missing the argument names and only have the
types, which isn't very useful to understand the function signature.

Before this change, using the type serializer to generate docs would
result in (the wip) `fs.link` serialization appearing as:

```luau
fs.link

(string, string) -> ()
```

But after this change, we have:

```luau
fs.link

(src: string, dest: string) -> ()
```

which better matches the actual function signature of of fs.link, which
is

```luau
function fs.link(src: string, dest: string): ()
```

Pls see more examples of this specific change's additions (in my [WIP
branch](https://github.com/luau-lang/lute/compare/annietang/lute_doc_integration_with_typeofmodule)
of `lute doc`) if curious:
9488009
…ssert.throwsWith` (#905)

following naming convention from
[NUnit](https://docs.nunit.org/articles/nunit/writing-tests/assertions/classic-assertions/Assert.Throws.html)

`assert.errors` renamed to `assert.throws<...T>: function, ...T`
`assert.errorseq` renamed to `assert.throwsWith<...T> : (with : any,
function, ...T)`
**Luau**: Updated from `0.713` to `0.714`

**Release Notes:**
https://github.com/luau-lang/luau/releases/tag/0.714

---
*This PR was automatically created by the [Update Luau
workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)*

Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
Co-authored-by: Sora Kanosue <kanosuesora@gmail.com>
**Lute**: Updated from `0.1.0-nightly.20260320` to
`0.1.0-nightly.20260327`

**Release Notes:**
https://github.com/luau-lang/lute/releases/tag/0.1.0-nightly.20260327

---
*This PR was automatically created by the [Update Luau
workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)*

Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
Achieved via a combination of refactoring, casts, and annotations. The
remaining ones should be addressed/addressable when we bump Luau to
0.716.
The typechecker was flagging an actual error in the luau code, which is
that the table we were creating to represent filtered test suites was
missing properties. Although the testing framework never uses these
properties (as they are index metatable methods that are used to
register test cases), they are in fact missing, which can cause errors
if they are accesses down the road. This PR just table.clones these
testsuites and updates their test cases explicitly to the list of
filtered test cases.
Moved the `profiler options` from the `CLI` directly into the
`profiler`. Currently, the sampling `frequency` in Hz duplicates its
default value in two places:
[here](https://github.com/luau-lang/lute/blob/6ed3142c96d109a7ac94ec7c9a7d8dc86a56ac69/lute/cli/src/profiler.cpp#L53)
and
[here](https://github.com/luau-lang/lute/blob/6ed3142c96d109a7ac94ec7c9a7d8dc86a56ac69/lute/cli/include/lute/climain.h#L13).
It has no impact at the moment, but having a single source will help
avoid potential bugs in the future.

Originally a minor change in PR #911, this has been moved to a separate
PR for better clarity.

Besides, in PR #911 the main logic of `runBytecode` was moved from `CLI`
to `Runtime`, so we don't need the `profiler` dependency in the `CLI` at
all.
Part of a larger refactor of AST types where we want property names to
be camelCased
Part of a larger refactor of AST types so that property names are
camelCased
Part of a larger refactor of AST types so property names are camelCased
…ableeq` and `buffereq` (#904)

Updates `assert.eq` to perform structural equality, calling
`assert.tableeq` and `assert.buffereq` to simplify user experience for
the assertion library. We also unexpose `tableeq`, `buffereq` so users
only need to use `assert.eq` to test equality

Updates tests and snapshots to reflect changes
…#906)

This PR exposes the `task` library methods in `@std` as wrappers around
the task methods in `@lute`. I've left in the previous implementations
of `task.await/awaitAll/create` for now, because we're still exposing
the superset that users would expect of the roblox api.
- camelCases the members of the stringext library.
- `local stringext = require("@std/stringext') -> local stringExt =
require("@std/stringext")` - not strictly required, but I just feel like
it's better.
afujiwara-roblox and others added 30 commits July 6, 2026 16:55
Summary
  
- Make lute pkg install read the existing loom.lock.luau before
resolving. If the lockfile satisfies the current manifest and path
dependencies haven't changed, skip resolution entirely.
- When re-resolution is needed, the solver prefers previously-locked
registry versions to minimize version churn
- Add --locked flag that errors if the lockfile is missing or doesn't
match the manifest
The CLI battery's `help` method was showing empty parens if an option
didn't have any aliases. I added a check not to emit it if there is no
alias, and snapshot tests documenting it.
Title is self-explanatory.

I feel like I've ended up implementing bespoke versions of these quite
often in side projects, so I think they'd be useful to have. Open to
name-change ideas

---------

Co-authored-by: ariel <aweiss@hey.com>
Co-authored-by: ariel <arielweiss@roblox.com>
Updates all the lint messages that begin with "XYZ detected". Slightly
changes some wording to read better.

---------

Co-authored-by: Sora Kanosue <kanosuesora@gmail.com>
Co-authored-by: ariel <aweiss@hey.com>
Adds a non-default lint to flag on reassignment of parameters in functions.
…1181)

As part of introducing AST types to Lute, we would like AST types to
subtype structurally against CST types. However, the AST returned by the
Luau parser provides no way to distinguish between table type properties
that are bracketed and those that aren't. This means that the eventual
Lute AST will have a single type for bracketed and non-bracketed table
type properties, so the Lute CST should too.
Fixes #1172.

On Windows, `io.input()` returned the line with its trailing terminator
still
attached. That meant a path read from input would fail in `fs.open()`
with "no
such file or directory" even when the file was right there.

The cause is that `io.input()` just returned `io.read()` directly.
`io.read()`
is the raw read primitive, so it returns the bytes from stdin as-is,
including
the line terminator (`\r\n` on Windows, `\n` on Unix). I fixed it in
`io.input()` instead of `io.read()` so the raw read keeps returning
exactly
what it read, while the line-oriented helper hands back a clean string
you can
pass straight to filesystem APIs. It strips a single trailing terminator
and
leaves interior and leading whitespace alone.

I added `IoInputSuite` to `tests/std/io.test.luau`. Each case pipes a
value into
a small script so the platform's own terminator gets appended (`\r\n` on
Windows,
which is the case in #1172, and `\n` on Unix), then checks that
`io.input()`
returns the clean string. The cases cover a basic value, a path with
separators,
and preserving interior whitespace.

I verified this locally on Windows with the MSVC (VS 2022) build. The
new suite
passes and the rest of the test suite is unaffected.
**Lute**: Updated from `1.0.1-nightly.20260701` to
`1.0.1-nightly.20260710`

**Release Notes:**
https://github.com/luau-lang/lute/releases/tag/v1.0.1-nightly.20260710

---
*This PR was automatically created by the [Update Luau
workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)*

Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
**Luau**: Updated from `0.728` to `0.729`

**Release Notes:**
https://github.com/luau-lang/luau/releases/tag/0.729

---
*This PR was automatically created by the [Update Luau
workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)*

Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
Returns an array of values from a dictionary `tbl` with the keys
discarded. It would be useful for functions like `toSet`, `extend` of
`TableExt`

---------

Co-authored-by: Sora Kanosue <kanosuesora@gmail.com>
- Add overrides support to loom, allowing projects to force specific
versions or sources for any transitive dependency (similar to npm/pnpm
overrides)
- Two override modes: version pin (force an exact registry version) and
source redirect (replace a registry package with a local path or github
source)
- Lockfile version bumps to 4 only when overrides are present; projects
without overrides stay on version 3

Overrides are declared at the project root in loom.config.luau:

```
return {
    package = { ... },
    overrides = {
        -- Pin a transitive dependency to an exact version
        citrus = { sourceKind = "registry", source = "citrus", version = "3.0.0" },
        -- Or redirect to a local fork
        citrus = { sourceKind = "path", source = "./citrus-fork" },
    },
}
```

The resolver removes conflicting constraints for overridden packages,
builds a modified universe respecting the pins, and stitches
source-redirected packages back into the dependency graph after solving.
The lockfile records a fingerprint of
active overrides so changes trigger re-resolution.
Recent changes to the Luau type solver have reduced the number of code
too complex errors being emitted, meaning we can remove some any casts.
Adds a `lute self` subcommand for installing, updating, and uninstalling
lute from a well-known system location (~/.lute/bin). This gives users a
first-class way to bootstrap and maintain their lute installation
without relying on external toolchain managers.

### Subcommands

- `lute self install`: Copies the running lute binary to `~/.lute/bin`
and adds it to PATH via shell profile modifications (Unix) or the user
registry (Windows)
- `lute self update`: Queries the latest GitHub release (or a specific
`--version`) and replaces the installed binary
- `lute self uninstall`: Removes the binary directory and strips PATH
entries from all known shell profiles. Supports `--remove-data` to also
delete cached type definitions under `~/.lute`

---------

Co-authored-by: Ariel Weiss <arielweiss@roblox.com>
After #1205 was merged, I noticed
the documentation has the wrong casing for `Self` instead of `self` (see
https://lute.luau.org/cli/self.html)
This PR makes breakpoints actually functional but in order to do we need
to add many features under the hood
* as mentioned here
#1202 (review),
we need to run the child debuggee process in a separate VM.
* as a side effect of the above change, we need to instead schedule
operations (such as adding and removing breakpoints) onto the child VM,
which effectively makes them async
* we add some callbacks when breakpoints are installed or un-installed,
and when program execution terminates, and when a breakpoint is hit
* we add a `continue()` to resume program execution

Caveats:
* most of this code relies on the debugged script (`exit` and
`continue`) being single coroutine. Multi-coroutines execution will be
handled in future PRs.
Pretty straightforward, implements a `--nightly` flag to update to the
latest nightly build as opposed to the latest official release which is
currently at `1.0.0`:
https://api.github.com/repos/luau-lang/lute/releases/latest

---------

Co-authored-by: ariel <aweiss@hey.com>
The `resolve` function has gotten a little big. This PR just breaks out
the functionality to individual functions
**Lute**: Updated from `1.0.1-nightly.20260710` to
`1.0.1-nightly.20260717`

**Release Notes:**
https://github.com/luau-lang/lute/releases/tag/v1.0.1-nightly.20260717

---
*This PR was automatically created by the [Update Luau
workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)*

Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
**Luau**: Updated from `0.729` to `0.730`

**Release Notes:**
https://github.com/luau-lang/luau/releases/tag/0.730

---
*This PR was automatically created by the [Update Luau
workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)*

Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
This adds a minimal DAP adapter, which is not currently callable by the
`lute` CLI
* we handle I/O and JSON parsing correctly (and add some tests for this)
* add some minimal implementations for the debugger startup/terminate
events

If we modify Mandolin, we can connect it to VSCode
<img width="1236" height="817" alt="Screenshot 2026-07-10 at 2 11 11 PM"
src="https://github.com/user-attachments/assets/d9d280f3-bc67-4a6d-a21a-b2ad9bb341ef"
/>
While reviewing feedback for my attribute parsing PR, I realized we're
missing query tests and query visitor suppressions for some node types.
This PR adds a unit test for querying each CST node type and any needed
fixes.
Remove print statements since they're polluting test output. We'll need
to introduce some sort of logging library with different modes that we
can disable for tests.
I noticed lute was still using `.luaurc` and had a stray
`lint.config.luau` so I merged the two
## Summary
Adds support for user-specified type definition files in `lute check`.
Definition files (`.d.luau`) declare globals and types that are injected
into the type checker's global scope, allowing user code to reference
them without explicit imports.

## Configuration
Definition files are specified in `.config.luau` under lute.definitions
as a map:
```luau
return {
    lute = {
        definitions = {
            roblox = "./types/roblox.d.luau",
            custom = "./types/custom-globals.d.luau",
        },
    },
}
```
Run `clang-format` (v22.1.8) on `runtime` as a part of splitting
#1233 into three.
`@std/syntax/visitor` was missing methods for `visitStat`, `visitType`,
and `visitTypePack`.
Previously, we used `resumeTokens` to do pausing in the debugger. This
is unsustainable for multi-coroutine applications. Instead, we introduce
a`debugMode` to `Runtime` that enables pausing all coroutines at once.
We also add a `pauseProcess` method in the debugger itself that can be
called outside of breakpoints.

The pausing pathway is now:
1. Trigger the presently queued running coroutine to break out of
execution. The easiest way to do this is to set a callback in the VM and
then call `lua_break`
2. Use the runtime's `stopDebug()` to actually stop queuing of further
coroutines.
Added some additional testing to breakpoints + resolved one potential
timing issue in `setBreakpoint`
Create initial bindings for `lute/debug` to Luau, which primarily
focuses on breakpoint behavior.

- Add some basic Luau tests
- A definitions file for the library for type checking
- Renames `debugger.cpp` to `debuginternals.cpp` to more clearly
separate out the bindings from internal implementation
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.