This is the mail archive of the
fortran@gcc.gnu.org
mailing list for the GNU Fortran project.
Re: Type-bound procedure and procedure pointer component calls
Hi Janus,
thanks for the comments!
Janus Weil wrote:
Add a new ref-type REF_PROC or extend REF_COMPONENT with an attribute to
hold an actual arglist; then in match_varspec, if a component symbol is
found that is in the type-bound procedures namespace, parse an arglist
following it and build such a REF_PROC:
WRITE (*,*) val(1)%tbp_function (42)
will become
EXPR_VARIABLE(val) -> REF_ARRAY(1) -> REF_PROC(arglist(42), gfc_typebound*)
Sounds good. Alternatively the arglist could be stored in the top
level gfc_expr, which already has a field for it
(expr->value.function.actual). Then I think we also need a new
expression type (EXPR_SUBROUTINE?) for the case that the TBP/PPC is a
subroutine. For functions we can probably reuse the existing
EXPR_FUNCTION.
Actually, so far I thought about the gfc_expr only as a means to reuse
match_varspec and until we do something with the matched data after that
in parsing or resolution. I don't quite like the idea of gfc_expr
holding a SUBROUTINE "officially". This from my point of view somewhat
defeats the purpose of an "expression". OTOH of course, this makes
handling a bit easier.
I'd rather go for using EXPR_FUNCTION for both subroutines and functions
and allow the exception that gfc_code->expr of a CALL statement can/must
be an EXPR_FUNCTION expression referencing a SUBROUTINE. As for the
arglist, if we do EXPR_FUNCTION it is of course a good idea to reuse
value.function.actual (if we use another type, I don't think its a good
idea to use the function-specific union).
I just realize that for EXPR_FUNCTION the symtree member will be treated
as the function to call, won't it? Thus it is probably safer to use a
new expr-type for "component-calls".
During resolution, we can transform such an expression easily into an
ordinary function call; the passed-object will be given by the expression
itself with the last reference removed, and the other things needed for the
call (the binding-target procedure and the arglist) are in the REF_PROC.
Ok. However, this "transforming to ordinary function call" does not
work for PPCs of course. There we need dynamic calling, which will
also be necessary for TBPs later to have fully dynamic polymorphism
(once the other OOP bits are in place). So, at *some* point this will
have to be implemented in a dynamic way. The question is: Should we
already do this now, or rather start with a static transformation at
resolution stage? The advantage of the dynamic approach would be that
it's more or less the same for both TBPs and PPCs, so that we
hopefully need only one implementation. And we wouldn't have to change
it later for full OOP.
Agreed. However, for dynamic dispatch and TBPs to work, we need Paul's
CLASS implementation. Until then, I think for TBPs it will be best to
implement them at first the quick way and work out a dynamic
implementation later; at least I do want to look how big the patch gets
and how easy such an implementation will be.
But of course it is good to find a common strategy that can be used for
that implementation and for PPCs. If we use a new expr-type as
suggested above, it should not be too hard to integrate it into the
trans-phase with whatever implementation we need for it, I think. That
could be something like:
expr.expr_type = EXPR_COMPCALL;
expr.symtree = ...; expr.ref = ...;
expr.value.compcall.actual = arglist;
expr.value.compcall.derived = derived;
expr.value.compcall.comp = comp;
Where symtree/ref contain the originally parsed ref-chain leading to the
called component, arglist is the actual arglist that is still resolved
to contain the passed-object during resolution, derived is the declared
derived-type of the passed-object and comp is the called component,
either as symtree for TBPs or gfc_component for PPCs (some way to store
it at least).
This would not change any existing code in respect to EXPR_FUNCTION of
course and we would "simply" have to implement trans of EXPR_COMPCALL
the way we need to do it. If possible (for now and maybe
NON_OVERRIDABLE methods or something like this) we could also handle
EXPR_COMPCALL in resolution.
For PPCs, we need to extend the expr.value.compcall structure and do the
right trans'ing, but otherwise it should be fine?
For CALL's, we could add a new field
gfc_expr* tbp;
to gfc_code. If not NULL it will hold such a reference-expression as above
encapsulating the TBP-call. Once again, during resolution this will be
transformed into an ordinary CALL of a SUBROUTINE.
Do you think an extra field is necessary? gfc_code already has two
gfc_expr fields ("expr" and "expr2"), none of which is being used for
CALL. And the type of the expression will in any way be indicated by
expr->expr_type (EXPR_SUBROUTINE/EXPR_FUNCTION/etc).
To implement CALL's, we need a way to distinguish between ordinary calls
and component calls, too, maybe a flag or another EXEC_ type (I'm not
sure how much change this would mean). Then once more again, in trans
look at the type and either call the referenced symtree as we do now or
call the EXPR_COMPCALL stored in expr.
Maybe it would be a good idea to start with a patch that changes the
way that ordinary functions and subroutines are called (by using
gfc_expr instead of gfc_symtree), so that this can more easily be
extended to TBPs and PPCs.
If we do so, we could as well call them through the completely new
gfc_callee structure, couldn't we? If we don't want to go through all
that code changes needed to accomplish that, I think we should stick to
only extending by new means to call components with dynamic dispatching
as written above. What would you change and what would you leave?
Maybe some of the more experienced gfortraners could try to comment on
all of this. I'm not sure if I'm overlooking all the consequences of
our design decisions right now.
That's a very good idea indeed :D
BTW, why can't we transform PPC-calls to calls to ordinary
procedure-pointers with adapted arglist? I have to admit though that I
know nearly nothing about procedure-pointers in Fortran nor about your
implementation of them.
So far,
Daniel
--
Done: Arc-Bar-Cav-Sam-Val-Wiz, Dwa-Elf-Gno-Hum-Orc, Law-Neu-Cha, Fem-Mal
To go: Hea-Kni-Mon-Pri-Ran-Rog-Tou