-
Notifications
You must be signed in to change notification settings - Fork 463
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Speed up record inclusion check. #6289
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very clever!
This PR actually makes me wonder why upstream does Ctype.equal nested. Obviously, for a record with many fields, it would be very slow.
Great work! 🎉 There is another place where compare_records is invoked (in compare_constructor_arguments). Should that be adapted, too? |
@mununki could you check what https://github.com/mununki/benchmark-rescript-records gives when running this PR? |
It's clear that performance has improved under the same conditions.
|
Speed up record inclusion check. Fixes #6284 Record inclusion check (between implementation and interface) is quadratic. Example: ```res module M : { type t<'a, 'b, 'c> = {x:list<('a, 'b)>, y:int, z:int} } = { type t<'a, 'b, 'c> = {x:list<('a, 'c)>, y:int, z:int} } ``` The algorithm tries to instantiate type parameters. It only reports an error if there is an inconsistency. This requires solving type equations involving many types at once. To improve error message, the first problematic field is reported. So the type equations are checked again and again with size 1, 2, ...n where n is the number of fields. (Plus the type parameters). This is quadratic and is problematic for types of ~1K elements. This PR provides a fast path which just checks if there is an error, without blaming a specific field. The fast path is linear. Only if an error is detected, the quadratic path is take to blame precisely which field is involved.
b335eef
to
cda4816
Compare
So that there's some minimal sanity check that record type inclusion works as expected on a nontrivial case.
Refactored so there's a single function now. |
One alternative would be to make this internal function incremental: let eqtype_list rename type_pairs subst env tl1 tl2 =
univar_pairs := [];
let snap = Btype.snapshot () in
try eqtype_list rename type_pairs subst env tl1 tl2; backtrack snap
with exn -> backtrack snap; raise exn so it would not slow down even for the error case. However it would be more complicated. |
Speed up record inclusion check.
Fixes #6284
Record inclusion check (between implementation and interface) is quadratic.
Example:
The existing algorithm tries to instantiate type parameters. It only reports an error if there is an inconsistency. This requires solving type equations involving many types at once.
To give an accurate error message, the first problematic field is reported (in this case
y
). So the type equations are checked again and again with size 1, 2, ...n where n is the number of fields. (Plus the type parameters).This is quadratic and is problematic for records of ~1K fields.
This PR provides a fast path which just checks if there is an error, without blaming a specific field. The fast path is linear.
Only if an error is detected, the quadratic path is take to blame precisely which field is involved.