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
Make Tsubst directly retain two arguments, instead of nesting a Ttuple #10174
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.
This is a nice improvement, and I approve in principle. I think that we could discuss the code a bit more before merging:
- The role of the
type_expr option
is not documented at the point whereTsubst of ...
is declared, maybe you could comment there that theoption
part is only usedNone
for row types, during copying operations? - Many places in the type-checker now ignore the second component of
Tsubst
, when before they would iterate on the whole type argument (so both sides of the Tuple if it was a tuple). The assumption is that we never hit the Some case in these functions (for some of them it is clear that they never run on row types). I wondered if we wanted to explicitly assert that the second component isNone
, instead of ignoring it. (Or would something break if we did? That would be useful information.) - I think that it may be nice to have a separate constructor for this particular mode of use of
Tsubst
,Trowsubst
orTrowcopy
for example, so that it would be very clear that it does something different from the normalTsubst
node, and only occur on row variables. This may make the patch more invasive (some visitors of typedtree would need to be edited), however.
Oh, that documentation is indeed necessary. I added explanations in types.mli.
I could not clearly understand your Tuple example. Could you a bit more elaborate on it? My assumption is that the use of the second component is concealed in copying functions and does not escape out of them.
Yes, that division of |
In the code to iterate on type sub-expressions (for example I am not completely sure whether this is the case (whether a Thinking about it more, I would rather guess that we can hit cases with |
Thank you, now I understand what you are concerned about. The last commit makes |
After my previous commit, Jacques examined this possibility and explained me that this will not happen. |
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.
typing/printtyp.ml
Outdated
else ty :: tyl) | ||
(* Two parameters might be identical due to a constraint but we need to | ||
print them differently in order to make the output syntactically valid. | ||
We use Tsubst because it does not appear in a valid type. *) |
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.
I am confused by this comment that says that Tsubst
is used, but (if I read the diff correctly) in fact changes from Tsubst
to Ttuple
.
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.
Fixed.
(* TODO: move this line to btype.ml | ||
there is a similar problem also in ctype.ml *) | ||
ty' | ||
else ty | ||
| Tsubst ty -> | ||
| Tsubst (ty, _) -> |
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.
Can we assert = None here?
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.
This case actually failed at one test (poly.ml). I am now looking into the bug..
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.
This is needed when the row variable of a polymorphic variant is Tunivar
.
In printtyp, Now that the use of |
I think that this is my turn to ask a naive question: rather than trying to pretend that This PR seems to go in the opposite direction by adding even more data that only exist in a very specific context to the typexpr graph. |
That's an interesting suggestion but the PR as-is is already an improvement, and the change you suggest is much more invasive. I would be interested in converging on the current proposal not-too-slowly, merging it, and then letting @t6s and @garrigue decide where they want to invest their efforts next (possibly in hiding |
@@ -1235,7 +1235,7 @@ let rec copy ?partial ?keep_names scope ty = | |||
in | |||
(* Register new type first for recursion *) | |||
Private_type_expr.set_desc | |||
more (Tsubst(newgenty(Ttuple[more';t]))); | |||
more (Tsubst (more', Some t)); |
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.
All code paths aware of the this tuple encoding (aka the pattern matching above and one in Subst
) never use more'
. Since all other users would erroneously interpret this encoding as a real tuple, it seems to me that rather than the product type_expr * type_expr option
, the non-encoded argument of Tsubst
is a sum.
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.
If we were to just encode the current behavior of the algorithm in this type, you are correct.
However, it seems cleaner that the meaning of Tsubst
be regular, i.e. its first argument is always a copy of the original node. Then the second argument is some special information used by the algorithm, here a copy of the enclosing Tvariant
node.
We can ensure that we do not depart from the current behavior of the algorithm by checking that this second argument is always None
when we use the first one. We will add such assertions.
typing/printtyp.ml
Outdated
tree_of_typexp sch ty | ||
| Tsubst _ -> | ||
Otyp_stuff "<Tsubst>" | ||
(* This case should not happen *) |
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.
I would prefer an assert false
: the outcome tree is user facing, no users should need to known what a Tsubst
is.
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.
Sometimes we use Printtyp functions in the middle of the type-checker to debug things, but I guess we use raw_type
rather than the higher-level functions. At least for raw_type
I think it is important to handle intermediate states correctly.
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.
They need not see it: it is not going to happen, as many functions will now reject it anyway.
However, as @gasche pointed, one might want to use Printtyp.type_expr
in the debugger for readability, and it is better not to have the debugger crashing because of an assertion.
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.
This seems sensible. However, the comment could be updated to: This case should not happen except when debugging the compiler
.
Also, would it be too much to be extra-explicit with <Error: unexpected Tsubst>
?
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.
I changed the comment but not the output. When this happens, this should actually not be unexpected.
This code is inherited from Jérôme, and originally it only used
We are not adding more data, since it was already there. We are just streamlining it, to make its handling easier. |
It appears that adding
in
where The reason the original code worked is due to the use of
which extracted the |
Added assertion to check that |
The removal of |
I concur that the removal of |
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.
My impression is that the PR is essentially done, modulo two comments from Florian in the printer code (a question in the case Tsubst _ -> ()
, and a small suggestion to rephrase printing.)
let vars, ty_arg = | ||
match repr lbl.lbl_arg with | ||
{desc = Tpoly (ty, tl)} -> | ||
instance_poly' scope ~keep_names:false fixed tl ty | ||
| _ -> | ||
[], copy scope lbl.lbl_arg | ||
in | ||
(* call [copy] after [instance_poly] to avoid introducing [Tsubst] *) | ||
let ty_res = copy scope lbl.lbl_res in |
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.
For the record, I don't really understand what is going on here. I suppose there is a problem when lbl_res
and lbl_args
share some parts of the type, but it's not clear who might introduce Tsubst
. (I suppose instance_poly
can introduce Tsubst nodes, and copy
normalizes them away?)
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.
This is the other way round: copy_sep
(first phase of instance_poly
) does not introduce (and should not see) Tsubst
's, while copy
does. Could add an assertion in copy_sep
.
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.
We could add many assertions in copy_sep
, I don't think this PR is the one where we want to start doing that.
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.
We are already adding assertions about Tsubst
everywhere, so why not in copy_sep
.
Now all functions that call iter_type_expr
are checking this, but copy_sep
is using copy_type_desc
instead, which explicitly allows Tsubst
, hence the need for a specific assertion.
I do not pretend that this alone will make copy_sep
self-explanatory :-)
…et Tsubst retain two arguments.
…subst to print constrained type parameters; add a test case to check its output
I checked the errors in the CI, and they come from other PRs or internal CI problems (this PR has nothing to do with the standard library documentation). |
The constructor
Tsubst
oftype_desc
has only onetype_expr
as its argument while it needs two during a copy.The two values are currently packed as a
Ttuple
and wrapped in an extratype_expr
before they are fed toTsubst
.This style looks quite ad-hoc, and moreover it turned out to be an obstacle in our (@garrigue and me) attempt to make
type_expr
an abstract type.This PR adds to
Tsubst
another argument of typetype_expr option
to eliminate that hackish use ofTtuple
.