@@ -881,10 +881,12 @@ class IsContiguousHelper
881881public:
882882 using Result = std::optional<bool >; // tri-state
883883 using Base = AnyTraverse<IsContiguousHelper, Result>;
884- explicit IsContiguousHelper (
885- FoldingContext &c, bool namedConstantSectionsAreContiguous)
886- : Base{*this }, context_{c}, namedConstantSectionsAreContiguous_{
887- namedConstantSectionsAreContiguous} {}
884+ explicit IsContiguousHelper (FoldingContext &c,
885+ bool namedConstantSectionsAreContiguous,
886+ bool firstDimensionStride1 = false )
887+ : Base{*this }, context_{c},
888+ namedConstantSectionsAreContiguous_{namedConstantSectionsAreContiguous},
889+ firstDimensionStride1_{firstDimensionStride1} {}
888890 using Base::operator ();
889891
890892 template <typename T> Result operator ()(const Constant<T> &) const {
@@ -956,13 +958,14 @@ class IsContiguousHelper
956958 if (!*baseIsContiguous) {
957959 return false ;
958960 }
959- // TODO could be true if base contiguous and this is only component, or
960- // if base has only one element?
961+ // TODO: should be true if base is contiguous and this is only
962+ // component, or when the base has at most one element
961963 }
962964 return std::nullopt ;
963965 }
964966 }
965967 Result operator ()(const ComplexPart &x) const {
968+ // TODO: should be true when base is empty array, too
966969 return x.complex ().Rank () == 0 ;
967970 }
968971 Result operator ()(const Substring &x) const {
@@ -1061,6 +1064,9 @@ class IsContiguousHelper
10611064 auto dims{subscript.size ()};
10621065 std::vector<bool > knownPartialSlice (dims, false );
10631066 for (auto j{dims}; j-- > 0 ;) {
1067+ if (j == 0 && firstDimensionStride1_ && !result.value_or (true )) {
1068+ result.reset (); // ignore problems on later dimensions
1069+ }
10641070 std::optional<ConstantSubscript> dimLbound;
10651071 std::optional<ConstantSubscript> dimUbound;
10661072 std::optional<ConstantSubscript> dimExtent;
@@ -1083,18 +1089,20 @@ class IsContiguousHelper
10831089 dimExtent = 0 ;
10841090 }
10851091 }
1086-
10871092 if (const auto *triplet{std::get_if<Triplet>(&subscript[j].u )}) {
10881093 ++rank;
1094+ const Expr<SubscriptInteger> *lowerBound{triplet->GetLower ()};
1095+ const Expr<SubscriptInteger> *upperBound{triplet->GetUpper ()};
1096+ std::optional<ConstantSubscript> lowerVal{lowerBound
1097+ ? ToInt64 (Fold (context_, Expr<SubscriptInteger>{*lowerBound}))
1098+ : dimLbound};
1099+ std::optional<ConstantSubscript> upperVal{upperBound
1100+ ? ToInt64 (Fold (context_, Expr<SubscriptInteger>{*upperBound}))
1101+ : dimUbound};
10891102 if (auto stride{ToInt64 (triplet->stride ())}) {
1090- const Expr<SubscriptInteger> *lowerBound{triplet->GetLower ()};
1091- const Expr<SubscriptInteger> *upperBound{triplet->GetUpper ()};
1092- std::optional<ConstantSubscript> lowerVal{lowerBound
1093- ? ToInt64 (Fold (context_, Expr<SubscriptInteger>{*lowerBound}))
1094- : dimLbound};
1095- std::optional<ConstantSubscript> upperVal{upperBound
1096- ? ToInt64 (Fold (context_, Expr<SubscriptInteger>{*upperBound}))
1097- : dimUbound};
1103+ if (j == 0 && *stride == 1 && firstDimensionStride1_) {
1104+ result = *stride == 1 ; // contiguous or empty if so
1105+ }
10981106 if (lowerVal && upperVal) {
10991107 if (*lowerVal < *upperVal) {
11001108 if (*stride < 0 ) {
@@ -1110,23 +1118,31 @@ class IsContiguousHelper
11101118 *lowerVal + *stride >= *upperVal) {
11111119 result = false ; // discontiguous if not empty
11121120 }
1113- } else {
1114- mayBeEmpty = true ;
1121+ } else { // bounds known and equal
1122+ if (j == 0 && firstDimensionStride1_) {
1123+ result = true ; // stride doesn't matter
1124+ }
1125+ }
1126+ } else { // bounds not both known
1127+ mayBeEmpty = true ;
1128+ }
1129+ } else { // stride not known
1130+ if (lowerVal && upperVal && *lowerVal == *upperVal) {
1131+ // stride doesn't matter when bounds are equal
1132+ if (j == 0 && firstDimensionStride1_) {
1133+ result = true ;
11151134 }
11161135 } else {
11171136 mayBeEmpty = true ;
11181137 }
1119- } else {
1120- mayBeEmpty = true ;
11211138 }
1122- } else if (subscript[j].Rank () > 0 ) {
1139+ } else if (subscript[j].Rank () > 0 ) { // vector subscript
11231140 ++rank;
11241141 if (!result) {
1125- result = false ; // vector subscript
1142+ result = false ;
11261143 }
11271144 mayBeEmpty = true ;
1128- } else {
1129- // Scalar subscript.
1145+ } else { // scalar subscript
11301146 if (dimExtent && *dimExtent > 1 ) {
11311147 knownPartialSlice[j] = true ;
11321148 }
@@ -1138,7 +1154,7 @@ class IsContiguousHelper
11381154 if (result) {
11391155 return result;
11401156 }
1141- // Not provably discontiguous at this point.
1157+ // Not provably contiguous or discontiguous at this point.
11421158 // Return "true" if simply contiguous, otherwise nullopt.
11431159 for (auto j{subscript.size ()}; j-- > 0 ;) {
11441160 if (const auto *triplet{std::get_if<Triplet>(&subscript[j].u )}) {
@@ -1170,33 +1186,36 @@ class IsContiguousHelper
11701186
11711187 FoldingContext &context_;
11721188 bool namedConstantSectionsAreContiguous_{false };
1189+ bool firstDimensionStride1_{false };
11731190};
11741191
11751192template <typename A>
11761193std::optional<bool > IsContiguous (const A &x, FoldingContext &context,
1177- bool namedConstantSectionsAreContiguous) {
1194+ bool namedConstantSectionsAreContiguous, bool firstDimensionStride1 ) {
11781195 if (!IsVariable (x) &&
11791196 (namedConstantSectionsAreContiguous || !ExtractDataRef (x, true , true ))) {
11801197 return true ;
11811198 } else {
1182- return IsContiguousHelper{context, namedConstantSectionsAreContiguous}(x);
1199+ return IsContiguousHelper{
1200+ context, namedConstantSectionsAreContiguous, firstDimensionStride1}(x);
11831201 }
11841202}
11851203
11861204template std::optional<bool > IsContiguous (const Expr<SomeType> &,
1187- FoldingContext &, bool namedConstantSectionsAreContiguous);
1205+ FoldingContext &, bool namedConstantSectionsAreContiguous,
1206+ bool firstDimensionStride1);
11881207template std::optional<bool > IsContiguous (const ArrayRef &, FoldingContext &,
1189- bool namedConstantSectionsAreContiguous);
1208+ bool namedConstantSectionsAreContiguous, bool firstDimensionStride1 );
11901209template std::optional<bool > IsContiguous (const Substring &, FoldingContext &,
1191- bool namedConstantSectionsAreContiguous);
1210+ bool namedConstantSectionsAreContiguous, bool firstDimensionStride1 );
11921211template std::optional<bool > IsContiguous (const Component &, FoldingContext &,
1193- bool namedConstantSectionsAreContiguous);
1212+ bool namedConstantSectionsAreContiguous, bool firstDimensionStride1 );
11941213template std::optional<bool > IsContiguous (const ComplexPart &, FoldingContext &,
1195- bool namedConstantSectionsAreContiguous);
1214+ bool namedConstantSectionsAreContiguous, bool firstDimensionStride1 );
11961215template std::optional<bool > IsContiguous (const CoarrayRef &, FoldingContext &,
1197- bool namedConstantSectionsAreContiguous);
1198- template std::optional<bool > IsContiguous (
1199- const Symbol &, FoldingContext &, bool namedConstantSectionsAreContiguous );
1216+ bool namedConstantSectionsAreContiguous, bool firstDimensionStride1 );
1217+ template std::optional<bool > IsContiguous (const Symbol &, FoldingContext &,
1218+ bool namedConstantSectionsAreContiguous, bool firstDimensionStride1 );
12001219
12011220// IsErrorExpr()
12021221struct IsErrorExprHelper : public AnyTraverse <IsErrorExprHelper, bool > {
0 commit comments