Skip to content

Commit

Permalink
Spec changes for const [cvref] (chapel-lang#23447)
Browse files Browse the repository at this point in the history
This PR adjusts the spec to change the approach for the default &
`const` intent to mean `const` [cvref] (chapel-lang#21499). It builds upon PR
chapel-lang#23097.
* The approach used here is to describe `const` intent as one where the
compiler will choose between `const in` and `const ref`, with the
implication that programs relying on one or the other (due to updates to
the referred-to-value by other means than the formal) will have
unexpected behavior when the compiler makes a different choice. As an
extension to the above implication, it adds the constraint that the
compiler can assume that the referred-to value will not change.
* This leaves it implementation-dependent for example whether a
`.locale` query on a `const` (including default intent for most types)
formal argument will refer to the original value when the compiler
chooses `const ref` vs to a local copy when it chooses `const in`.
* The PR switches to treating `const` as a concrete intent and removes
the distinction between abstract and concrete intents. The
abstract/concrete structure is not worth keeping just for the exception
that the default intent for `sync` and `atomic` is `ref`.

Additionally this PR adjusts the spec to take the following steps to
address concerns raised in chapel-lang#22770:
* disallow const arrays over domains that could change (to address a
correctness concern)
* require const domain formals to remain unchanged during the call
(although this is an implication of the more general extension to the
implication that is described above)
* require the domain of a const array formal to remain unchanged during
the call (to address a concern about the optimizability of Chapel
programs).

As we gain experience with these rules, and in particular, as we
implement compiler changes to rely on them, we will almost certainly
update the spec to make it more specific. The language in this version
is intentionally general to give us more room to avoid breaking programs
that follow the spec.

Reviewed by @vasslitvinov - thanks!
  • Loading branch information
mppf authored Sep 21, 2023
2 parents 9fc54a0 + ae585b9 commit 1a5b927
Show file tree
Hide file tree
Showing 9 changed files with 284 additions and 123 deletions.
9 changes: 6 additions & 3 deletions doc/rst/language/spec/arrays.rst
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,12 @@ Array Values

An array’s value is the collection of its elements’ values. Assignments
between array variables are performed by value as described
in :ref:`Array_Assignment`. Chapel semantics are defined so that
the compiler will never need to insert temporary arrays of the same size
as a user array variable.
in :ref:`Array_Assignment`.

When an array is stored in a ``const`` variable, the array elements are
immutable. Undefined behavior will result if the domain is modified (see
:ref:`Association_of_Arrays_to_Domains`) since that would necessarily
add or remove elements.

Array literal values can be either rectangular or associative,
corresponding to the underlying domain which defines its indices.
Expand Down
4 changes: 2 additions & 2 deletions doc/rst/language/spec/classes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2075,7 +2075,7 @@ For example:

The default intent for :type:`~OwnedObject.owned` is ``const``. See more on
argument intents in the :ref:`Procedures Primer <primers-procedures>` and see
more on the default intent in the :ref:`Default_Intent_for_owned_and_shared`.
more on the default intent in the :ref:`Intents_for_owned_and_shared`.

.. _Owned_Methods:

Expand Down Expand Up @@ -2155,7 +2155,7 @@ See :ref:`about-owned-coercions` for more details and examples.

The default intent for :type:`~SharedObject.shared` is ``const``. See more on
argument intents in the :ref:`Procedures Primer <primers-procedures>` and see
more on the default intent in the :ref:`Default_Intent_for_owned_and_shared`.
more on the default intent in the :ref:`Intents_for_owned_and_shared`.

.. _Shared_Methods:

Expand Down
3 changes: 1 addition & 2 deletions doc/rst/language/spec/conversions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -473,8 +473,7 @@ Implicit Conversions for Function Calls
An implicit conversion for a function call - also called a *coercion* -
occurs when the actual argument of a function call is converted to the
type of the corresponding formal argument, if the formal’s intent is
``param``, ``in``, ``const in``, or an abstract intent
(:ref:`Abstract_Intents`) with the semantics of ``in`` or ``const in``.
``param``, ``in``, ``const in``, ``const``, or the default intent.

Implicit conversions for function calls are allowed between numeric
and boolean types (:ref:`Implicit_NumBool_Conversions`), numeric types
Expand Down
6 changes: 5 additions & 1 deletion doc/rst/language/spec/data-parallelism.rst
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,11 @@ the forall construct implicitly refer to the corresponding shadow
variable.

Each formal argument of a task function or iterator has the default
intent by default. For variables of primitive, enum, and class types,
intent by default. See also :ref:`The_Default_Intent`. Note that the
default intent allows the compiler to assume that the value will not be
concurrently modified, except for values of ``sync`` or ``atomic`` type.

For variables of primitive, enum, and class types,
this has the effect of capturing the value of the variable at task
creation time. Within the lexical scope of the forall construct, the
variable name references the captured value instead of the original
Expand Down
20 changes: 15 additions & 5 deletions doc/rst/language/spec/iterators.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ The syntax to declare an iterator is given by:
identifier
yield-intent:
'const'
'const ref'
'ref'
'param'
Expand Down Expand Up @@ -84,11 +85,20 @@ statement. A yield statement in an iterator that yields references must
yield an lvalue expression.

The iterator's ``yield-intent`` determines how each value is yielded.
The rules for yielding are the same as the rules for returning values
from procedures, see :ref:`Return_Intent`, except an iterator with
the ``ref`` or ``const ref`` yield intent is allowed to yield an lvalue
that is local to the iterator's scope.
The rules for yielding a tuple are specified in :ref:`Tuple_Yield_Behavior`.
The rules for yielding are similar to the rules for returning values from
procedures (described in :ref:`Return_Intent`), with these exceptions:

1. The default yield intent is ``const``.

2. The default and the ``const`` yield intents make it up to the
implementation to choose between yielding with ``const ref`` or
``out``.

3. An iterator with the ``ref`` or ``const ref`` yield intent is
allowed to yield an lvalue that is local to the iterator's scope.

4. The rules for yielding a tuple are specified in
:ref:`Tuple_Yield_Behavior`.

When a ``return`` is encountered, the iterator finishes without yielding
another index value. The ``return`` statements appearing in an iterator
Expand Down
Loading

0 comments on commit 1a5b927

Please sign in to comment.