Skip subtyping reasoning that is never read - #2992
Conversation
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.
|
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. |
|
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! |
| LUAU_FASTFLAG(LuauRefactorStringSemanticSubtyping) | ||
| LUAU_FASTFLAG(DebugLuauParseExactTables) | ||
| LUAU_FASTFLAG(DebugLuauExactTableTypes) | ||
| LUAU_FASTFLAG(LuauFixSuperNegationTypePaths) |
There was a problem hiding this comment.
what was the issue when this flag is off?
There was a problem hiding this comment.
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
left a comment
There was a problem hiding this comment.
approved, with a few comments. Once those are good to go, we can merge this in :)
SubtypingResultprepends aTypePathcomponent 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 checksisSubtypefirst. Likewise,T <: A | Bmerges each failing option's reasoning into its result and then clears it before returning.Under the
LuauSubtypingSkipUnreadReasoningfflag, it now skips both:withSubComponent,withSuperComponent,withSubPathandwithSuperPathreturn early on a successful result, andisContravariantWith/isInvariantWithno longer attach a variance marker to oneThe reasoning of a failing result, and so every error message, is unchanged;
Luau.UnitTestpasses with default flags and with--fflags=true.successful_subtyping_has_no_reasoningcovers the new invariant: a successfulnumber <: ~stringused to come back carrying aNegatedpath.On a 12.7k-module Roblox codebase (new solver, all flags on), a CPU profile of a full check puts 23% of samples in
TypePathvector copies,SubtypingReasoningsets andPath::operator==. Measured through a language server pinned to 0.733 with the same change applied, interleaved runs, median: