Skip to content

Commit

Permalink
Improve errors for missue of Sort with arrays and domains (#25863)
Browse files Browse the repository at this point in the history
Improves the errors thrown by the Sort module (and .sorted() method)
when it is used incorrectly by passing unsupported array.domain types.

This PR also adds a warning to `assocDomain.sorted()`, but it does not
deprecate it to maintain backwards compatibility.

- [x] tested with a full paratest with/without comm
- [x] checked that docs build and render properly

Resolves #25109

[Reviewed by @ShreyasKhandekar]
  • Loading branch information
jabraham17 authored Sep 4, 2024
2 parents e732ba1 + 33040d3 commit 382fdc9
Show file tree
Hide file tree
Showing 75 changed files with 340 additions and 143 deletions.
23 changes: 19 additions & 4 deletions modules/internal/ChapelDomain.chpl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ module ChapelDomain {
@chpldoc.nodoc
config param noNegativeStrideWarnings = false;

@chpldoc.nodoc
config param noSortedWarnings = false;

pragma "no copy return"
pragma "return not owned"
proc _getDomain(value) {
Expand Down Expand Up @@ -2791,11 +2794,23 @@ module ChapelDomain {
}

// associative array interface
/* Yields the domain indices in sorted order. */
/*
Yields the domain indices in sorted order. This method is only supported
on associative domains.
.. warning::
It is recommended to use :proc:`Sort.sorted` instead of this method.
*/
iter sorted(comparator:?t = chpl_defaultComparator()) {
for i in _value.dsiSorted(comparator) {
yield i;
}
if !this.isAssociative() then
compilerError("'.sorted()' is only supported on associative domains");
if !noSortedWarnings then
compilerWarning(
"It is recommended to use 'Sort.sorted' instead of this method. ",
"Compile with '-snoSortedWarnings' to suppress this warning.");
for x in this._value.dsiSorted(comparator) do yield x;
}

@chpldoc.nodoc
Expand Down
3 changes: 2 additions & 1 deletion modules/packages/ReplicatedVar.chpl
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ proc rcCollect(replicatedVar: [?D] ?MYTYPE, ref collected: [?CD] MYTYPE): void
var targetLocales = _rcTargetLocalesHelper(replicatedVar);
assert(replicatedVar.domain == rcDomainBase);
for idx in collected.domain do assert(targetLocales.domain.contains(idx));
coforall (idx, col) in zip(targetLocales.domain.sorted(), collected) do
import Sort;
coforall (idx, col) in zip(Sort.sorted(targetLocales.domain), collected) do
on targetLocales[idx] do
col = replicatedVar[rcDomainIx];
}
Expand Down
23 changes: 18 additions & 5 deletions modules/standard/Sort.chpl
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,11 @@ proc sort(ref x: [?Dom] , comparator:? = new DefaultComparator(), param stable:b
where Dom.rank != 1 || !x.isRectangular() {
compilerError("sort() is currently only supported for 1D rectangular arrays");
}
@chpldoc.nodoc
proc sort(ref x: domain,
comparator:? = new DefaultComparator(),
param stable:bool = false) do
compilerError("sort() is not supported on domains");

/*
Check if array `x` is in sorted order
Expand Down Expand Up @@ -868,9 +873,12 @@ proc isSorted(x: list(?), comparator:? = new DefaultComparator()): bool {
@chpldoc.nodoc
/* Error message for multi-dimension arrays */
proc isSorted(x: [], comparator:? = new DefaultComparator())
where x.domain.rank != 1 {
compilerError("isSorted() requires 1-D array");
where x.rank != 1 || !x.isRectangular() {
compilerError("isSorted() is currently only supported for 1D rectangular arrays");
}
@chpldoc.nodoc
proc isSorted(x: domain, comparator:? = new DefaultComparator()) do
compilerError("isSorted() is not supported on domains");

/*
Check if array `Data` is in sorted order
Expand All @@ -890,6 +898,8 @@ proc isSorted(Data: [?Dom] ?eltType, comparator:?rec=defaultComparator): bool {

@chpldoc.nodoc
iter sorted(x : domain, comparator:? = new DefaultComparator()) {
if !x.isAssociative() then
compilerError("sorted() is currently only supported on associative domains");
for i in x._value.dsiSorted(comparator) {
yield i;
}
Expand All @@ -909,8 +919,8 @@ iter sorted(x : domain, comparator:? = new DefaultComparator()) {
//
// TODO - Make standalone or leader/follower parallel iterator
/*
Yield the elements of argument `x` in sorted order, using sort
algorithm.
Yield the elements of argument `x` in sorted order, using the same algorithm
as :proc:`sort`.
.. note:
Expand All @@ -935,7 +945,10 @@ iter sorted(x, comparator:? = new DefaultComparator()) {
}
} else if isArrayValue(x) && Reflection.canResolveMethod(x._value, "dsiSorted") {
compilerError(x._value.type:string + " does not support dsiSorted(comparator)");
} else {
} else if isArrayValue(x) && x.isSparse() {
compilerError("sorted() is not supported on sparse arrays");
}
else {
var y = x; // need to do before isArrayValue test in case x is an iterable
param iterable = isArrayValue(y) || isSubtype(y.type, List.list(?));
if iterable {
Expand Down
13 changes: 7 additions & 6 deletions test/arrays/diten/enumArrayMethods.chpl
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import Sort;
enum E {a=1, b=0, c=2};

var D: domain(E) = E.a..E.c;

writeln(D.sorted());
writeln(Sort.sorted(D));

D -= E.a;
writeln(D.sorted());
writeln(Sort.sorted(D));

D -= E.b;
writeln(D.sorted());
writeln(Sort.sorted(D));

D += E.a;
writeln(D.sorted());
writeln(Sort.sorted(D));

D += E.b;
writeln(D.sorted());
writeln(Sort.sorted(D));

D.clear();
writeln(D.sorted());
writeln(Sort.sorted(D));
5 changes: 3 additions & 2 deletions test/arrays/diten/nestSortedIter.chpl
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import Sort;
var D: domain(int);
D += 1; D += 2; D+=4; D += 3;
for a in D.sorted() {
for b in D.sorted() {
for a in Sort.sorted(D) {
for b in Sort.sorted(D) {
writeln((a,b));
}
}
3 changes: 2 additions & 1 deletion test/associative/bharshbarg/domains/recordWithRange.chpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Sort;
use List;

config const n = 100;
Expand Down Expand Up @@ -58,5 +59,5 @@ for 1..n {
assert(D.size == recs.size);
}

for d in D.sorted() do
for d in Sort.sorted(D) do
writeln(d, " => ", A[d]);
3 changes: 2 additions & 1 deletion test/associative/bradc/assocRecord.chpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Sort;
record Coord {
var x: int;
var y: int;
Expand All @@ -20,7 +21,7 @@ Name(c1) = "z basis coordinate";
Name(c2) = "y basis coordinate";
Name(c3) = "x basis coordinate";

for coord in D.sorted() {
for coord in Sort.sorted(D) {
writeln("coord ", coord, " is called ", Name(coord));
}

Expand Down
3 changes: 2 additions & 1 deletion test/associative/deitz/arrays/test_indefinite4.chpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Sort;
use printHelp;

var d : domain(int);
Expand All @@ -12,5 +13,5 @@ a(5) = 4;
writelnSorted(d);
writelnSortedByDom(a);

for i in d.sorted() do
for i in Sort.sorted(d) do
writeln(i, " -> ", a(i));
3 changes: 2 additions & 1 deletion test/associative/deitz/arrays/test_indefinite5.chpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Sort;
use printHelp;

var d : domain(int);
Expand All @@ -12,5 +13,5 @@ a(0) = 4;
writelnSorted(d);
writelnSortedByDom(a);

for i in d.sorted() do
for i in Sort.sorted(d) do
writeln(i, " -> ", a(i));
3 changes: 2 additions & 1 deletion test/associative/deitz/arrays/test_indefinite6.chpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Sort;
use printHelp;

var d : domain(int);
Expand All @@ -12,5 +13,5 @@ a(0) = 4;
writelnSorted(d);
writelnSortedByDom(a);

for i in d.sorted() do
for i in Sort.sorted(d) do
writeln(i, " -> ", a(i));
3 changes: 2 additions & 1 deletion test/associative/deitz/arrays/test_indefinite7.chpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Sort;
use printHelp;

var d : domain(string);
Expand All @@ -12,5 +13,5 @@ a("zero") = 4;
writelnSorted(d);
writelnSortedByDom(a);

for i in d.sorted() do
for i in Sort.sorted(d) do
writeln(i, " -> ", a(i));
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Sort;
use printHelp;

type t = (int, int);
Expand All @@ -8,5 +9,5 @@ writelnSorted(D);
var A: [D] int;
A((1, 2)) = 5;
A((3, 4)) = 6;
for i in D.sorted() do
for i in Sort.sorted(D) do
writeln((i, A(i)));
5 changes: 3 additions & 2 deletions test/associative/ferguson/plus-reduce-assoc.chpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Sort;
// Can I use + reduce on associative domain?
var D: domain(int);

Expand All @@ -9,8 +10,8 @@ proc makeD(x:int) {

D = + reduce [i in 1..10] makeD(i);

writeln(D.sorted());
writeln(Sort.sorted(D));

var D2 = + reduce for i in 1..10 do makeD(i);

writeln(D2.sorted());
writeln(Sort.sorted(D2));
3 changes: 2 additions & 1 deletion test/associative/ferguson/plus-reduce-intent-assoc.chpl
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import Sort;
// Can use + reduce intent on associative domain?
var D: domain(int);

forall x in 1..10 with (+ reduce D) {
D += x;
}

writeln(D.sorted());
writeln(Sort.sorted(D));
5 changes: 3 additions & 2 deletions test/classes/bradc/arrayInClass/arrayOfArithInClass.chpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Sort;
// declare class types

class ArithC {
Expand All @@ -22,7 +23,7 @@ class EnumC {
}

iter sortedAssoc(arr) {
for k in arr.domain.sorted() {
for k in Sort.sorted(arr.domain) {
yield arr[k];
}
}
Expand All @@ -31,7 +32,7 @@ iter sortedAssoc(arr) {

proc foo(C) {
if (C.x.domain.isAssociative()) {
writeln("C.x.domain is: ", C.x.domain.sorted());
writeln("C.x.domain is: ", Sort.sorted(C.x.domain));
writeln("x is: ", sortedAssoc(C.x));
} else {
writeln("C.x.domain is: ", C.x.domain);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Sort;
// declare class types

class ArithC {
Expand Down Expand Up @@ -30,7 +31,7 @@ class EnumC {
}

iter sortedAssoc(arr) {
for k in arr.domain.sorted() {
for k in Sort.sorted(arr.domain) {
yield arr[k];
}
}
Expand All @@ -39,7 +40,7 @@ iter sortedAssoc(arr) {

proc foo(C) {
if (C.x.domain.isAssociative()) {
writeln("C.x.domain is: ", C.x.domain.sorted());
writeln("C.x.domain is: ", Sort.sorted(C.x.domain));
writeln("x is: ", sortedAssoc(C.x));
} else {
writeln("C.x.domain is: ", C.x.domain);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Sort;
// declare class types

class ArithC {
Expand Down Expand Up @@ -31,7 +32,7 @@ class EnumC {

/* We have to handle nested associative types */
iter sortedOut(arr) {
const ks = if arr.domain.isAssociative() then arr.domain.sorted() else arr.domain;
const ks = if arr.domain.isAssociative() then Sort.sorted(arr.domain) else arr.domain;
for k in ks {
const x = arr[k];
if isArrayType(x.type) && x.domain.isAssociative() {
Expand All @@ -47,7 +48,7 @@ iter sortedOut(arr) {

proc foo(C) {
if (C.x.domain.isAssociative()) {
writeln("C.x.domain is: ", C.x.domain.sorted());
writeln("C.x.domain is: ", Sort.sorted(C.x.domain));
writeln("x is: ", sortedOut(C.x));
} else {
writeln("C.x.domain is: ", C.x.domain);
Expand Down
5 changes: 3 additions & 2 deletions test/classes/bradc/arrayInClass/genericArrayInClass-real.chpl
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Sort;
// declare class types

class ArithC {
Expand Down Expand Up @@ -30,7 +31,7 @@ class EnumC {
}

iter sortedAssoc(arr) {
for k in arr.domain.sorted() {
for k in Sort.sorted(arr.domain) {
yield arr[k];
}
}
Expand All @@ -39,7 +40,7 @@ iter sortedAssoc(arr) {

proc foo(C) {
if (C.x.domain.isAssociative()) {
writeln("C.x.domain is: ", C.x.domain.sorted());
writeln("C.x.domain is: ", Sort.sorted(C.x.domain));
writeln("x is: ", sortedAssoc(C.x));
} else {
writeln("C.x.domain is: ", C.x.domain);
Expand Down
5 changes: 3 additions & 2 deletions test/classes/bradc/arrayInClass/genericClassArray-named.chpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Sort;
iter sortedAssoc(arr) {
for k in arr.domain.sorted() {
for k in Sort.sorted(arr.domain) {
yield arr[k];
}
}
Expand All @@ -11,7 +12,7 @@ class C {

proc foo() {
if (x.domain.isAssociative()) {
writeln("x.domain is: ", x.domain.sorted());
writeln("x.domain is: ", Sort.sorted(x.domain));
writeln("x is: ", sortedAssoc(x));
} else {
writeln("x.domain is: ", x.domain);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Sort;
use HashedDist;

config const verbose = false;
Expand All @@ -20,7 +21,7 @@ D += 2.4;
D += 3.5;

writeln("D is:");
for d in D.sorted() {
for d in Sort.sorted(D) {
writeln(d);
}

Expand All @@ -31,7 +32,7 @@ A(2.4) = "two point four";
A(3.5) = "three point five";

writeln("A is:");
for d in D.sorted() {
for d in Sort.sorted(D) {
writeln(A[d]);
if verbose then
writeln(A[d], " on locale ", A[d].locale);
Expand Down
Loading

0 comments on commit 382fdc9

Please sign in to comment.