[Chapel Merge] Avoid unnecessary instantiations for generic funct

Branch: refs/heads/master
Revision: 32ea5bc
Author: mppf
Log Message:

Merge pull request #16479 from mppf/investigate-extra-insns

Avoid unnecessary instantiations for generic functions with later concrete arguments

Resolves #16470.
Resolves #15928.

In the issue #16470, we were seeing problems with Arkouda running into
the instantiation limit for certain _cast functions that should not
have been candidates for most calls. I was able to create a small
reproducer as shown in #16470. This PR fixes the problem by ruling out
generic candidate functions before instantiation in more cases.

For example, a cast function like
proc _cast(type t, arg: int(32)) where t == string
was being instantiated for a call site with two c_ptr
typed arguments. In other words, the fact that the function couldn’t
possibly match due to passing a pointer actual argument to an int(32)
formal argument was not used by the compiler before instantiating.

The problem is that checkGenericFormals doesn’t actually check any
arguments that don’t have their type established yet. Meanwhile,
tagIfGeneric/hasGenericFormals (which is called early in
ResolutionCandidate::isApplicable) establishes the types for arguments
up until the first generic argument (because at that point, it has served
its purpose - it knows the function is generic). As a result,
checkGenericFormals was only checking arguments up to and including the
first generic argument.

There is one situation in which it would be impractical to establish the
type for a second generic argument before instantiating the function
signature. In particular, the language allows the types of later
arguments to depend on earlier arguments. For example, in
proc f(a, b: typeFn(a.type)),
the type for the second argument cannot really be
established without performing substitutions (which is currently done
when instantiating the signature).

This PR improves the situation by adjusting hasGenericFormals to
establish the types for all arguments up until an argument is encountered
that has a type expression that mentions a previous generic argument.
Note that some of these arguments can still have generic types. This
allows cases like the cast above to be ruled out before instantiation
while still allowing cases like f above to work correctly.

This PR only offers modest improvement in compile time but is probably
worthwhile anyway. I have observed compilation time improvements when
compiling hello.chpl with a debug build of the compiler. With an
optimized compiler, the time to compile hello.chpl is not very much
changed by this PR. However it happens to resolve the case described in #15928
(because more argument types are established to be checked) and it
should reduce problems with programs that come near to the instantiation
limit.

Reviewed by @vasslitvinov - thanks!

  • [x] full local futures testing

Modified Files:
A test/functions/resolution/error-expected-param-missing-15928.chpl
A test/functions/resolution/error-expected-param-missing-15928.good
A test/functions/resolution/error-expected-param-missing.chpl
A test/functions/resolution/error-expected-param-missing.good
A test/functions/resolution/error-expected-param-missing2.bad
A test/functions/resolution/error-expected-param-missing2.chpl
A test/functions/resolution/error-expected-param-missing2.future
A test/functions/resolution/error-expected-param-missing2.good
M compiler/AST/FnSymbol.cpp
M modules/standard/Heap.chpl
M test/functions/export/exportGenericArgs.good
M test/studies/beer/bradc/beer-promoted-infer.good

Compare: https://github.com/chapel-lang/chapel/compare/bd199832e851...32ea5bcdbb0b