[Chapel Merge] Richer array literal element type inference

Branch: refs/heads/main
Revision: b3e5396
Author: bradcray
Link: Richer array literal element type inference by bradcray · Pull Request #20563 · chapel-lang/chapel · GitHub
Log Message:

Merge pull request #20563 from bradcray/array-literal-first-elt-wins

Richer array literal element type inference

[reviewed by @vasslitvinov, and @bmcdonald3 reviewed and
provided feedback on an earlier draft]

In #8196, users have (understandably) complained about how poor
Chapel's type unification for array literals is. Specifically, an array
literal's type is currently based on its first element's type, and all
subsequent elements must match precisely or an error is generated.
This means that [1.0, 2] and [1, 2.0] are inferred to be array of
real and array of int respectively, and that an error is flagged because
the second element doesn't match the initial one.

In this PR, I've implemented a module-based strategy to improve upon
this behavior. With it, the module code will inspect all array elements,
trying to determine a most satisfying type for them. I did this by writing
a utility routine that iterates over all of the elements in a param loop,
returning each of them in its own iteration, and then querying the return
type of that routine to leverage return type unification. This causes the
arrays above to each be inferred to be "array of real" and for the integer
values to turn into their real equivalents.

A downside to this strategy is that it results in code (or, at least, AST),
that's proporational in size to the array literal in order to return all the
elements. That said, so does the pre-existing machinery that builds
the array literal.

In order to generate a reasonable error message, I tagged my routine
with a pragma and made the compiler recognize it when complaining
about inability to resolve return types, substituting in an array-centric
message.

While here, I added special-case code for homogeneous array literals to
avoid the current and new param loops in order to reduce code size and
improve compilation times (and possibly execution times?). I also noticed
that we had some ancient code that was still turning arrays of c-strings
into arrays of strings (and similarly for other data types), which is a remnant
of when we only had one string literal type and they were all C string literals.
That feels simply wrong in today's world where strings and C-strings have
their own literal formats, so as part of clean-up I took it out.

I added some new tests of various degrees of array literal and updated some
existing tests to reflect the new behavior and error message.

Note that as the dyno compiler comes online, we'd really like to move this
reasoning about array literal types out of the module code and into the
compiler, unifying it with other type unification needs like the return type
inference. To that end, this can be considered a baby step in the right
direction until we get there that should help users out (while also
hopefully reducing compile time for homogeneous array literals).

Resolves #8196.

Modified Files:
A test/arrays/literals/cStringLiteral.chpl

A test/arrays/literals/cStringLiteral.good
A test/arrays/literals/hetLiteralsNotUnifiable-local.chpl
A test/arrays/literals/hetLiteralsNotUnifiable-local.good
A test/arrays/literals/hetLiteralsNotUnifiable.chpl
A test/arrays/literals/hetLiteralsNotUnifiable.good
A test/arrays/literals/hetLiteralsUnifiable.chpl
A test/arrays/literals/hetLiteralsUnifiable.good
A test/arrays/literals/homogLiterals.chpl
A test/arrays/literals/homogLiterals.good
M compiler/dyno/include/chpl/uast/PragmaList.h
M compiler/resolution/resolveFunction.cpp
M doc/rst/language/spec/arrays.rst
M modules/internal/ChapelArray.chpl
M modules/internal/ChapelDomain.chpl
M test/arrays/bradc/inferArrayOfDerivedType.bad
M test/arrays/johnk/literals_bad_types.good
M test/release/examples/primers/arrays.chpl

Compare: https://github.com/chapel-lang/chapel/compare/3983a1cc1f9d...b3e539645f00