Skip to content

Skip subtyping reasoning that is never read - #2992

Merged
Vighnesh-V merged 2 commits into
luau-lang:masterfrom
Pyseph:subtyping-skip-unused-reasoning
Sep 28, 2026
Merged

Vighnesh-V merged 2 commits into
luau-lang:masterfrom
Pyseph:subtyping-skip-unused-reasoning

Conversation

@Pyseph

@Pyseph Pyseph commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

SubtypingResult prepends a TypePath component to its reasoning at every level of a subtyping test, including on results that turn out to be subtypes. That reasoning, however is never read -- every caller which explains a failure checks isSubtype first. Likewise, T <: A | B merges each failing option's reasoning into its result and then clears it before returning.

Under the LuauSubtypingSkipUnreadReasoning fflag, it now skips both:

  • withSubComponent, withSuperComponent, withSubPath and withSuperPath return early on a successful result, and isContravariantWith/isInvariantWith no longer attach a variance marker to one
  • the union loop clears each failing option's reasoning instead of merging it

The reasoning of a failing result, and so every error message, is unchanged; Luau.UnitTest passes with default flags and with --fflags=true. successful_subtyping_has_no_reasoning covers the new invariant: a successful number <: ~string used to come back carrying a Negated path.

On a 12.7k-module Roblox codebase (new solver, all flags on), a CPU profile of a full check puts 23% of samples in TypePath vector copies, SubtypingReasoning sets and Path::operator==. Measured through a language server pinned to 0.733 with the same change applied, interleaved runs, median:

flag off flag on
full check, 12.7k modules, 16 threads: CPU 446 s 398 s -11%
full check, 12.7k modules, 16 threads: wall 37.3 s 33.0 s -11%
two cold ~2.5k-module require closures, 1 thread: CPU 25.5 s 23.3 s -9%

A successful SubtypingResult's reasoning is never read, yet every with*Component/Path call
built TypePath entries for it, and T <: A | B merged each failing option's reasoning only to
clear it. Both are skipped under LuauSubtypingSkipUnreadReasoning; failing results, and so
error messages, are unchanged.
@Pyseph
Pyseph marked this pull request as ready for review September 26, 2026 15:38
@Pyseph
Pyseph requested a review from a team as a code owner September 26, 2026 15:38
@Pyseph
Pyseph requested a review from max-au September 26, 2026 15:38
@Vighnesh-V
Vighnesh-V self-requested a review September 26, 2026 20:07
@Vighnesh-V

Copy link
Copy Markdown
Contributor

Clever! We've been running into problems w/ subtype reasoning perf too. 10% perf improvement is huge. The PR broadly looks good (I took a look this morning), but I will do a more detailed review on Monday.

@Pyseph

Pyseph commented Sep 26, 2026

Copy link
Copy Markdown
Contributor Author

Thank you! id love to dig further into the existing perf. bottlenecks in the new solver, as its behind ~95% of our in-house luau lsp's clock time, but i understand the need for brevity & wanting the team to handle it instead of outside PRs. would love to know if this is anything i can continue poking at!

Comment thread Analysis/src/Subtyping.cpp Outdated
Comment thread tests/Subtyping.test.cpp Outdated
LUAU_FASTFLAG(LuauRefactorStringSemanticSubtyping)
LUAU_FASTFLAG(DebugLuauParseExactTables)
LUAU_FASTFLAG(DebugLuauExactTableTypes)
LUAU_FASTFLAG(LuauFixSuperNegationTypePaths)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what was the issue when this flag is off?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing, it turns out: with it off, isCovariantWith(..., superNegation) adds the Negated component once at the end rather than per branch, so a successful number <: ~string carries the same reasoning either way. I've dropped it from the test, which still fails without LuauSubtypingSkipUnreadReasoning with that flag on or off.

@Vighnesh-V Vighnesh-V left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approved, with a few comments. Once those are good to go, we can merge this in :)

@Vighnesh-V
Vighnesh-V merged commit 0e6da1a into luau-lang:master Sep 28, 2026
13 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

Development

Successfully merging this pull request may close these issues.

2 participants