Skip to content

Infer with-kinds for GADTs, using Tof_kind for existentials #3814

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

Open
wants to merge 27 commits into
base: aspsmith/of-kind
Choose a base branch
from

Conversation

glittershark
Copy link
Member

@glittershark glittershark commented Apr 4, 2025

Infer full with-kinds for GADTs, using the new Tof_kind type to stand-in for existential type variables.

There's a big Note in jkind.ml explaining the approach here; see that for an overview.

Review all in one go, commit history is mostly not useful.

@glittershark glittershark requested a review from goldfirere April 4, 2025 20:54
@glittershark glittershark force-pushed the aspsmith/with-kinds-for-gadts branch 3 times, most recently from 0d39428 to a04fc56 Compare April 7, 2025 13:20
Copy link
Collaborator

@goldfirere goldfirere left a comment

Choose a reason for hiding this comment

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

I have done some light review and have concerns, sadly. I just don't think we're going to get away this easily. Might be worth checking in with Leo or Stephen to see if they have wisdom we do not.

@glittershark glittershark force-pushed the aspsmith/with-kinds-for-gadts branch from 402aac2 to a4663a2 Compare April 14, 2025 20:36
Copy link

github-actions bot commented Apr 14, 2025

Parser Change Checklist

This PR modifies the parser. Please check that the following tests are updated:

  • parsetree/source_jane_street.ml

This test should have examples of every new bit of syntax you are adding. Feel free to just check the box if your PR does not actually change the syntax (because it is refactoring the parser, say).

@glittershark glittershark force-pushed the aspsmith/with-kinds-for-gadts branch 4 times, most recently from f0934ab to dc43483 Compare April 15, 2025 18:03
@glittershark glittershark force-pushed the aspsmith/with-kinds-for-gadts branch from bc77351 to a90f40f Compare April 15, 2025 18:14
@glittershark glittershark changed the base branch from main to aspsmith/of-kind April 15, 2025 18:15
@glittershark glittershark changed the title Infer with-kinds for GADTs, avoiding existentials Infer with-kinds for GADTs, using Tof_kind for existentials Apr 15, 2025
@glittershark glittershark requested a review from goldfirere April 15, 2025 19:19
@glittershark glittershark marked this pull request as ready for review April 15, 2025 19:19
Comment on lines +263 to +268
Error: The kind of type "existential_abstract" is immutable_data
with (type : value mod portable) abstract
because it's a boxed variant type.
But the kind of type "existential_abstract" must be a subkind of
immediate
because of the annotation on the declaration of the type existential_abstract.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would be kinda cool to have

Suggested change
Error: The kind of type "existential_abstract" is immutable_data
with (type : value mod portable) abstract
because it's a boxed variant type.
But the kind of type "existential_abstract" must be a subkind of
immediate
because of the annotation on the declaration of the type existential_abstract.
Error: The kind of type "existential_abstract" is
immutable_data with (type : value mod portable) abstract
because it's a boxed variant type.
But the kind of type "existential_abstract" must be a subkind of
immediate
because of the annotation on the declaration of the type existential_abstract.

but not worth a lot of effort if that's hard. (This is just a change in spacing/newlines.)

val foo2 : M.t @ contended -> unit
end
|}]

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe add tests here like

module F3(M : S with type 'a b = 'a) = struct
  type t : value mod portable = M.t
  let foo (x : t @ nonportable) = use_portable x
end

and

module F4(M : S with type 'a b = 'a) = struct
  let foo (x : t @ contended) = use_uncontended x
end


(* Demonstrate that this is only a printing issue *)
type _ box : immediate = Box : 'a -> 'a box

Copy link
Collaborator

Choose a reason for hiding this comment

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

Would be cool to demonstrate the asymmetry of the kind of box2. That is, I think (int, int ref) box2 will mode-cross contention, while (int ref, int) box2 will not. (Yes, I know both of these are uninhabited, but that's not the interesting detail here.)

@@ -315,3 +317,29 @@ let unboxed_labels_of_type ty_path decl =
labels rep decl.type_private
| Type_record _
| Type_variant _ | Type_abstract _ | Type_open -> []

let constructor_unbound_type_vars_excluding_row_variables cstr =
Copy link
Collaborator

Choose a reason for hiding this comment

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

Much of this computation duplicates work in for_boxed_variant. Maybe just inline this? That is, you traverse the result args to find all the bare Tvars, stored in a list. This list will be matched with the params in the call to apply. But it also can be turned into a set and subtracted from the free variables of the entire constructor. This approach has the nice property of making it even clearer that every variable free in a constructor's fields gets substituted away by the apply, either to a param or to a Tof_kind.

Copy link
Collaborator

@goldfirere goldfirere Apr 16, 2025

Choose a reason for hiding this comment

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

I think you'd probably need to pass Ctype.free_vars (or Btype.free_vars? not sure about the difference) into for_boxed_variant. That's a small shame.... but certainly no worse than the forward-declaration of this function.

let arg_vars_set =
free_vars
~include_row_variables:false
(newgenty (Ttuple (List.map (fun ty -> None, ty) tyl)))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Tupling here is, I believe, more efficient than mapping and set-unioning. Might be nice to have a comment explaining why do this (because, to me, mapping and set-unioning is a more direct statement of what you're trying to do).

typing/ctype.ml Outdated
jkind
|> Jkind.disallow_right
(* [Tof_kind] stands in for an existential type, which always have best kinds *)
|> Jkind.mark_best
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can't we arrange just to mark these best upon construction? I think that's better than doing it here.

Copy link
Member Author

Choose a reason for hiding this comment

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

not trivially, since best jkinds can't be lr. Should we relax that requirement?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants