Skip to content

Expand aliases if necessary during immediacy computation (third attempt)#11841

Closed
ccasin wants to merge 10 commits intoocaml:trunkfrom
ccasin:rebase-10041
Closed

Expand aliases if necessary during immediacy computation (third attempt)#11841
ccasin wants to merge 10 commits intoocaml:trunkfrom
ccasin:rebase-10041

Conversation

@ccasin
Copy link
Copy Markdown
Contributor

@ccasin ccasin commented Dec 28, 2022

This is a rebased version of @stedolan's #10041 (which itself was an alternate approach to #10017 - good discussions in both of those PRs).

To copy the original description: "The major change is to entirely remove the fixpoint computation in typedecl_immediacy.ml which computed the type_immediacy field of each named type. Instead, the immediacy of abstract types is represented as a parameter to the Type_abstract kind. Immediacy is checked when the type is defined rather than being inferred.

Removing the type_immediacy field fixes the bugs in #10017: the bugs arise because the contents of this field becomes stale after substitutions."

Following @stedolan's approach, this is broken into a few commits. The first is boring mechanical changes. The second has the main substantive changes. The third is a minor piece of related cleanup that seemed appropriate here (but could be deleted if it's undesirable for any reason).

Looking back at the discussion in #10041, I think there were two main pieces of remaining feedback:

  • check_type_immediate could be clarified by splitting it into two functions and eliminating the recursion. That's done here (folded into the second commit).
  • It might be possible to combine get_unboxed_type_representation and try_expand_once_opt. This might be an improvement, but seems somewhat orthogonal to the main purpose of this PR, so I suggest investigating it separately.

(cc @gasche - sorry it took me so long to get to this)

@gasche
Copy link
Copy Markdown
Member

gasche commented Dec 29, 2022

Thanks! I am on vacation right now (until January 3rd) but I hope to look at this shortly.

Copy link
Copy Markdown
Member

@gasche gasche left a comment

Choose a reason for hiding this comment

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

I started reviewing this PR, and I realize that the first commit does not build. If you think that this should be best reviewed commit-by-commit (I think it was initially intended this way), then it would be nice to ensure that each commit builds separately. Or should we rather look at the whole diff at once?

@ccasin
Copy link
Copy Markdown
Contributor Author

ccasin commented Jan 12, 2023

To quickly answer the question about how to review: I debated whether to preserve the multi-commit structure of Stephen's original PR (which also had the property that the first commit didn't build). It's unfortunately tricky to make that commit have sensible behavior, because the boring changes are plumbing related to removing the old immediacy system and adding the spot for immediacy information in type_kind, but you need the interesting bits from the second commit to actually put sensible information in that new spot.

I decided to keep the split because there are really quite a lot of these "boring" changes, and isolating the interesting parts into the second commit felt possibly useful, but feel free to review it all at once if that's easier.

Copy link
Copy Markdown
Member

@gasche gasche left a comment

Choose a reason for hiding this comment

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

I reviewed the third commit (refactoring), and I agree it is an improvement. See minor inline comments. (Now I have the second commit left to look at.)

Copy link
Copy Markdown
Member

@gasche gasche 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 now reviewed the "substantial changes" commit -- the last commit I hadn't reviewed yet. See inline comments.

Reading this code again reminded me that I would prefer to change the immediacy lattice to include the "not immediate" case, which would clarify the code (and optimize the computation in some corner cases). I talk a bit about it in my review comments, but I consider this as future work, not a requested change in the context of the present PR.

| Type_variant (cstrs, _) ->
if List.exists (fun c -> c.Types.cd_args <> Types.Cstr_tuple []) cstrs
then Type_immediacy.Unknown
else Type_immediacy.Always
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

(This is a "thinking out loud" remark with no actual change suggestions for the present PR, apologies for the noise.)

In this function I find the use of Type_immediacy.Unknown perplexing, because that immediacy is supposed to mean "we don't know whether the type is immediate or not" (it is the immediacy of an abstract type with no immediacy annotation on it), but we use it here for types that we know are not immediate. I would rather expect a Type_immediacy.Never value in this case.

I vaguely remember that I proposed such a "not immediate" immediacy to @stedolan in one of the earlier attempts (in the context of a fairly different approach to computing and checking immediacies), and that he was not convinced. I still think that it would be more natural than the code we write here -- or in other parts of the immediacy computation.

On the other hand, having this should not be a requirement for the present PR, whose scope is to make the computation of immediacy "on-demand" rather than store it for each type. I am not suggesting that it must be added now, I think it could be something to consider for another PR.

Currently immediacies form a lattice

Immediate <= Immediate64 <= Unknown

and we would have instead

Immediate <= Immediate64 <= Unknown
NonImmediate <= Unknown

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.

I agree it would great to have a way to record that types are never immediate.

In addition to clarifying this code, it could be a performance win - as you observed below, the immediacy recorded in type kinds is an upper bound, so when we see Type_immediacy.Unknown on a type abbreviation we sometimes expand the manifest to check whether the upper bound was conservative. This is potentially expensive, and could be skipped if we had a way to record types were NonImmediate even after substitutions. We've been considering different designs for this in the context of our "unboxed types" prototype (which essentially just expands the lattice you suggest with still more options - different "layouts"), but haven't settled on anything and plan to revisit it in the future.

| Ok () -> Ok ()
| Error _ ->
let ty = get_unboxed_type_representation env ty in
Type_immediacy.coerce (type_immediacy_head env ty) ~as_:imm
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I find the logic here a bit strange. One may think of type_immediacy_head as computing the immediacy of a type constructor, but its result is actually incorrect on unboxed types, which are not taken into account in kind_immediacy. So if we get a failure, we try again after calling `get_unboxed_type_represeentation.

Two questions:

  1. Why not always get the unboxed type representation first? Performance reasons, I suppose: we want to avoid expanding abbreviations, because abbreviations already carry correct immediacy information in their kind.
  2. Why not have kind_immediacy handle unboxed datatypes, so that type_immediacy_head returns the correct result for all types? Would we still need a fallback in this case? What would be the downside?

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.

Why not always get the unboxed type representation first?

You are exactly correct - this is for performance reasons. get_unboxed_type_representation is potentially expensive, so in the case of a Tconstr we first look at the kind and see if it yields a definitive answer. If not, we perform the expensive expansion and unboxing.

This optimization was already present in the previous version of this PR, but it was implemented by a recursive call in check_type_immediate in the case we needed to call get_unboxed_type_representation. That approach was somewhat confusing, so here I've incorporated a suggestion from @lpw25 from that PR to eliminate the recursion by breaking it into two functions (check_type_immediate and type_immediacy_head).

The intent, then, is that type_immediacy_head is a cheap look at the "head" of the type, which check_type_immediate tries and then calls get_unboxed_type_representation if it doesn't provide a definitive answer.

Why not have kind_immediacy handle unboxed datatypes, so that type_immediacy_head returns the correct result for all types?

kind_immediacy may return an approximation in two cases: unboxed types, and abbreviations (because the immediacy recorded on Type_abstract is a conservative upper bound, as you observe elsewhere). As the fallback in both cases is the same (check_type_immediate calls get_unboxed_type_representation), it seemed cleanest to leave the unboxing logic there.

An alternative design would be to duplicate more of the logic of get_unboxed_type_representation here. In particular, one advantage would be that we could check whether we have a definitive immediacy after each recursive step of expansion and unboxing. But as this function and its fuel parameter are somewhat unfortunate, and it sounds like there are medium term plans to replace it, my instinct is not to do this.

So, to summarize, I do think we need some fallback in any event to deal with abbreviations, and it therefore seems cleanest not to complicate kind_immediacy. But let me know if you disagree. And in any event the situation should be documented - I'll add a comment if that sounds reasonable.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I find the current state disturbing: there is a notion of "the immediacy of a kind", which would be an inexact approximation of "the immediacy of the type", but it is not what kind_immediacy currently computes. But it is not so simple to compute the "right" thing (as I suggested earlier) because it the case of unboxed datatypes we would need to recursively call type_immediacy_head.

In the short term, I thing maybe you could just add a comment to point out that kind_immediacy is incorrect on unboxed datatypes.

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.

I have changed the name to kind_immediacy_approx and added a comment to the mli.


and ('lbl, 'cstr) type_kind =
Type_abstract
Type_abstract of {immediate : Type_immediacy.t}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Note: there is a non-obvious design choice being made here, which is that abbreviations (with use Typ_abstract kind with a Some ty manifest) will carry an immediacy. One may think that it is not necessary to store an immediacy for abbreviation as it can always be computed on-demand from the definition, and only "truly abstract" types without a manifest need an immediacy. (If we wanted to go "full on-demand" we would consider that.) The current state is a compromise, which is fine with me. It may also work better in presence of type constructors that are not fully abstract but whose definition is not in the environment / has been forgotten.

But: if I understand correctly, sometimes the information in this 'immediate' field may be stale / incorrect / a pessimistic approximation. (Otherwise we would not need the fallback logic in this case in check_decl_immediate.) I think that this happens in the functor-instantation scenarios that were discussed in the previous iterations of the PR, where currently the computation of variance and other type properties is not redone after substitution.

I think this should be documented: the immediacy information in the kind here may be an imprecise approximation of the immediacy of the manifest (when available), which is the "true" immediacy of the type.

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.

Yes. I think we can end up in the conservative approximation situation even without functors (e.g., type 'a t = 'a is not immediate, but int t is). I've added a comment mentioning this and directing readers to the original motivating examples for details, but let me know if it's not quite what you wanted.

typing/ctype.ml Outdated
| Type_variant ([{cd_args = Cstr_tuple [arg]; _}], Variant_unboxed)
| Type_variant ([{cd_args = Cstr_record [{ld_type = arg; _}]; _}],
Variant_unboxed)) } ->
check_type_immediate env arg imm
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

here again, we would not need this case if kind_immediacy worked correctly with unboxed datatypes, right?

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.

Agreed - I guess I'd say there's a tradeoff, either we perform this check here, or check_type_immediate will potentially perform it twice (once in kind_immediacy and again when we fall back to get_unboxed_type_representation).

begin match Type_immediacy.coerce kind_imm ~as_:immediate with
| Ok () -> ()
| Error v -> raise(Error(sdecl.ptype_loc, Immediacy v))
end;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

One awkward thing about this function is that there is code to "check" the declaration error cases in three distinct places:

  1. the one for the unboxed attribute above
  2. the one for the immediacy attribute here
  3. the one for constraints below

Case (3) is fairly different in nature, but for cases (1) and (2) it is annoying that there is no common structure to the placement: (1) is placed right when the attribute is accessed, while (2) is placed after a bunch of non-trivial logic. There is an explanation (the check (1) is self-contained from the information already there, the check (2) requires building more of the declaration to make sense), but the code remains slightly inconsistent. If I was adding support for yet another kind of attribute, where would I put the checking code? "In a random place that works" is what the current code says.

My suggestion:

  • move the logic of both checks (1) and (2) to auxiliary functions, verify_unboxed_attr and verify_immediacy_attr or something
  • call both those functions at the same place in the code, for example at the current point (2) or after the let decl = ... in declaration.

I think this would make the code both more readable and easier to extend.

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.

Agreed - that does sound better. I'll take a stab at this tomorrow.

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.

I made the change you suggested. However, while doing so, I realized there remains an issue. In particular, this PR will reject the following declaration which is accepted by current ocaml.

type t = { x : int } [@@unboxed] [@@immediate]

This behavior is present in the previous iteration of this PR (#10041) but I suppose was not noticed at that time. As the issue is that kind_immediacy does not traverse through @@unboxed, I feel this somewhat vindicates your unhappiness with that function :).

I can think of a few solutions. The most obvious is to rename kind_immediacy to something like kind_immediacy_approx, and write a new kind_immediacy that does unbox things. I think this new function would need to call get_unboxed_type_representation if it sees an unboxed type - unboxing just one level is potentially insufficient. And it's possible the check needs to be moved later in transl_type_decl to accommodate mutually recursive or circular types (but I haven't thought that through yet). But I thought I'd get your opinion before implementing something.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ah, good catch! (If you haven't done this yet, you should add the example to the testsuite.)

I agree with your suggestion to rename kind_immediacy intokind_immediacy_approx to make things more obvious. This will encourage us to consider this issue for each callsites, which we initially forgot to do ourselves.

Regarding how to fix this: my naive reaction is that we were wrong to call only kind_immediacy here and should have called the proper immediacy-checking function that uses the backtracking behavior, check_decl_immediate. Is there a reason that we cannot do this at this step, on the decl below? (Maybe the declaration is not fully-formed or not already in the typing environment or something, or we end up trusting the annotation before checking it?)

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.

OK, I've pushed a possible fix. Here's my thinking:

We can not perform the kind check in transl_declaration. The issue is mutually defined types like:

type t = { x : s } [@@unboxed] [@@immediate]
and s = int

Checking that t's kind is compatible with the [@@immediate] attribute requires access to s's manifest, but the environment used for transl_declaration doesn't have accurate manifests for mutually defined types. This declaration is accepted by today's OCaml, so we don't want to reject it.

So we must perform this later - after the call to update_type in transl_type_decl. It seems sensible to put it with the other checks in that function after the ill-formed abbrevs check.

I've done that now. So in transl_type_decl we simply copy the immediacy attribute into the kind (for the abstract case), and we check it later. Here I describe why I think the check I've added is sufficient, in combination with check_coherence:

  • We might have an [@@unboxed] type, in which case we call check_type_immediate on the inner thing. This inner thing might be an mutually defined abstract type whose annotation we have trusted, but in that case its manifest is checked by check_coherence later.
  • Otherwise, we just use kind_immediacy_approx. The two cases where this is innaccurate are unboxed types (already handled) and abstract types, which are either purely abstract (fine) or abbreviations (checked by check_coherence).

The last question is whether check_coherence itself can be trusted. In particular, it checks that the manifests of abbreviations marked [@@immediate] are actually immediate, and the manifest may mention other abbreviation from the mutually recursive group. But this is fine, because their manifests will also be checked. And if there is a cycle, it's fine to treat all of them as immediate.

One consequence is that this declaration is allowed by this PR but is rejected by current OCaml:

type t = { x : s } [@@unboxed] [@@immediate]
and s = t [@@immediate]

This seems fine. Unfortunately, this similar declaration is not allowed, and could be:

type t = { x : s } [@@unboxed] [@@immediate]
and s = t

The difference is that in the former case s's kind records it is immediate, hitting the fast path of immediacy checking, while in the latter case we must expand, which runs out of fuel. This seems acceptable, if unfortunate, to me. But we can revisit the design if you disagree (I think it can be fixed, but at some cost in the complexity of the immediacy checking code, which doesn't seem worth it for such a silly type).

if !Clflags.native_code && Sys.word_size = 64 then Always_on_64bits
else Always
in
Result.is_ok (Ctype.check_type_immediate env ty imm)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I find the new definition harder to read than before. It comes from previous design iterations of this PR, which had functions to check whether a given type satisfied a given immediacy, but no function to actually compute the immediacy of a type. But this is not the case anymore. Could we write the following?

let is_immediate env ty =
  match Ctype.(type_immediacy_head env ty) with
  ...

?

(I think this would require tuning type_immediacy to work correctly on unboxed types, as suggested in another comment.)

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.

Interesting! I found the old version confusing (particularly, is_immediate seemed an odd name for a Type_immediacy.t -> bool).

I think we still do not have a function to calculate the exact immediacy - as described above the issue is not just unboxed types but also the approximation in the kind for abbreviations. We could add such a function - an analogue of check_type_immediate that returns the immediacy. My instinct is that this would be unnecessarily duplicative if it's only used in this one place, but I'm open to other opinions.

@nojb nojb added the typing label Jan 22, 2023
@gasche
Copy link
Copy Markdown
Member

gasche commented Jan 24, 2023

We are at a state where I think that the implementation is basically fine, but I still dislike some aspects of the design of the PR, which is that it defines a notion of immediacy without providing a function to compute the immediacy of a type. (This is not new, it was already a criticism of previous iterations.) I think that computing the immediacy of a type would be the better design, but we would need to add a NonImmediate immediacy to do so efficiently (without doing more expansions than with the current indirect approach; sometimes doing less expansions).

I think that we could move forward by merging the current PR with the current interface that I don't really like, and maybe I could propose a follow-up PR to implement my more invasive suggestion. @ccasin, what do you think? (In that scenario, would you be available to review a follow-up PR?)

@ccasin
Copy link
Copy Markdown
Contributor Author

ccasin commented Jan 24, 2023

I think that computing the immediacy of a type would be the better design, but we would need to add a NonImmediate immediacy to do so efficiently (without doing more expansions than with the current indirect approach; sometimes doing less expansions).

I'm not quite sure adding NonImmediate avoids all the same expansions. It seems to me that NonImmediate helps us fail immediacy checks more quickly (a clear improvement on this PR), but doesn't necessarily help in the case where the current PR allows us to succeed at immediacy checks without expanding. But perhaps I'm missing something (and I think NonImmediate would be a strong addition in any case).

I think that we could move forward by merging the current PR with the current interface that I don't really like, and maybe I could propose a follow-up PR to implement my more invasive suggestion. @ccasin, what do you think? (In that scenario, would you be available to review a follow-up PR?)

Yes, I would be happy to commit to reviewing a follow-up PR if we can find an acceptable solution to the remaining issue in this one.

@gasche
Copy link
Copy Markdown
Member

gasche commented Jan 25, 2023

I'm not quite sure adding NonImmediate avoids all the same expansions. It seems to me that NonImmediate helps us fail immediacy checks more quickly (a clear improvement on this PR), but doesn't necessarily help in the case where the current PR allows us to succeed at immediacy checks without expanding.

After thinking about this, I think that you are right, but that this can only happen in a corner case: when we are checking immediacy(ty) <= Immediate64, and intermediate approximation of ty's immediacy gives us Immediate64, we can stop early, whereas a "most precise immediacy" check needs to continue expanding ty as the most precise immediacy may still be Immediate.

Other cases:

  • if the immediacy we are checking against is Unknown, we never need to expand anyway
  • if the immediacy we are checking against is not Unknown, currently we have to keep expanding if the kind immediacy would be NotImmediate, while we could stop earlier in this case.

Thoughts:

  • I feel that the NotImmediate situation is much more likely to occur than the Immediate64 situation in most real-world programs, as Immediate64 is a rather niche feature. However, the NotImmediate situation helps failing early for programs that do not type-check, while the Immediate64 situation lets us succeed early for programs that do type-check. Typically, invalid programs get fixed quickly and are only type-checked a couple times, while valid programs keep evolving and their code is type-checked many times. Succeeding early is more important than failing early in practice.
  • In any case we could integrate NotImmediate to the current approach and get, in terms of expansions, the best of both worlds.
  • In an arbitrary lattice of properties (not just the current fixed lattice of immediacies), it seems that the indirect "check if the property is below a bound." approach could provide arbitrarily important gains over the direct "compute the property then check the bound" approach. So the current approach, with the indirectness I do not like, may still be the design that will scale better to layouts and what not.

@lpw25
Copy link
Copy Markdown
Contributor

lpw25 commented Jan 25, 2023

After thinking about this, I think that you are right, but that this can only happen in a corner case: when we are checking immediacy(ty) <= Immediate64, and intermediate approximation of ty's immediacy gives us Immediate64, we can stop early, whereas a "most precise immediacy" check needs to continue expanding ty as the most precise immediacy may still be Immediate.

I think a key point here is that this corner case quickly stops being a corner case once you expand the lattice to general kinds. Then you really do want to use a check function rather than a two step "get me the best answer, then compare it" approach. I think this is generally the correct approach in most subtyping-style systems: it is usually the case that many checks can be short-circuited without finding out the most accurate information.

@lpw25
Copy link
Copy Markdown
Contributor

lpw25 commented Jan 25, 2023

(I also just realized that I missed you make the exact same point -- so just consider the above a +1 to what you said in your last bullet).

@gasche
Copy link
Copy Markdown
Member

gasche commented Jan 25, 2023

Yes. I still wonder whether it would be possible to present the computation as a "compute the property then compare", without loss in efficiency, by using a different interface, for example by returning an on-demand stream of increasingly-precise approximations. This is just a conceptual distinction, outside the scope of the present PR. That approach (compute then compare) is the one that relates most clearly the implementation of the check with the semantics of the property.

@ccasin
Copy link
Copy Markdown
Contributor Author

ccasin commented Feb 1, 2023

I was just looking back at this and realized I had forgotten to actually push the fix I described in my last comment - sorry, I've done that now. I think where this stands is that we've agreed on everything except a fix for the problem identified with unboxed types - the comment here describes the fix I've just pushed (but meant to push last week).

@gasche gasche self-assigned this Feb 6, 2023
@gasche
Copy link
Copy Markdown
Member

gasche commented Feb 6, 2023

Quoting the "comment above" from @ccasin to discuss this important question in the main thread.

We can not perform the kind check in transl_declaration. The issue is mutually defined types like:

type t = { x : s } [@@unboxed] [@@immediate]
and s = int

Checking that t's kind is compatible with the [@@immediate] attribute requires access to s's manifest, but the environment used for transl_declaration doesn't have accurate manifests for mutually defined types. This declaration is accepted by today's OCaml, so we don't want to reject it.

So we must perform this later - after the call to update_type in transl_type_decl. It seems sensible to put it with the other checks in that function after the ill-formed abbrevs check.

I've done that now. So in transl_type_decl we simply copy the immediacy attribute into the kind (for the abstract case), and we check it later. Here I describe why I think the check I've added is sufficient, in combination with check_coherence:

  • We might have an [@@unboxed] type, in which case we call check_type_immediate on the inner thing. This inner thing might be an mutually defined abstract type whose annotation we have trusted, but in that case its manifest is checked by check_coherence later.

  • Otherwise, we just use kind_immediacy_approx. The two cases where this is innaccurate are unboxed types (already handled) and abstract types, which are either purely abstract (fine) or abbreviations (checked by check_coherence).

The last question is whether check_coherence itself can be trusted. In particular, it checks that the manifests of abbreviations marked [@@immediate] are actually immediate, and the manifest may mention other abbreviation from the mutually recursive group. But this is fine, because their manifests will also be checked. And if there is a cycle, it's fine to treat all of them as immediate.

One consequence is that this declaration is allowed by this PR but is rejected by current OCaml:

type t = { x : s } [@@unboxed] [@@immediate]
and s = t [@@immediate]

This seems fine. Unfortunately, this similar declaration is not allowed, and could be:

type t = { x : s } [@@unboxed] [@@immediate]
and s = t

The difference is that in the former case s's kind records it is immediate, hitting the fast path of immediacy checking, while in the latter case we must expand, which runs out of fuel. This seems acceptable, if unfortunate, to me. But we can revisit the design if you disagree (I think it can be fixed, but at some cost in the complexity of the immediacy checking code, which doesn't seem worth it for such a silly type).

@gasche
Copy link
Copy Markdown
Member

gasche commented Feb 6, 2023

@ccasin I apologize for the silence here; I was at a conference last week and am trying to write a paper this week. I won't be back to reviewing this in details before next week.

I understand the high-level idea of the approach you describe and I agree that it sounds okay.

@gasche
Copy link
Copy Markdown
Member

gasche commented Jul 20, 2024

I understand that there have been significant changes to this design on the Jane Street side, see in particular oxcaml/oxcaml#1384 . When they have time, I would be curious to hear from @goldfirere or @ccasin on their current understanding, and what is the best approach moving forward.

@ccasin
Copy link
Copy Markdown
Contributor Author

ccasin commented Jul 29, 2024

I understand that there have been significant changes to this design on the Jane Street side, see in particular ocaml-flambda/flambda-backend#1384 . When they have time, I would be curious to hear from @goldfirere or @ccasin on their current understanding, and what is the best approach moving forward.

Sorry for the slow response - I was on vacation last week - and for not getting back to this sooner in general.

You're right that things have moved a bit on our end. The main change is the one you linked - moving immediacy information out of the Abstract case of type_kind and into type_declaration. Indeed, this choice was debated back in #10041, and we went with the approach here for a while before moving to the other. This offers some improvements in clarity and performance, but I think it is not a big change.

I am happy to rebase this PR and make that change (though likely not for a week or two). Would it be easier for you if I pushed those changes as new commits here, or closed this and opened a fresh PR when ready?

@gasche
Copy link
Copy Markdown
Member

gasche commented Jul 29, 2024

There is no hurry on my end (next week it will be my turn to go for vacations for the month of August), but I would still be interested in getting something close to your final design, whatever it is, upstreamed. Regarding whether to update here or open a new PR, please do as you prefer -- when the time is right.

@gasche
Copy link
Copy Markdown
Member

gasche commented May 15, 2025

My understanding is that the Jane Street type-checker is not using this approach anymore, so my hope of merging this to reduce the diff before the two is not up-to-date, and the best thing to do is to close the current PR -- with apologies for @ccasin for the time investment on his part... It was a pleasure trying to get into this again.

@gasche gasche closed this May 15, 2025
@ccasin
Copy link
Copy Markdown
Contributor Author

ccasin commented May 15, 2025

My understanding is that the Jane Street type-checker is not using this approach anymore, so my hope of merging this to reduce the diff before the two is not up-to-date, and the best thing to do is to close the current PR -- with apologies for @ccasin for the time investment on his part... It was a pleasure trying to get into this again.

Agreed. The newer approach is not very different, and I do still want to make a PR here with it, but it's fine to close this and do that as a separate PR considering that I've clearly failed to find time for this. Thanks!

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