Compilers should suggest adding a CONTAINS statement when missing

A mistake I often make is forgetting a CONTAINS statement in a module before defining procedures. Usually Fortran compiler messages are good at saying what is needed to fix a code, but for the invalid code

module m
implicit none
function twice(i) result(j)
integer, intent(in) :: i
integer             :: j
j = 2*i
end function twice
end module m

gfortran says

temp.f90:3:1:

    3 | function twice(i) result(j)
      | 1
Error: Unclassifiable statement at (1)
temp.f90:6:7:

    6 | j = 2*i
      |       1
Error: Unexpected assignment statement in MODULE at (1)
temp.f90:7:3:

    7 | end function twice
      |   1
Error: Expecting END MODULE statement at (1)
temp.f90:4:24:

    4 | integer, intent(in) :: i
      |                        1
Error: Symbol at (1) is not a DUMMY variable

ifx says

temp.f90(3): error #6218: This statement is positioned incorrectly and/or has syntax errors.
function twice(i) result(j)
^
temp.f90(6): error #6274: This statement must not appear in the specification part of a module.
j = 2*i
^
temp.f90(4): error #6451: A dummy argument name is required in this context.   [I]
integer, intent(in) :: i
-----------------------^
temp.f90(7): error #6786: This is an invalid statement; an END [MODULE] statement is required.
end function twice
^
temp.f90(7): error #6785: This name does not match the unit name.   [TWICE]
end function twice
-------------^
temp.f90(8): error #6790: This is an invalid statement; an END [PROGRAM]  statement is required.
end module m
^
temp.f90(8): error #6785: This name does not match the unit name.   [M]
end module m
-----------^
compilation aborted for temp.f90 (code 1)

and LFortran says

syntax error: Token 'function' is unexpected here
 --> input:3:1
  |
3 | function twice(i) result(j)
  | ^^^^^^^^ 

Ideally they would say something like “missing CONTAINS statement in module before procedure definition”. Fortran novices may be confused by the current error messages, although Grok and ChatGPT 4o do explain the problem when given the code and gfortran error messages.

1 Like

Back when I was in college, we were using PL/C. a PL/I compiler that was “error correcting”. If it found a syntax error it would try to guess what the user intended, insert its correction, and put in the listing file (remember those?) “PL/C uses …” followed by its correction. This worked for some simplistic cases, but often fell down for others. If it got really confused, it would throw out the entire statement, reporting “PL/C uses ‘;’”

I was an undergraduate teaching assistant, and students would come up to me with their listing, asking why their program didn’t work. Often, they’d tell me that they changed the program to what “the computer” told them to do, almost always not what they wanted.

This is my way of suggesting that having the compiler offer one possible correction is likely to create more problems than it solves. This could perhaps be tempered by different wording, but maybe they wanted INTERFACE instead (assuming the compiler doesn’t look farther ahead to analyze what the programmer’s intentions may have been.)

3 Likes

Good catch @Beliavsky, I agree compilers should have better error messages for this case (I created an issue for LFortran here: Give a better error message when `contains` is missing ¡ Issue #7207 ¡ lfortran/lfortran ¡ GitHub).

I also agree with @sblionel’s comment. For those reasons I think a compiler should not try to guess.

However, I think it can still try to suggest, or even just ask a leading question, to help the user. For example in the above, it could say “help: did you mean to put contains or interface above?” or something like that. Kind of like most modern compilers recommend a different variable name if a misspelling was found (“error: use of undeclared identifier ‘my_it’; did you mean ‘my_int’?”). Users need to learn not to blindly apply such suggestions, but think about if that’s what they meant.

2 Likes

A similar pattern often happens at my company with inexperienced developers after they perform a git rebase and try to git push without --force or --force-with-lease. They get an error like this:

Pushing to git@github.com:some-project/some-repo.git
To git@github.com:some-project/some-repo.git
  ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@github.com:some-project/some-repo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Note the horrible advice therein suggesting a git pull. One developer followed this advice after multiple rebases, six or seven times. As a result his branch was a huge mess of repeated commits merging into each other.

1 Like

Yes, git is an example of a great technology underneath, but a terrible user interface. And things have gotten a lot better over the past 20 years.