Skip to content

Commit 00917d5

Browse files
authored
Spec updates for ranges and domains (#23521)
This PR makes the following changes, mostly in the language spec: * Remove the difference between the definitions of "the range has ambiguous alignment" and "the range is ambiguously aligned". * Add implicit conversions for ranges and updates explicit conversions for ranges and domains. * Remove several counter-productive where-clauses from online docs. * Indicate that `domain` written by itself is generic. TODO: * [ ] Add implicit conversions for domains. * [ ] Move these configs out of the spec because they are purely about the implementation: newSliceRule, newRangeLiteralType, noNegativeStrideWarnings. * [ ] Replace "ambiguously aligned" and "alignment is unambiguous" with "[un]aligned" throughout ChapelRange.chpl. r: @DanilaFe
2 parents cea1566 + 14e6261 commit 00917d5

File tree

5 files changed

+108
-63
lines changed

5 files changed

+108
-63
lines changed

doc/rst/language/spec/conversions.rst

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ the referenced subsections:
5353
compile-time
5454
constant (:ref:`Implicit_Compile_Time_Constant_Conversions`),
5555

56+
- ranges (:ref:`Implicit_Range_Conversions`),
57+
5658
- class types (:ref:`Implicit_Class_Conversions`), and
5759

5860
- when the source type is a subtype of the target type (including when
@@ -174,6 +176,30 @@ implicitly convert:
174176
* to ``uint`` of matching or greater size or to ``real``
175177
* or, to ``complex`` of any size.
176178

179+
.. _Implicit_Range_Conversions:
180+
181+
Implicit Range Conversions
182+
~~~~~~~~~~~~~~~~~~~~~~~~~~
183+
184+
Implicit conversions among range types are allowed when all values
185+
representable in the source type can also be represented in the target
186+
type, retaining their full precision. In particular, an implicit
187+
conversion is allowed when:
188+
189+
* the ``idxType`` of the source can be implicitly converted
190+
to the ``idxType`` of the target,
191+
192+
* the ``bounds`` of the source and the target are the same, and
193+
194+
* one of the following holds:
195+
196+
- the ``strides`` of the source and the target are the same,
197+
- the ``strides`` of the target is ``any``,
198+
- the ``strides`` of the target is ``positive``
199+
and the ``strides`` of the source is ``one``, or
200+
- the ``strides`` of the target is ``negative``
201+
and the ``strides`` of the source is ``negOne``.
202+
177203
.. _Implicit_Class_Conversions:
178204

179205
Implicit Class Conversions
@@ -389,7 +415,8 @@ the following program locations:
389415
Implicit conversions for initialization or assignment are allowed between
390416
numeric and boolean types (:ref:`Implicit_NumBool_Conversions`), numeric
391417
types in the special case when the expression’s value is a compile-time
392-
constant (:ref:`Implicit_Compile_Time_Constant_Conversions`), class types
418+
constant (:ref:`Implicit_Compile_Time_Constant_Conversions`), ranges
419+
(:ref:`Implicit_Range_Conversions`), class types
393420
(:ref:`Implicit_Class_Conversions`), and for generic target types
394421
(:ref:`Subtype_Arg_Conversions`).
395422

@@ -478,7 +505,8 @@ type of the corresponding formal argument, if the formal’s intent is
478505
Implicit conversions for function calls are allowed between numeric
479506
and boolean types (:ref:`Implicit_NumBool_Conversions`), numeric types
480507
in the special case when the expression’s value is a compile-time
481-
constant (:ref:`Implicit_Compile_Time_Constant_Conversions`), class
508+
constant (:ref:`Implicit_Compile_Time_Constant_Conversions`),
509+
ranges (:ref:`Implicit_Range_Conversions`), class
482510
types (:ref:`Implicit_Class_Conversions`), and for generic target
483511
types (:ref:`Subtype_Arg_Conversions`).
484512

@@ -768,18 +796,28 @@ expression or a type expression.
768796
Explicit Range Conversions
769797
~~~~~~~~~~~~~~~~~~~~~~~~~~
770798

771-
An expression of a range type with ``strides=strideKind.any``
772-
can be explicitly converted to a range type with ``strides=strideKind.one``,
773-
changing the stride to 1 in the process.
799+
An expression of a range type can be explicitly converted to another
800+
range type with the same ``bounds`` parameter. Upon such conversion,
801+
each non-infinite bound of the source is explicitly converted
802+
to the target's ``idxType``. The explicit conversion for ranges
803+
is not allowed when the explicit conversion between their ``idxTypes``
804+
is not allowed.
805+
806+
The explicit conversion results in an error when the ``stride`` value
807+
of the source is not legal for the target type. This may be the case
808+
either because the source stride is not representable within the
809+
target's stride type or it is of the opposite sign than expected
810+
by the target's ``strides`` parameter.
774811

775812
.. _Explicit_Domain_Conversions:
776813

777814
Explicit Domain Conversions
778815
~~~~~~~~~~~~~~~~~~~~~~~~~~~
779816

780-
An expression of a domain type with ``strides=strideKind.any``
781-
can be explicitly converted to a domain type with ``strides=strideKind.one``,
782-
changing all strides to 1 in the process.
817+
An expression of a rectangular domain type can be explicitly converted
818+
to another rectangular domain type of the same ``rank``.
819+
Such conversion is performed dimension-wise following the rules
820+
for explicit range conversions (see :ref:`Explicit_Range_Conversions`).
783821

784822
.. _Explicit_String_to_Bytes_Conversions:
785823

doc/rst/language/spec/domains.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ types include all of the associative domain types.
134134
These base domain types are discussed in turn in the following
135135
subsections.
136136

137+
The keyword ``domain``, when not followed by parentheses, refers to
138+
a generic type that can be instantiated with any domain type.
139+
This type may also be written as ``domain(?)``.
140+
137141
Rectangular Domains
138142
~~~~~~~~~~~~~~~~~~~
139143

doc/rst/language/spec/ranges.rst

Lines changed: 50 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ follows.
4646
explicitly. Instead, infinite bound(s) are represented implicitly in
4747
the range’s type (:ref:`Range_Types`). When the low and/or high
4848
bound is :math:`\infty`, the represented sequence is unbounded in the
49-
corresponding direction(s).
49+
corresponding direction(s). However, when indices are drawn from
50+
a finite type, such as booleans or enum constants, the represented
51+
sequence always terminates when it runs out of legal indices
52+
of this type.
5053

5154
- The *stride* is a non-zero integer. It defines the distance between
5255
any two adjacent members of the represented sequence. The sign of the
@@ -58,55 +61,39 @@ follows.
5861

5962
- The *alignment* is either a specific index value or is *ambiguous*.
6063
It defines how the represented sequence’s members are aligned
61-
relative to the stride. For a range with a stride other than 1 or -1,
62-
ambiguous alignment means that the represented sequence is undefined.
63-
In such a case, certain operations discussed later result in an
64-
error.
65-
The alignment is always between zero and :math:`|stride|-1`,
66-
inclusively.
67-
68-
More formally, the represented sequence for the range
69-
:math:`(low, high, stride, alignmt)` contains all indices :math:`ix`
70-
such that:
71-
72-
=========================================================================== ============================================
73-
:math:`low \leq ix \leq high` if :math:`stride = 1` or :math:`stride = -1`
74-
:math:`low \leq ix \leq high` and :math:`ix \equiv alignmt \pmod{|stride|}` if :math:`alignmt` is not ambiguous
75-
the represented sequence is undefined otherwise
76-
=========================================================================== ============================================
77-
78-
The sequence, if defined, is increasing if :math:`stride > 0` and
79-
decreasing if :math:`stride < 0`.
64+
relative to the stride. The alignment, when unambiguous,
65+
is always between zero and :math:`|stride|-1`, inclusively.
66+
67+
A range with unambiguous alignment is called *aligned*. Otherwise
68+
the range is *unaligned* and its represented sequence is undefined.
69+
70+
The represented sequence for an aligned range
71+
:math:`(low, high, stride, alignmt)`
72+
with integral indices contains all indices :math:`ix` such that:
73+
74+
:math:`low \leq ix \leq high` and :math:`ix \equiv alignmt \pmod{|stride|}`
8075

8176
If the represented sequence is defined but there are no indices
82-
satisfying the applicable equation(s) above, the range and its
77+
satisfying the above equation, the range and its
8378
represented sequence are *empty*. A common case of this occurs when the
8479
low bound is greater than the high bound.
8580

8681
We say that a value :math:`ix` is *aligned* w.r.t. the range
8782
:math:`(low, high, stride, alignmt)` if:
8883

89-
- :math:`alignmt` is not ambiguous and
90-
:math:`ix \equiv alignmt \pmod{|stride|}`, or
91-
92-
- :math:`stride` is 1 or -1.
84+
:math:`alignmt` is not ambiguous and
85+
:math:`ix \equiv alignmt \pmod{|stride|}`.
9386

9487
Furthermore, :math:`\infty` is never aligned.
9588

9689
Ranges have the following additional properties.
9790

98-
- A range is *ambiguously aligned* if
99-
100-
- its alignment is ambiguous, and
101-
102-
- its stride is neither 1 nor -1.
103-
10491
- The *first index* is the first member of the represented sequence.
10592

10693
A range *has no* first index when the first member is undefined, that
10794
is, in the following cases:
10895

109-
- the range is ambiguously aligned,
96+
- the range is unaligned,
11097

11198
- the represented sequence is empty,
11299

@@ -121,7 +108,7 @@ Ranges have the following additional properties.
121108
A range *has no* last index when the last member is undefined, that
122109
is, in the following cases:
123110

124-
- it is ambiguously aligned,
111+
- the range is unaligned,
125112

126113
- the represented sequence is empty,
127114

@@ -156,8 +143,8 @@ Range Types
156143
The type of a range is characterized by three properties:
157144

158145
- ``idxType`` is the type of the values in the range’s represented
159-
sequence. However, when the range’s low and/or high bound is
160-
:math:`\infty`, the represented sequence also contains indices that
146+
sequence. However, when the range’s represented sequence is infinite,
147+
it also contains indices that
161148
are not representable by ``idxType``.
162149

163150
``idxType`` must be an integral, boolean, or enumerated type and is
@@ -242,8 +229,8 @@ header:
242229
param bounds = boundKind.both,
243230
param strides = strideKind.one) type
244231
245-
As a special case, the keyword ``range`` without a parenthesized
246-
argument list refers to the range type with the default values of all
232+
As a special case, the keyword ``range`` written without a parenthesized
233+
argument list refers to the concrete range type with the default values of all
247234
its parameters, i.e., ``range(int, boundKind.both, strideKind.one)``.
248235

249236
*Example (rangeVariable.chpl)*.
@@ -346,7 +333,7 @@ The value of a range literal is as follows:
346333

347334
- The stride is 1.
348335

349-
- The alignment is ambiguous.
336+
- The alignment is 0.
350337

351338
.. _Range_Default_Values:
352339

@@ -378,11 +365,6 @@ the type’s ``bounds`` parameter as follows:
378365
``high``-bounded range (or visa versa) produces an empty range,
379366
matching the default value for a ``both``-bounded range
380367

381-
.. warning::
382-
383-
Default initialization of ranges with ``boundKind.low`` or
384-
``boundKind.high`` is unstable.
385-
386368
Default values of ranges with boolean ``idxType`` are similar, but
387369
substituting ``false`` and ``true`` for 0 and 1 above. Ranges with
388370
``enum`` ``idxType`` use the 0th and 1st values in the enumeration in
@@ -391,6 +373,12 @@ default value uses the 0th value as the low bound and has an undefined
391373
high bound; the ``.size`` query should be used with such ranges before
392374
querying the high bound to determine whether or not it is valid.
393375

376+
.. warning::
377+
378+
Default initialization of ranges with ``boundKind.low`` or
379+
``boundKind.high`` is unstable w.r.t. the value of their
380+
finite bound.
381+
394382
.. _Ranges_Common_Operations:
395383

396384
Common Operations
@@ -445,12 +433,9 @@ Ranges can be compared using equality and inequality.
445433

446434
.. warning::
447435

448-
Equality comparisons for ranges over ``enum`` or ``bool`` types
449-
when one of the ranges is bounded and the other is unbounded
450-
is currently unstable.
451-
We currently treat both ranges as being bounded.
452-
This might change in the future.
453-
436+
Equality comparisons currently treat ranges over ``enum`` or ``bool`` types
437+
as bounded on both ends regardless of their ``bounds`` parameters.
438+
This behavior is unstable and might change in the future.
454439

455440
.. function:: operator ==(r1: range(?), r2: range(?)): bool
456441

@@ -844,8 +829,7 @@ the specified number of indices. Specifically:
844829
It is an error to apply the count operator with a positive count to a
845830
range that has no first index. It is also an error to apply the count
846831
operator with a negative count to a range that has no last index. It is
847-
an error to apply the count operator to a range that is ambiguously
848-
aligned.
832+
an error to apply the count operator to an unaligned range.
849833
It is an error if the count is greater than the ``size`` of the range.
850834

851835
*Example (rangeCountOperator.chpl)*.
@@ -872,6 +856,12 @@ It is an error if the count is greater than the ``size`` of the range.
872856
Each of these ranges represents the ordered set of three indices: 6,
873857
4, 2.
874858

859+
.. warning::
860+
861+
The count operator currently treats ranges over ``enum`` or ``bool`` types
862+
as bounded on both ends regardless of their ``bounds`` parameters.
863+
This behavior is unstable and might change in the future.
864+
875865
.. _Range_Arithmetic:
876866

877867
Arithmetic Operators
@@ -897,8 +887,8 @@ the result range are the same as for the input range.
897887
The stride of the resulting range is the same as the stride of the
898888
original. The alignment of the resulting range is shifted by the same
899889
amount as the high and low bounds. It is permissible to apply the shift
900-
operators to a range that is ambiguously aligned. In that case, the
901-
resulting range is also ambiguously aligned.
890+
operators to an unaligned range. In that case, the
891+
resulting range is also unaligned.
902892

903893
*Example (rangeAdd.chpl)*.
904894

@@ -922,6 +912,11 @@ resulting range is also ambiguously aligned.
922912
923913
(0..3, 1..4)
924914
915+
.. warning::
916+
917+
These operators are unstable.
918+
They may be removed or change behavior in the future.
919+
925920
.. _Range_Slicing:
926921

927922
Range Slicing
@@ -969,8 +964,8 @@ Range slicing is specified by the syntax:
969964
970965
(1..20, 3..20, 1..20 by 2, 1..20 by 6 align 3)
971966
972-
It is an error for the first operand to be ambiguously aligned.
973-
If the second operand is ambiguously aligned, it is replaced
967+
It is an error for the first operand to be unaligned.
968+
If the second operand is unaligned, it is replaced
974969
with a range that is identical except it is given an alignment
975970
in such a way that that the intersection of the two ranges'
976971
represented sequences is non-empty, if possible.

modules/internal/ChapelDomain.chpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2889,6 +2889,7 @@ module ChapelDomain {
28892889
do not fit in the new idxType or when the original stride(s)
28902890
are not legal for the new `strides` parameter.
28912891
*/
2892+
pragma "no where doc"
28922893
proc tryCast(type t: domain)
28932894
where chpl__isRectangularDomType(t) && this.isRectangular()
28942895
&& this.chpl_domainTryCastIsSafe(t)

modules/internal/ChapelRange.chpl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,12 +677,14 @@ module ChapelRange {
677677

678678

679679
/* Returns the range's stride. */
680+
pragma "no where doc"
680681
inline proc range.stride where !hasParamStride() do return _stride;
681682

682683
@chpldoc.nodoc proc range.stride param where hasParamStride() do
683684
return (if strides == strideKind.one then 1 else -1) : strType;
684685

685686
/* Returns the range's alignment. */
687+
pragma "no where doc"
686688
inline proc range.alignment where !hasParamAlignment() do
687689
return chpl_intToIdx(if hasParamAlignmentField() then 0 else _alignment);
688690

@@ -691,6 +693,7 @@ module ChapelRange {
691693

692694
/* Returns ``true`` if the range's alignment is unambiguous,
693695
``false`` otherwise. */
696+
pragma "no where doc"
694697
inline proc range.isAligned() where !hasParamAligned() do
695698
return _alignment != unalignedMark;
696699

@@ -699,6 +702,7 @@ module ChapelRange {
699702

700703
/* Returns ``true`` if the range's alignment is unambiguous,
701704
``false`` otherwise. */
705+
pragma "no where doc"
702706
@deprecated("'range.aligned' is deprecated; please use '.isAligned()' instead")
703707
inline proc range.aligned where !hasParamAligned() do
704708
return isAligned();
@@ -1242,6 +1246,7 @@ module ChapelRange {
12421246

12431247
/* Returns ``true`` if this range is naturally aligned, ``false``
12441248
otherwise. */
1249+
pragma "no where doc"
12451250
@deprecated("'range.isNaturallyAligned()' is deprecated; please feel encouraged to file a GitHub issue requesting it: https://github.com/chapel-lang/chapel/issues")
12461251
proc range.isNaturallyAligned()
12471252
where ! hasPosNegUnitStride() && bounds != boundKind.neither
@@ -1253,6 +1258,7 @@ module ChapelRange {
12531258
do return chpl_isNaturallyAligned();
12541259

12551260
// tells whether omitting the 'align' clause results in the same range
1261+
pragma "no where doc"
12561262
proc range.chpl_isNaturallyAligned()
12571263
where ! hasPosNegUnitStride() && bounds != boundKind.neither
12581264
do if bounds == boundKind.both {
@@ -1274,6 +1280,7 @@ module ChapelRange {
12741280

12751281
/* Returns ``true`` if the range is ambiguously aligned, ``false``
12761282
otherwise. */
1283+
pragma "no where doc"
12771284
@deprecated("'range.isAmbiguous()' is deprecated; please use '! range.isAligned()' instead")
12781285
proc range.isAmbiguous() param where hasPosNegUnitStride() do
12791286
return ! isAligned();

0 commit comments

Comments
 (0)