-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
At tailcall #111
At tailcall #111
Conversation
/cc @euanh |
/cc @simonjbeaumont |
Cool! I've also had a stab at the same problem. I also found that doing this in the compiler would mean threading through the annotations into the Lambda layer (passed the Transl stage). It seemed like that was a clear separation from the Typedtree to the Lambda so instead I wrote a cmt parser: https://github.com/simonjbeaumont/ocaml-tailrec It can be compiled with Cool to see this in the compiler though. I'd hacked up a similar approach but not quite made it. |
A ppx strategy would be useful to implement It's interesting to notice that this PR uses the function |
@@ -516,7 +516,9 @@ let rec emit_tail_infos is_tail lambda = | |||
match lambda with | |||
| Lvar _ -> () | |||
| Lconst _ -> () | |||
| Lapply (func, l, loc) -> | |||
| Lapply (func, l, ({apply_loc=loc} as info)) -> | |||
if info.apply_should_be_tailcall && not is_tail |
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.
You should test here if the warning is enabled. emit_tail_info, is allso called when -annot is used.
You should enable this warning by default since it won't warn if you didn't add annotations explicitely. |
| Lapply (func, l, loc) -> | ||
| Lapply (func, l, ({apply_loc=loc} as info)) -> | ||
if info.apply_should_be_tailcall && not is_tail | ||
then Location.prerr_warning loc Warnings.Expect_tailcall; | ||
list_emit_tail_infos false l; | ||
Stypes.record (Stypes.An_call (loc, call_kind l)) |
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.
You should test if -annot is set before emitting informations
First off, hats off to @c-cube! I'm pleased I wasn't the only one who thought it might be useful. I think @thomassa makes a good point. I found that the natural way of annotating the final line of with That was partly why I abandoned that approach and went instead for annotating a function definition as Is it not also a little suspect to thread through the annotation from the TypedTree to Lambda for just the Lapply. It kind of feels like annotations should exist in the Lambda stage or not (not just for one of the variants). |
Why not just add support for |
@lpw25 I guess a Otoh I don't think ditching This CPS example makes me wonder which syntax would be nice for expressing the constraint that in
the continuation |
Yes, and you need to add support for |
I think we should make a choice between either |
Ideally I think we'd have a prefix attribute: |
It looks like supporting |
To me it'd make much more sense if |
@pw374 that would make sense, I agree. A solution could be to allow |
For the record, I believe this conflict is artificial and could be avoided by replacing the rule:
in the definition of |
Just added a preprocessing phase to compilation so that I had issues with the build system, so there are almost surely lots of mistakes. |
9186116
to
594d444
Compare
I'm not happy with Please:
Syntax design is hard. The solution is not to allow everything. (We can discuss the conflict issue later. Maybe careful massaging of the grammar would let us have the nice things. We can try that later if the chosen syntax for the attribute leds itself to this extension without introducing two separate syntaxes.) |
@gasche: ok, fine. I'll get back to About |
I think it reads much less weird if you format it |
@c-cube wrote:
If it were valid then that's how I would read it, certainly: as saying that there is a tail-call of the function that results from applying @yallop: I agree. @c-cube wrote:
I agree that it would be nice to have some way to express that sort of constraint. |
The CPS example is interesting because it does not seem to differ much from the proposed semantics of This immediately suggests having an annotation Note that there is still a difference between this proposed semantics of "
The call to
On the side of the implementation, it is indeed a reasonable idea to "implement" the ¹: one problem with implementing |
@yallop: indeed, prefix attributes are a reasonable idea -- and it can generalize to other use-case. That said, I'm not convinced it is necessary in this case, and I'm afraid the extension/attribute syntax is quite complex already ( |
@alainfrisch: Oh, I hadn't realised there was anywhere @gasche: your idea of attaching the attribute to the binding-site is interesting, but I'm not clear on whether or not it would allow something like this:
The significant point there is that although when |
Looks good to me. |
ping @gasche for merging? ;) |
Merged in trunk. Thanks for the patch and the compromises! I remember at the OCaml coding sprint when we discussed the code, I was unconvinced by your choice of extending the |
@gasche I don't see this in trunk. |
Never mind. Apparently the git mirror is lagging behind. |
I have a dumb question, what is the use case for tailcall, is not it obvious by reading the code to see if it's tailcall. this seems to compilicate lambda intermediate representation for not too much benefit? |
Sometimes one may write a tail call, then their code evolves and the call isn't a tail one any more. Typically one write a tail-recursive function, and then adds something to handle some exception, which wrecks the tail position.
|
@bobzhang In practice, such mistakes are common enough that many people feel the feature is worthwhile. |
I agree it can be useful in some cases. but the implementation is not very modular, shall we design what kind of information should be passed down to lambda IL, if tomorrow we have another useful feature needed, shall we bloat lambda IL more? btw, for this feature, I think |
I don't see a problem with the implementation: this information is stored in a record of information about the application node. If we want to add a new feature of this kind, we can add a new field to the record, and most of the code (which uses the record by pattern-matching or projecting only a subset of its fields) will not need to be modified. (I would rather use a slightly different representation with a record for all informations instead of just the auxiliary information, as explained in this message, but the maintenance aspects discussed here are equivalent with both representations). |
A tailcall is not necessarily a tailrec call. |
Fix GC stats
c703f5f777 Incorporate upstream comments into type-variable refactor (ocaml#121) 362ba2349f Constrain curry modes to increase along applications (ocaml#108) b1f0cf9f91 Simplify the extension handling (ocaml#114) 4fd53a1f6f Remove pat_mode from typedtree (ocaml#105) cf6fcbc129 Handle attributes on lambdas with locally abstract types (ocaml#120) 5fa80fe23f Don't track attributes inside attributes for warning 53 (ocaml#115) 8a69777a3c Handle unclosed `[: ... :]` patterns (via `Generic_array` machinery) (ocaml#117) b0737f46c4 Add promote-one Makefile target (ocaml#118) c6ad684608 Refactoring and fixes around module lookup (ocaml#107) b0a649516b Add documentation for global constructor arguments (ocaml#69) dd79aeca91 Print `nlocal` in the `-d(raw)lambda` output (ocaml#112) 8035026661 Fix `nlocal` in the generated Lambda for list comprehensions (ocaml#113) afbcdf0642 Immutable arrays (ocaml#47) bfe1490dfb fix several issues when removing exp_mode (ocaml#110) 8f46060dc5 Better error message for under-applied functions (ocaml#74) 27331d848d Consistently use Lmutvar or Lvar in comprehensions (ocaml#111) 01e965b549 Skip failing test for now 0131357265 Fix test case to use comprehensions_experimental 22a73684b7 Temporarily disable list comprehensions tests due to locals bug e08377d2d1 Make `comprehensions` into `comprehensions_experimental` for now (ocaml#109) 947cf892b5 List and array comprehensions (ocaml#46) bd9e051 remove exp_mode from typedtree (ocaml#100) a9268d2 Fix misplaced attribute warning when using external parser (and some cleanup) (ocaml#101) 2b33f24 Refactor toplevel local escape check (ocaml#104) ed2aec6 Comment functions exported from TyVarEnv. 87838ba Move new variable creation into TyVarEnv. a3f60ab Encapsulate functions that work with tyvars 43d83a6 Prevent possibility of forgetting to re-widen 2f3dd34 Encapsulate context when narrowing type env't d78ff6d Make immediate64 things mode cross (ocaml#97) aa25ab9 Fix version number (ocaml#94) d01ffa0 Fix .depend file (ocaml#93) 942f2ab Bootstrap (ocaml#92) 05f7e38 Check Menhir version (ocaml#91) 1569b58 Move the CI jobs from 4.12 to 4.14. (ocaml#90) git-subtree-dir: ocaml git-subtree-split: c703f5f7772dd4252405b086be11c15a3c67f2ac
add all OCaml workshops
Add an attribute
[@tailcall]
such thatf args [@tailcall]
warns (with the new warning 50) if the call is not tail-recursive. See the ocaml hacking item.The patch is twofold:
Lapply
expression (in lambda code) is annotated with a record, rather than a location,with a boolean within this record that specifies whether the call is expected to be in tail position. This flag
is set if the corresponding
Typedtree.expr
has a "tailcall" attribute.Simplif
, if the warning is enabled, tail calls are annotated, and if a call is expected to be in tail positionbut isnt't, the warning is emitted.
Also added two tests in
testsuite/tests/warnings/
.