New Issue: Problem with instantiation caching for different POIs

18081, "mppf", "Problem with instantiation caching for different POIs", "2021-07-20T17:21:39Z"

(See also PR #16261 and issue #16261)

As of 1.23, the compiler tries to provide a behavior that caching of instantiations does not change program behavior.
However this is not the case with the following program:

module G {
  proc foo(param arg:int, val:int) { // "int variant"
    bar(arg);
  }
  proc foo(param arg:int, val:real) { // "real variant"
    bar(arg);
  }
}
module M1 {
  use G;
  proc bar(arg: int) {
    writeln("In M1.bar ", arg);
  }
  proc runM1() {
    writeln("In runM1");
    foo(1, 20);
  }
}

module M2 {
  use G;
  proc bar(arg: int) {
    writeln("In M2.bar ", arg);
  }
  proc runM2() {
    writeln("In runM2");
    foo(1, 20.0);
  }
}

module User {
  use M1, M2;
  proc main() {
    runM1();
    runM2();
  }
}

Current program output:

In runM1
In M1.bar 1
In runM2
In M1.bar 1

Expected program output:

In runM1
In M1.bar 1
In runM2
In M2.bar 1

I came across this when thinking about the structure of function resolution in the compiler rework.

What I think is happening here is that the instantiation caching strategy relies on the function body being resolved. In this particular program, within runM1, the signatures of both versions of foo are resolved, but only the body of the int variant is resolved. As a result, the CalledFunInfo entries are not gathered yet. Then, in runM2, when considering if the existing instantiation of the real variant of foo can be reused, the compiler concludes that it can be reused because there were no CalledFunInfo to rule it out.

Reasonable fixes might be to:

  • forget that the function signature for the real variant of foo was created in runM1 since it wasn't used anyway; or
  • when considering reusing the real variant of foo in runM2, the compiler can fully resolve that function (in order to be able to make a determination of whether or not it can be reused in the current case). Note that if this strategy is chosen, the compiler will need to be able to hide any errors encountered when resolving the body of the real variant of foo (since that version is actually never called in the program).