Parse affine map range sizes.

PiperOrigin-RevId: 204240947
diff --git a/lib/Parser/Parser.cpp b/lib/Parser/Parser.cpp
index 3eff98c..1d73d5b 100644
--- a/lib/Parser/Parser.cpp
+++ b/lib/Parser/Parser.cpp
@@ -628,6 +628,11 @@
   unsigned getNumDims() const { return dims.size(); }
   unsigned getNumSymbols() const { return symbols.size(); }
 
+  /// Returns true if the only identifiers the parser accepts in affine
+  /// expressions are symbolic identifiers.
+  bool isPureSymbolic() const { return pureSymbolic; }
+  void setSymbolicParsing(bool val) { pureSymbolic = val; }
+
   // Binary affine op parsing.
   AffineLowPrecOp consumeIfLowPrecOp();
   AffineHighPrecOp consumeIfHighPrecOp();
@@ -657,6 +662,9 @@
   // TODO(bondhugula): could just use an vector/ArrayRef and scan the numbers.
   llvm::StringMap<unsigned> dims;
   llvm::StringMap<unsigned> symbols;
+  /// True if the parser should allow only symbolic identifiers in affine
+  /// expressions.
+  bool pureSymbolic = false;
 };
 } // end anonymous namespace
 
@@ -664,6 +672,7 @@
 AffineExpr *AffineMapParser::getBinaryAffineOpExpr(AffineHighPrecOp op,
                                                    AffineExpr *lhs,
                                                    AffineExpr *rhs) {
+  // TODO: make the error location info accurate.
   switch (op) {
   case Mul:
     if (!lhs->isSymbolic() && !rhs->isSymbolic()) {
@@ -828,15 +837,21 @@
     return (emitError("expected bare identifier"), nullptr);
 
   StringRef sRef = getTokenSpelling();
+  // dims, symbols are all pairwise distinct.
   if (dims.count(sRef)) {
+    if (isPureSymbolic())
+      return (emitError("identifier used is not a symbolic identifier"),
+              nullptr);
     consumeToken(Token::bare_identifier);
     return builder.getDimExpr(dims.lookup(sRef));
   }
+
   if (symbols.count(sRef)) {
     consumeToken(Token::bare_identifier);
     return builder.getSymbolExpr(symbols.lookup(sRef));
   }
-  return (emitError("identifier is neither dimensional nor symbolic"), nullptr);
+
+  return (emitError("use of undeclared identifier"), nullptr);
 }
 
 /// Parse a positive integral constant appearing in an affine expression.
@@ -1053,8 +1068,36 @@
   if (parseCommaSeparatedList(Token::r_paren, parseElt, false))
     return nullptr;
 
+  // Parse optional range sizes.
+  //  (`size` `(` dim-size (`,` dim-size)* `)`)?
+  // TODO: check if sizes are non-negative whenever they are constant.
+  SmallVector<AffineExpr *, 4> rangeSizes;
+  if (consumeIf(Token::kw_size)) {
+    // Location of the l_paren token (if it exists) for error reporting later.
+    auto loc = getToken().getLoc();
+    if (!consumeIf(Token::l_paren))
+      return (emitError("expected '(' at start of affine map range"), nullptr);
+
+    auto parseRangeSize = [&]() -> ParseResult {
+      auto *elt = parseAffineExpr();
+      ParseResult res = elt ? ParseSuccess : ParseFailure;
+      rangeSizes.push_back(elt);
+      return res;
+    };
+
+    setSymbolicParsing(true);
+    if (parseCommaSeparatedList(Token::r_paren, parseRangeSize, false))
+      return nullptr;
+    if (exprs.size() > rangeSizes.size())
+      return (emitError(loc, "fewer range sizes than range expressions"),
+              nullptr);
+    if (exprs.size() < rangeSizes.size())
+      return (emitError(loc, "more range sizes than range expressions"),
+              nullptr);
+  }
+
   // Parsed a valid affine map.
-  return builder.getAffineMap(dims.size(), symbols.size(), exprs);
+  return builder.getAffineMap(dims.size(), symbols.size(), exprs, rangeSizes);
 }
 
 AffineMap *Parser::parseAffineMapInline() {