ford
ford copied to clipboard
ford crashes on module procedure with interface body in same scope
% tree .
.
├── ford.md
└── src
└── foo_m.f90
1 directory, 2 files
% cat ford.md
---
project: Foo
summary: yada yada yada
src_dir: src/
% cat src/foo_m.f90
module foo_m
implicit none
interface foo
module function foo() result(bar)
implicit none
logical bar
end function
end interface
contains
module procedure foo
bar = .true.
end procedure
end module
% ford ford.md
Reading file src/foo_m.f90
ERROR in file 'foo_m.f90': Unexpected MODULE PROCEDURE in module 'foo_m':
module procedure foo
ERROR in file 'foo_m.f90': END statement outside of any nesting:
end module
Traceback (most recent call last):
File "/usr/local/Cellar/ford/6.1.15/libexec/lib/python3.10/site-packages/ford/fortran_project.py", line 108, in __init__
ford.sourceform.FortranSourceFile(
File "/usr/local/Cellar/ford/6.1.15/libexec/lib/python3.10/site-packages/ford/sourceform.py", line 1389, in __init__
FortranContainer.__init__(self, source, "")
File "/usr/local/Cellar/ford/6.1.15/libexec/lib/python3.10/site-packages/ford/sourceform.py", line 789, in __init__
self._cleanup()
File "/usr/local/Cellar/ford/6.1.15/libexec/lib/python3.10/site-packages/ford/sourceform.py", line 1033, in _cleanup
raise NotImplementedError()
NotImplementedError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/bin/ford", line 8, in <module>
sys.exit(run())
File "/usr/local/Cellar/ford/6.1.15/libexec/lib/python3.10/site-packages/ford/__init__.py", line 645, in run
main(proj_data, proj_docs, md)
File "/usr/local/Cellar/ford/6.1.15/libexec/lib/python3.10/site-packages/ford/__init__.py", line 568, in main
project = ford.fortran_project.Project(proj_data)
File "/usr/local/Cellar/ford/6.1.15/libexec/lib/python3.10/site-packages/ford/fortran_project.py", line 121, in __init__
print(f"Warning: Error parsing {relative_path}.\n\t{e.args[0]}")
IndexError: tuple index out of range
% ford --version
ford version 6.1.15
Moving the procedure definition to a submodule also generates a compiler error:
% tree .
.
├── ford.md
└── src
├── foo_m.f90
└── foo_s.f90
1 directory, 3 files
% cat src/foo_m.f90
module foo_m
implicit none
interface foo
module function foo() result(bar)
implicit none
logical bar
end function
end interface
end module
% cat src/foo_s.f90
submodule(foo_m) foo_s
implicit none
contains
module procedure foo
bar = .true.
end procedure
end submodule
Thanks for the bug report @rouson, I really appreciate the clear reproducer! I'm afraid it'll be at least a week before I can look at this properly.
I'm not 100% sure that this is valid Fortran, but gfortran at least accepts it.
@ZedThree although I don't have the relevant citation handy, I'm certain this is standard-conforming code. In case it helps, I'm on the standard committee, I use this feature across more than a dozen projects with multiple compilers,and the non-profit that I lead, Sourcery Institute, paid for this feature to be added to gfortran
several years ago.
Yes, I happened to have this problem today as well.
Replace the procedure
in the following example with subroutine
, and ford
will not report an error, which is indeed valid Fortran syntax.
module mod
interface
module subroutine say_hello()
end subroutine
end interface
end module mod
submodule(mod) submod
contains
module procedure say_hello ! procedure -> subroutine
print '(a)', "Hello World!"
end procedure say_hello ! procedure -> subroutine
end submodule submod
program main
use mod, only: say_hello
call say_hello()
end program main
In the Windows-MSYS2 environment, ford
produces the following error:
Reading file app\demo.f90
Processing documentation comments...
Correlating information from different parts of your project...
Traceback (most recent call last):
File "C:\msys64\ucrt64\lib\python3.10\runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:\msys64\ucrt64\lib\python3.10\runpy.py", line 86, in _run_code
exec(code, run_globals)
File "C:\msys64\ucrt64\bin\ford.exe\__main__.py", line 7, in <module>
File "C:\msys64\ucrt64\lib\python3.10\site-packages\ford\__init__.py", line 645, in run
main(proj_data, proj_docs, md)
File "C:\msys64\ucrt64\lib\python3.10\site-packages\ford\__init__.py", line 592, in main
project.correlate()
File "C:\msys64\ucrt64\lib\python3.10\site-packages\ford\fortran_project.py", line 254, in correlate
container.correlate(self)
File "C:\msys64\ucrt64\lib\python3.10\site-packages\ford\sourceform.py", line 1078, in correlate
if proc.module and proc.name.lower() in self.all_procs:
AttributeError: 'FortranSubmoduleProcedure' object has no attribute 'module'
Thanks,@zoziha! You taught me something. I didn't know about this alternative approach. this issue broke our documentation deployment on several projects and your alternative is less involved than the only workaround I had devised (repeating all of the interface information in the procedure definition).
I remember that some older versions of ford
can be deployed through the ford
document of Fortran-stdlib
. Fortran-stdlib
has always used the coding paradigm of submodule + module procedure
. Now Fortran-stdlib
also also fails to deploy. I wonder if it's possible to make the docs deploy pass briefly by identifying an old ford
version.
pip install -v ford==6.1.10
@zoziha please see #447 for one proposed solution. Thanks to @everythingfunctional, I now realize that your workaround requires repeating the interface information in the procedure definition. I hadn't recognized that because your say_hello
procedure has no arguments so there was nothing to do other than replace procedure
with subroutine
. I'm hoping to avoid having the interface content in two places. Hopefully the solution in #447 works for you. In case an example is helpful, we're now using this approach in the Assert repository CI.
I think the forced downgrade of markdown
is a bit of a red herring. I've also not found a version of ford
where module procedure
works in a module
scope (as opposed to in a submodule, which does work), so I'm not sure what's happening there! The version using a separate submodule works for me with the latest ford
I do have a simple fix that will allow this to work, but it will have some repercussions when a generic (named) interface has the same name as one of its specific routines (@rouson This is the bit I didn't realise was valid Fortran!). Namely, that the specific routine will clobber the generic one and you might not get docs for the interface -- I need to do some more checking to be certain though. That might be a rather bigger fix too.
I've reopened this issue till I've got some proper tests and a fix in.
The version using a separate submodule works for me with the latest
ford
@ZedThree I later reached the same conclusion.
I do have a simple fix that will allow this to work, but it will have some repercussions when a generic (named) interface has the same name as one of its specific routines (@rouson This is the bit I didn't realise was valid Fortran!).
That was a mistake on my part. Based on this realization, I agree that what I submitted is is likely not standard-conforming.
I've reopened this issue till I've got some proper tests and a fix in.
I look forward to using the fix. Thanks for investigating this!
That was a mistake on my part. Based on this realization, I agree that what I submitted is is likely not standard-conforming.
I actually reached the opposite conclusion, I'm pretty sure what you had is completely valid! Both gfortran and Intel accept it.
Fortran is generally a little bit weird about which names clash and which don't. I guess this case is fine because the compiler will always assume a call to foo
is the generic name and then resolve which specific name from that.
I'm not sure exactly how to handle this in ford
though. Currently, we dump all the procedures found in a generic interface into the parent module's dict
of procedures. We then use this dict in various places for matching procedure names to the actual objects, for example for function calls, but also for module procedure
s. The issue is then that we want the generic name for looking up calls, and the specific name for the module procedure
s.
Having spent a bit of time looking into this, there are quite a few sharp edges to module procedure
s in general in Ford that I'll need to work on.
I remember that some older versions of
ford
can be deployed through theford
document ofFortran-stdlib
.Fortran-stdlib
has always used the coding paradigm ofsubmodule + module procedure
. NowFortran-stdlib
also also fails to deploy. I wonder if it's possible to make the docs deploy pass briefly by identifying an oldford
version.pip install -v ford==6.1.10
I encountered the AttributeError: 'FortranSubmoduleProcedure'
building stdlib-0.2.1 documentation using ford-6.1.15 and 6.1.16 while it's successfully built with ford-6.1.13 (Gentoo linux GURU repo package):
Reading file src/common.fypp
Preprocessing /var/tmp/portage/dev-libs/fortran-stdlib-0.2.1/work/stdlib-0.2.1/src/common.fypp
Processing documentation comments...
Correlating information from different parts of your project...
Traceback (most recent call last):
File "/usr/lib/python-exec/python3.10/ford", line 8, in <module>
sys.exit(run())
File "/usr/lib/python3.10/site-packages/ford/__init__.py", line 645, in run
main(proj_data, proj_docs, md)
File "/usr/lib/python3.10/site-packages/ford/__init__.py", line 592, in main
project.correlate()
File "/usr/lib/python3.10/site-packages/ford/fortran_project.py", line 254, in correlate
container.correlate(self)
File "/usr/lib/python3.10/site-packages/ford/sourceform.py", line 1091, in correlate
if proc.module and proc.name.lower() in self.all_procs:
AttributeError: 'FortranSubmoduleProcedure' object has no attribute 'module'
I've got a few projects that fail with the latest version of Ford, except that using an older version of one of its dependencies works. Namely the CI scripts have this command for installing Ford:
sudo pip install ford markdown==3.3.4
@band-a-prend @zoziha I've checked that #463 works with stdlib, but if you would like to double check links etc are what you expect, that would be lovely
@everythingfunctional Would you mind checking that PR with your projects too?
@rouson Your original error should be fixed in #463 now, but I've not had time to look at how to link the module procedure implementation to its interface when it's inside an interface
with the same name. If you keep the docstring on the interface
, then this should hopefully be ok for you
@ZedThree thank you for fix. Unfortunately I could check only after 24 November.
I'll have to work out how to get it working on my machine, but I'll try to get to it soon.
@ZedThree I just edited my original comment to add an underscore to the interface name. Matching the interface and procedure names was something that I inadvertently did while trying to develop a short reproducer for the ford
bug. In my intended use cases, the names don't match and I'm not certain that the original code with matching names was standard-conforming.
@everythingfunctional is the sudo pip install ford markdown==3.3.4
no longer working? I've been using it CI on GitHub. On my local machine, I'm using Homebrew to install ford
and this issue is blocking me from producing documentation for the initial release of a new project.
@rouson , that still works, but if recent developments have made it unnecessary, that would useful to know.
@everythingfunctional actually I'm not sure the workaround is working for me anymore. See the Inference-Engine CI results. Or is it possible that the issue is that the PR generated those CI results contains the first version of the deploy-docs.yml
file for that repository and the deployment won't work until the PR is merged into the main branch?
@rouson I checked out Inference-Engine, and with a small change to your ford.md
, I managed to successfully build the docs.
@everythingfunctional I checked out rojff
, as it uses submodules, and confirmed that it fails with 6.1.16, and passes with #463
I'm happy this is now working as intended, so I'll go ahead a make a new release now
Fixed in v6.1.17!
@ZedThree if I need your edit to Inference-Engine's ford.md
file, could you please submit a pull request on the Inference-Engine repository? If I don't need your edits once I have v6.1.17, then no need to submit the PR. For now, I'm trying brew install ford --HEAD
to see if that does the trick.
@ZedThree thanks for working on this!
@ZedThree
I confirm that stdlib-0.2.1
documentation now successfully build with ford-6.1.17
.