chapel-lang/chapel — pull request #324 by vasslitvinov (2014-09-06 05:35:32+00:00)
Title: Implemented const-ness checking for loop index variables

Also changed how _indexOfInterest is detupled in certain cases.

There are various cases that needed to be handled,
the ones I considered are listed in

test/statements/vass/index-variable-const-errors.chpl

The way I decide whether to set FLAG_CONST on the index variable
is based on isReferenceType() of _indexOfInterest and,
in the case it is detupled, on isReferenceType() of the
corresonding tuplel component.

Looking in the future: A solution based on FLAG_REF_VAR
would be preferred. Each index variable would be either
FLAG_CONST or FLAG_REF_VAR. FLAG_REF_TO_CONST would be
added to the latter if appropriate.

I set FLAG_INDEX_OF_INTEREST on temporaries to handle the case
of the index variables forming a tuple of a tuple, e.g.

for ((i1,i2),a) in zip(my_2D_domain, myArray) ...

A tricky case is a zippered loop with a 'var' iterator,
and a single index variable, i.e. with no detupling:

for myVar in zip(...) ...

Ideally we would like myVar(i) to be mutable for those
'i' positions that correspond to mutable iterators,
and const for the other positions.

Currently, in the above, myVar is considered 'const'.
I hope this makes sense.
All myVar(i) are mutable, however, because checking
accesses to const tuples is not implemented.

Another tricky case is a regular loop where the iterator
returns a tuple containing an array. I did not look
into this case specifically.

On how _indexOfInterest is detupled:

The compiler currently creates a generic detupling expression
_indexOfInterest(1) etc. during parsing/in build.cpp.

During resolution this used to get converted to

(A) PRIM_GET_MEMBER i.e. address of _indexOfInterest(1)
if that member's type is non-reference

(B) PRIM_GET_MEMBER_VALUE if the member has a reference type

This actually makes sense. For (B) the address is fetched from the tuple
directly. This transports a Chapel-level reference.
For (A), the compiler did not specialize for _indexOfInterest.
In general, it is unknown whetherh myTuple(i) will be used
as a reference or as a value, to the more general choice
is made, and later transformations deal with this somehow.

For _indexOfInterest, however, we know that (A) will
be constant, so will not be used as a reference, so
we can use PRIM_GET_MEMBER_VALUE directly.
However, we still need to watch out when the entire
tuple has a _ref type, e.g. _ref(int*2). This indicates
that the tuple comes from a tuple-yielding 'var' iterator.
It so happens that we need PRIM_GET_MEMBER in this case.

My motivation for this change is that I need it for my
upcoming forall intents.

TEST CHANGES

There were a couple of tests that assumed that index variables
are mutable. I modified them to comply with my checks.

Those tests seemed so convincing, however, that I feel
we should allows them optionally, e.g. using 'var' keyword:

for myVar in ... // myVar is const
for var myVar in ... // myVar can be modified

I filed a future for this.

This resolves David's recent future on the subject. I augmented .good
because the compiler reports both const errors in a single pass.