[Mlir-commits] [mlir] ab9cdf0 - [mlir:Parser] Don't use strings for the "ugly" form of Attribute/Type syntax

River Riddle llvmlistbot at llvm.org
Tue Jul 5 16:21:13 PDT 2022


Author: River Riddle
Date: 2022-07-05T16:20:30-07:00
New Revision: ab9cdf09f4f03259e7e75c5187139e6628a37815

URL: https://github.com/llvm/llvm-project/commit/ab9cdf09f4f03259e7e75c5187139e6628a37815
DIFF: https://github.com/llvm/llvm-project/commit/ab9cdf09f4f03259e7e75c5187139e6628a37815.diff

LOG: [mlir:Parser] Don't use strings for the "ugly" form of Attribute/Type syntax

This commit refactors the syntax of "ugly" attribute/type formats to not use
strings for wrapping. This means that moving forward attirbutes and type formats
will always need to be in some recognizable form, i.e. if they use incompatible
characters they will need to manually wrap those in a string, the framework will
no longer do it automatically.

This has the benefit of greatly simplifying how parsing attributes/types work, given
that we currently rely on some extremely complicated nested parser logic which is
quite problematic for a myriad of reasons; unecessary complexity(we create a nested
source manager/lexer/etc.), diagnostic locations can be off/wrong given string escaping,
etc.

Differential Revision: https://reviews.llvm.org/D118505

Added: 
    

Modified: 
    flang/lib/Optimizer/Dialect/FIRType.cpp
    mlir/docs/LangRef.md
    mlir/lib/IR/AsmPrinter.cpp
    mlir/lib/Parser/DialectSymbolParser.cpp
    mlir/lib/Parser/Parser.h
    mlir/lib/Parser/ParserState.h
    mlir/test/Dialect/EmitC/types.mlir
    mlir/test/Dialect/GPU/invalid.mlir
    mlir/test/Dialect/OpenACC/ops.mlir
    mlir/test/Dialect/OpenMP/ops.mlir
    mlir/test/Dialect/Quant/parse-any-invalid.mlir
    mlir/test/Dialect/Quant/parse-calibrated-invalid.mlir
    mlir/test/Dialect/Quant/parse-uniform-invalid.mlir
    mlir/test/IR/enum-attr-invalid.mlir
    mlir/test/IR/enum-attr-roundtrip.mlir
    mlir/test/IR/invalid.mlir
    mlir/test/IR/parser.mlir
    mlir/test/Target/Cpp/types.mlir
    mlir/test/mlir-tblgen/attr-or-type-format-roundtrip.mlir
    mlir/test/mlir-tblgen/attr-or-type-format.mlir
    mlir/test/mlir-tblgen/testdialect-attrdefs.mlir
    mlir/test/python/ir/attributes.py

Removed: 
    


################################################################################
diff  --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp
index 3293cad6177a2..0a8a2eb0385b7 100644
--- a/flang/lib/Optimizer/Dialect/FIRType.cpp
+++ b/flang/lib/Optimizer/Dialect/FIRType.cpp
@@ -749,14 +749,17 @@ mlir::Type fir::SequenceType::parse(mlir::AsmParser &parser) {
     return {};
   }
   mlir::Type eleTy;
-  if (parser.parseType(eleTy) || parser.parseGreater())
+  if (parser.parseType(eleTy))
     return {};
   mlir::AffineMapAttr map;
-  if (!parser.parseOptionalComma())
+  if (!parser.parseOptionalComma()) {
     if (parser.parseAttribute(map)) {
       parser.emitError(parser.getNameLoc(), "expecting affine map");
       return {};
     }
+  }
+  if (parser.parseGreater())
+    return {};
   return SequenceType::get(parser.getContext(), shape, eleTy, map);
 }
 

diff  --git a/mlir/docs/LangRef.md b/mlir/docs/LangRef.md
index d264b30e79119..aacc6170dce1b 100644
--- a/mlir/docs/LangRef.md
+++ b/mlir/docs/LangRef.md
@@ -685,55 +685,46 @@ system.
 ```
 dialect-namespace ::= bare-id
 
-opaque-dialect-item ::= dialect-namespace '<' string-literal '>'
+dialect-type ::= '!' (opaque-dialect-type | pretty-dialect-type)
+opaque-dialect-type ::= dialect-namespace dialect-type-body
+pretty-dialect-type ::= dialect-namespace '.' pretty-dialect-type-lead-ident
+                                              dialect-type-body?
+pretty-dialect-type-lead-ident ::= '[A-Za-z][A-Za-z0-9._]*'
 
-pretty-dialect-item ::= dialect-namespace '.' pretty-dialect-item-lead-ident
-                                              pretty-dialect-item-body?
-
-pretty-dialect-item-lead-ident ::= '[A-Za-z][A-Za-z0-9._]*'
-pretty-dialect-item-body ::= '<' pretty-dialect-item-contents+ '>'
-pretty-dialect-item-contents ::= pretty-dialect-item-body
-                              | '(' pretty-dialect-item-contents+ ')'
-                              | '[' pretty-dialect-item-contents+ ']'
-                              | '{' pretty-dialect-item-contents+ '}'
-                              | '[^\[<({\]>)}\0]+'
-
-dialect-type ::= '!' (opaque-dialect-item | pretty-dialect-item)
+dialect-type-body ::= '<' dialect-type-contents+ '>'
+dialect-type-contents ::= dialect-type-body
+                            | '(' dialect-type-contents+ ')'
+                            | '[' dialect-type-contents+ ']'
+                            | '{' dialect-type-contents+ '}'
+                            | '[^\[<({\]>)}\0]+'
 ```
 
-Dialect types can be specified in a verbose form, e.g. like this:
+Dialect types are generally specified in an opaque form, where the contents
+of the type are defined within a body wrapped with the dialect namespace
+and `<>`. Consider the following examples:
 
 ```mlir
-// LLVM type that wraps around llvm IR types.
-!llvm<"i32*">
+// A tensorflow string type.
+!tf<string>
 
-// Tensor flow string type.
-!tf.string
+// A type with complex components.
+!foo<something<abcd>>
 
-// Complex type
-!foo<"something<abcd>">
-
-// Even more complex type
-!foo<"something<a%%123^^^>>>">
+// An even more complex type.
+!foo<"a123^^^" + bar>
 ```
 
-Dialect types that are simple enough can use the pretty format, which is a
-lighter weight syntax that is equivalent to the above forms:
+Dialect types that are simple enough may use a prettier format, which unwraps
+part of the syntax into an equivalent, but lighter weight form:
 
 ```mlir
-// Tensor flow string type.
+// A tensorflow string type.
 !tf.string
 
-// Complex type
+// A type with complex components.
 !foo.something<abcd>
 ```
 
-Sufficiently complex dialect types are required to use the verbose form for
-generality. For example, the more complex type shown above wouldn't be valid in
-the lighter syntax: `!foo.something<a%%123^^^>>>` because it contains characters
-that are not allowed in the lighter syntax, as well as unbalanced `<>`
-characters.
-
 See [here](AttributesAndTypes.md) to learn how to define dialect types.
 
 ### Builtin Types
@@ -807,40 +798,45 @@ Example:
 
 ### Dialect Attribute Values
 
-Similarly to operations, dialects may define custom attribute values. The
-syntactic structure of these values is identical to custom dialect type values,
-except that dialect attribute values are distinguished with a leading '#', while
-dialect types are distinguished with a leading '!'.
+Similarly to operations, dialects may define custom attribute values.
 
 ```
-dialect-attribute-value ::= '#' opaque-dialect-item
-dialect-attribute-value ::= '#' pretty-dialect-item
+dialect-namespace ::= bare-id
+
+dialect-attribute ::= '#' (opaque-dialect-attribute | pretty-dialect-attribute)
+opaque-dialect-attribute ::= dialect-namespace dialect-attribute-body
+pretty-dialect-attribute ::= dialect-namespace '.' pretty-dialect-attribute-lead-ident
+                                              dialect-attribute-body?
+pretty-dialect-attribute-lead-ident ::= '[A-Za-z][A-Za-z0-9._]*'
+
+dialect-attribute-body ::= '<' dialect-attribute-contents+ '>'
+dialect-attribute-contents ::= dialect-attribute-body
+                            | '(' dialect-attribute-contents+ ')'
+                            | '[' dialect-attribute-contents+ ']'
+                            | '{' dialect-attribute-contents+ '}'
+                            | '[^\[<({\]>)}\0]+'
 ```
 
-Dialect attribute values can be specified in a verbose form, e.g. like this:
+Dialect attributes are generally specified in an opaque form, where the contents
+of the attribute are defined within a body wrapped with the dialect namespace
+and `<>`. Consider the following examples:
 
 ```mlir
-// Complex attribute value.
-#foo<"something<abcd>">
+// A string attribute.
+#foo<string<"">>
 
-// Even more complex attribute value.
-#foo<"something<a%%123^^^>>>">
+// A complex attribute.
+#foo<"a123^^^" + bar>
 ```
 
-Dialect attribute values that are simple enough can use the pretty format, which
-is a lighter weight syntax that is equivalent to the above forms:
+Dialect attributes that are simple enough may use a prettier format, which unwraps
+part of the syntax into an equivalent, but lighter weight form:
 
 ```mlir
-// Complex attribute
-#foo.something<abcd>
+// A string attribute.
+#foo.string<"">
 ```
 
-Sufficiently complex dialect attribute values are required to use the verbose
-form for generality. For example, the more complex type shown above would not be
-valid in the lighter syntax: `#foo.something<a%%123^^^>>>` because it contains
-characters that are not allowed in the lighter syntax, as well as unbalanced
-`<>` characters.
-
 See [here](AttributesAndTypes.md) on how to define dialect attribute values.
 
 ### Builtin Attribute Values

diff  --git a/mlir/lib/IR/AsmPrinter.cpp b/mlir/lib/IR/AsmPrinter.cpp
index 745393d25af42..c3bc7ab1a2c1b 100644
--- a/mlir/lib/IR/AsmPrinter.cpp
+++ b/mlir/lib/IR/AsmPrinter.cpp
@@ -1650,7 +1650,8 @@ void AsmPrinter::Impl::printLocation(LocationAttr loc, bool allowAlias) {
 }
 
 /// Returns true if the given dialect symbol data is simple enough to print in
-/// the pretty form, i.e. without the enclosing "".
+/// the pretty form. This is essentially when the symbol takes the form:
+///   identifier (`<` body `>`)?
 static bool isDialectSymbolSimpleEnoughForPrettyForm(StringRef symName) {
   // The name must start with an identifier.
   if (symName.empty() || !isalpha(symName.front()))
@@ -1663,64 +1664,9 @@ static bool isDialectSymbolSimpleEnoughForPrettyForm(StringRef symName) {
   if (symName.empty())
     return true;
 
-  // If we got to an unexpected character, then it must be a <>.  Check those
-  // recursively.
-  if (symName.front() != '<' || symName.back() != '>')
-    return false;
-
-  SmallVector<char, 8> nestedPunctuation;
-  do {
-    // If we ran out of characters, then we had a punctuation mismatch.
-    if (symName.empty())
-      return false;
-
-    auto c = symName.front();
-    symName = symName.drop_front();
-
-    switch (c) {
-    // We never allow null characters. This is an EOF indicator for the lexer
-    // which we could handle, but isn't important for any known dialect.
-    case '\0':
-      return false;
-    case '<':
-    case '[':
-    case '(':
-    case '{':
-      nestedPunctuation.push_back(c);
-      continue;
-    case '-':
-      // Treat `->` as a special token.
-      if (!symName.empty() && symName.front() == '>') {
-        symName = symName.drop_front();
-        continue;
-      }
-      break;
-    // Reject types with mismatched brackets.
-    case '>':
-      if (nestedPunctuation.pop_back_val() != '<')
-        return false;
-      break;
-    case ']':
-      if (nestedPunctuation.pop_back_val() != '[')
-        return false;
-      break;
-    case ')':
-      if (nestedPunctuation.pop_back_val() != '(')
-        return false;
-      break;
-    case '}':
-      if (nestedPunctuation.pop_back_val() != '{')
-        return false;
-      break;
-    default:
-      continue;
-    }
-
-    // We're done when the punctuation is fully matched.
-  } while (!nestedPunctuation.empty());
-
-  // If there were extra characters, then we failed.
-  return symName.empty();
+  // If we got to an unexpected character, then it must be a <>. Check that the
+  // rest of the symbol is wrapped within <>.
+  return symName.front() == '<' && symName.back() == '>';
 }
 
 /// Print the given dialect symbol to the stream.
@@ -1735,9 +1681,7 @@ static void printDialectSymbol(raw_ostream &os, StringRef symPrefix,
     return;
   }
 
-  os << "<\"";
-  llvm::printEscapedString(symString, os);
-  os << "\">";
+  os << '<' << symString << '>';
 }
 
 /// Returns true if the given string can be represented as a bare identifier.

diff  --git a/mlir/lib/Parser/DialectSymbolParser.cpp b/mlir/lib/Parser/DialectSymbolParser.cpp
index 11484410257f3..623ea8ef12ea1 100644
--- a/mlir/lib/Parser/DialectSymbolParser.cpp
+++ b/mlir/lib/Parser/DialectSymbolParser.cpp
@@ -43,9 +43,9 @@ class CustomDialectAsmParser : public AsmParserImpl<DialectAsmParser> {
 };
 } // namespace
 
-/// Parse the body of a pretty dialect symbol, which starts and ends with <>'s,
-/// and may be recursive.  Return with the 'prettyName' StringRef encompassing
-/// the entire pretty name.
+/// Parse the body of a dialect symbol, which starts and ends with <>'s, and may
+/// be recursive. Return with the 'body' StringRef encompassing the entire
+/// body.
 ///
 ///   pretty-dialect-sym-body ::= '<' pretty-dialect-sym-contents+ '>'
 ///   pretty-dialect-sym-contents ::= pretty-dialect-sym-body
@@ -54,24 +54,26 @@ class CustomDialectAsmParser : public AsmParserImpl<DialectAsmParser> {
 ///                                  | '{' pretty-dialect-sym-contents+ '}'
 ///                                  | '[^[<({>\])}\0]+'
 ///
-ParseResult Parser::parsePrettyDialectSymbolName(StringRef &prettyName) {
-  // Pretty symbol names are a relatively unstructured format that contains a
-  // series of properly nested punctuation, with anything else in the middle.
-  // Scan ahead to find it and consume it if successful, otherwise emit an
-  // error.
-  auto *curPtr = getTokenSpelling().data();
-
-  SmallVector<char, 8> nestedPunctuation;
+ParseResult Parser::parseDialectSymbolBody(StringRef &body) {
+  // Symbol bodies are a relatively unstructured format that contains a series
+  // of properly nested punctuation, with anything else in the middle. Scan
+  // ahead to find it and consume it if successful, otherwise emit an error.
+  const char *curPtr = getTokenSpelling().data();
 
   // Scan over the nested punctuation, bailing out on error and consuming until
-  // we find the end.  We know that we're currently looking at the '<', so we
-  // can go until we find the matching '>' character.
+  // we find the end. We know that we're currently looking at the '<', so we can
+  // go until we find the matching '>' character.
   assert(*curPtr == '<');
+  SmallVector<char, 8> nestedPunctuation;
   do {
     char c = *curPtr++;
     switch (c) {
     case '\0':
       // This also handles the EOF case.
+      if (!nestedPunctuation.empty()) {
+        return emitError() << "unbalanced '" << nestedPunctuation.back()
+                           << "' character in pretty dialect name";
+      }
       return emitError("unexpected nul or EOF in pretty dialect name");
     case '<':
     case '[':
@@ -102,6 +104,14 @@ ParseResult Parser::parsePrettyDialectSymbolName(StringRef &prettyName) {
       if (nestedPunctuation.pop_back_val() != '{')
         return emitError("unbalanced '}' character in pretty dialect name");
       break;
+    case '"': {
+      // Dispatch to the lexer to lex past strings.
+      resetToken(curPtr - 1);
+      if (state.curToken.isNot(Token::string))
+        return failure();
+      curPtr = state.curToken.getEndLoc().getPointer();
+      break;
+    }
 
     default:
       continue;
@@ -110,11 +120,10 @@ ParseResult Parser::parsePrettyDialectSymbolName(StringRef &prettyName) {
 
   // Ok, we succeeded, remember where we stopped, reset the lexer to know it is
   // consuming all this stuff, and return.
-  state.lex.resetPointer(curPtr);
+  resetToken(curPtr);
 
-  unsigned length = curPtr - prettyName.begin();
-  prettyName = StringRef(prettyName.begin(), length);
-  consumeToken();
+  unsigned length = curPtr - body.begin();
+  body = StringRef(body.data(), length);
   return success();
 }
 
@@ -125,12 +134,24 @@ static Symbol parseExtendedSymbol(Parser &p, Token::Kind identifierTok,
                                   CreateFn &&createSymbol) {
   // Parse the dialect namespace.
   StringRef identifier = p.getTokenSpelling().drop_front();
-  auto loc = p.getToken().getLoc();
+  SMLoc loc = p.getToken().getLoc();
   p.consumeToken(identifierTok);
 
+  // Check to see if this is a pretty name.
+  StringRef dialectName;
+  StringRef symbolData;
+  std::tie(dialectName, symbolData) = identifier.split('.');
+  bool isPrettyName = !symbolData.empty();
+
+  // Check to see if the symbol has trailing data, i.e. has an immediately
+  // following '<'.
+  bool hasTrailingData =
+      p.getToken().is(Token::less) &&
+      identifier.bytes_end() == p.getTokenSpelling().bytes_begin();
+
   // If there is no '<' token following this, and if the typename contains no
   // dot, then we are parsing a symbol alias.
-  if (p.getToken().isNot(Token::less) && !identifier.contains('.')) {
+  if (!hasTrailingData && !isPrettyName) {
     // Check for an alias for this type.
     auto aliasIt = aliases.find(identifier);
     if (aliasIt == aliases.end())
@@ -140,94 +161,25 @@ static Symbol parseExtendedSymbol(Parser &p, Token::Kind identifierTok,
     return aliasIt->second;
   }
 
-  // Otherwise, we are parsing a dialect-specific symbol.  If the name contains
-  // a dot, then this is the "pretty" form.  If not, it is the verbose form that
-  // looks like <"...">.
-  std::string symbolData;
-  auto dialectName = identifier;
-
-  // Handle the verbose form, where "identifier" is a simple dialect name.
-  if (!identifier.contains('.')) {
-    // Consume the '<'.
-    if (p.parseToken(Token::less, "expected '<' in dialect type"))
-      return nullptr;
-
-    // Parse the symbol specific data.
-    if (p.getToken().isNot(Token::string))
-      return (p.emitWrongTokenError(
-                  "expected string literal data in dialect symbol"),
-              nullptr);
-    symbolData = p.getToken().getStringValue();
-    loc = SMLoc::getFromPointer(p.getToken().getLoc().getPointer() + 1);
-    p.consumeToken(Token::string);
-
-    // Consume the '>'.
-    if (p.parseToken(Token::greater, "expected '>' in dialect symbol"))
+  // If this isn't an alias, we are parsing a dialect-specific symbol. If the
+  // name contains a dot, then this is the "pretty" form. If not, it is the
+  // verbose form that looks like <...>.
+  if (!isPrettyName) {
+    // Point the symbol data to the end of the dialect name to start.
+    symbolData = StringRef(dialectName.end(), 0);
+    if (p.parseDialectSymbolBody(symbolData))
       return nullptr;
+    symbolData = symbolData.drop_front().drop_back();
   } else {
-    // Ok, the dialect name is the part of the identifier before the dot, the
-    // part after the dot is the dialect's symbol, or the start thereof.
-    auto dotHalves = identifier.split('.');
-    dialectName = dotHalves.first;
-    auto prettyName = dotHalves.second;
-    loc = SMLoc::getFromPointer(prettyName.data());
+    loc = SMLoc::getFromPointer(symbolData.data());
 
     // If the dialect's symbol is followed immediately by a <, then lex the body
     // of it into prettyName.
-    if (p.getToken().is(Token::less) &&
-        prettyName.bytes_end() == p.getTokenSpelling().bytes_begin()) {
-      if (p.parsePrettyDialectSymbolName(prettyName))
-        return nullptr;
-    }
-
-    symbolData = prettyName.str();
+    if (hasTrailingData && p.parseDialectSymbolBody(symbolData))
+      return nullptr;
   }
 
-  // Record the name location of the type remapped to the top level buffer.
-  SMLoc locInTopLevelBuffer = p.remapLocationToTopLevelBuffer(loc);
-  p.getState().symbols.nestedParserLocs.push_back(locInTopLevelBuffer);
-
-  // Call into the provided symbol construction function.
-  Symbol sym = createSymbol(dialectName, symbolData, loc);
-
-  // Pop the last parser location.
-  p.getState().symbols.nestedParserLocs.pop_back();
-  return sym;
-}
-
-/// Parses a symbol, of type 'T', and returns it if parsing was successful. If
-/// parsing failed, nullptr is returned. The number of bytes read from the input
-/// string is returned in 'numRead'.
-template <typename T, typename ParserFn>
-static T parseSymbol(StringRef inputStr, MLIRContext *context,
-                     SymbolState &symbolState, ParserFn &&parserFn,
-                     size_t *numRead = nullptr) {
-  SourceMgr sourceMgr;
-  auto memBuffer = MemoryBuffer::getMemBuffer(
-      inputStr, /*BufferName=*/"<mlir_parser_buffer>",
-      /*RequiresNullTerminator=*/false);
-  sourceMgr.AddNewSourceBuffer(std::move(memBuffer), SMLoc());
-  ParserConfig config(context);
-  ParserState state(sourceMgr, config, symbolState, /*asmState=*/nullptr);
-  Parser parser(state);
-
-  Token startTok = parser.getToken();
-  T symbol = parserFn(parser);
-  if (!symbol)
-    return T();
-
-  // If 'numRead' is valid, then provide the number of bytes that were read.
-  Token endTok = parser.getToken();
-  if (numRead) {
-    *numRead = static_cast<size_t>(endTok.getLoc().getPointer() -
-                                   startTok.getLoc().getPointer());
-
-    // Otherwise, ensure that all of the tokens were parsed.
-  } else if (startTok.getLoc() != endTok.getLoc() && endTok.isNot(Token::eof)) {
-    parser.emitError(endTok.getLoc(), "encountered unexpected token");
-    return T();
-  }
-  return symbol;
+  return createSymbol(dialectName, symbolData, loc);
 }
 
 /// Parse an extended attribute.
@@ -241,8 +193,7 @@ Attribute Parser::parseExtendedAttr(Type type) {
   MLIRContext *ctx = getContext();
   Attribute attr = parseExtendedSymbol<Attribute>(
       *this, Token::hash_identifier, state.symbols.attributeAliasDefinitions,
-      [&](StringRef dialectName, StringRef symbolData,
-          SMLoc loc) -> Attribute {
+      [&](StringRef dialectName, StringRef symbolData, SMLoc loc) -> Attribute {
         // Parse an optional trailing colon type.
         Type attrType = type;
         if (consumeIf(Token::colon) && !(attrType = parseType()))
@@ -251,11 +202,15 @@ Attribute Parser::parseExtendedAttr(Type type) {
         // If we found a registered dialect, then ask it to parse the attribute.
         if (Dialect *dialect =
                 builder.getContext()->getOrLoadDialect(dialectName)) {
-          return parseSymbol<Attribute>(
-              symbolData, ctx, state.symbols, [&](Parser &parser) {
-                CustomDialectAsmParser customParser(symbolData, parser);
-                return dialect->parseAttribute(customParser, attrType);
-              });
+          // Temporarily reset the lexer to let the dialect parse the attribute.
+          const char *curLexerPos = getToken().getLoc().getPointer();
+          resetToken(symbolData.data());
+
+          // Parse the attribute.
+          CustomDialectAsmParser customParser(symbolData, *this);
+          Attribute attr = dialect->parseAttribute(customParser, attrType);
+          resetToken(curLexerPos);
+          return attr;
         }
 
         // Otherwise, form a new opaque attribute.
@@ -287,11 +242,15 @@ Type Parser::parseExtendedType() {
       [&](StringRef dialectName, StringRef symbolData, SMLoc loc) -> Type {
         // If we found a registered dialect, then ask it to parse the type.
         if (auto *dialect = ctx->getOrLoadDialect(dialectName)) {
-          return parseSymbol<Type>(
-              symbolData, ctx, state.symbols, [&](Parser &parser) {
-                CustomDialectAsmParser customParser(symbolData, parser);
-                return dialect->parseType(customParser);
-              });
+          // Temporarily reset the lexer to let the dialect parse the type.
+          const char *curLexerPos = getToken().getLoc().getPointer();
+          resetToken(symbolData.data());
+
+          // Parse the type.
+          CustomDialectAsmParser customParser(symbolData, *this);
+          Type type = dialect->parseType(customParser);
+          resetToken(curLexerPos);
+          return type;
         }
 
         // Otherwise, form a new opaque type.
@@ -311,16 +270,29 @@ Type Parser::parseExtendedType() {
 template <typename T, typename ParserFn>
 static T parseSymbol(StringRef inputStr, MLIRContext *context, size_t &numRead,
                      ParserFn &&parserFn) {
+  SourceMgr sourceMgr;
+  auto memBuffer = MemoryBuffer::getMemBuffer(
+      inputStr, /*BufferName=*/"<mlir_parser_buffer>",
+      /*RequiresNullTerminator=*/false);
+  sourceMgr.AddNewSourceBuffer(std::move(memBuffer), SMLoc());
   SymbolState aliasState;
-  return parseSymbol<T>(
-      inputStr, context, aliasState,
-      [&](Parser &parser) {
-        SourceMgrDiagnosticHandler handler(
-            const_cast<llvm::SourceMgr &>(parser.getSourceMgr()),
-            parser.getContext());
-        return parserFn(parser);
-      },
-      &numRead);
+  ParserConfig config(context);
+  ParserState state(sourceMgr, config, aliasState, /*asmState=*/nullptr);
+  Parser parser(state);
+
+  SourceMgrDiagnosticHandler handler(
+      const_cast<llvm::SourceMgr &>(parser.getSourceMgr()),
+      parser.getContext());
+  Token startTok = parser.getToken();
+  T symbol = parserFn(parser);
+  if (!symbol)
+    return T();
+
+  // Provide the number of bytes that were read.
+  Token endTok = parser.getToken();
+  numRead = static_cast<size_t>(endTok.getLoc().getPointer() -
+                                startTok.getLoc().getPointer());
+  return symbol;
 }
 
 Attribute mlir::parseAttribute(StringRef attrStr, MLIRContext *context) {

diff  --git a/mlir/lib/Parser/Parser.h b/mlir/lib/Parser/Parser.h
index 521c0390edaf3..e762fc6d3543b 100644
--- a/mlir/lib/Parser/Parser.h
+++ b/mlir/lib/Parser/Parser.h
@@ -57,7 +57,7 @@ class Parser {
     return parseCommaSeparatedList(Delimiter::None, parseElementFn);
   }
 
-  ParseResult parsePrettyDialectSymbolName(StringRef &prettyName);
+  ParseResult parseDialectSymbolBody(StringRef &body);
 
   // We have two forms of parsing methods - those that return a non-null
   // pointer on success, and those that return a ParseResult to indicate whether
@@ -81,32 +81,7 @@ class Parser {
   /// Encode the specified source location information into an attribute for
   /// attachment to the IR.
   Location getEncodedSourceLocation(SMLoc loc) {
-    // If there are no active nested parsers, we can get the encoded source
-    // location directly.
-    if (state.parserDepth == 0)
-      return state.lex.getEncodedSourceLocation(loc);
-    // Otherwise, we need to re-encode it to point to the top level buffer.
-    return state.symbols.topLevelLexer->getEncodedSourceLocation(
-        remapLocationToTopLevelBuffer(loc));
-  }
-
-  /// Remaps the given SMLoc to the top level lexer of the parser. This is used
-  /// to adjust locations of potentially nested parsers to ensure that they can
-  /// be emitted properly as diagnostics.
-  SMLoc remapLocationToTopLevelBuffer(SMLoc loc) {
-    // If there are no active nested parsers, we can return location directly.
-    SymbolState &symbols = state.symbols;
-    if (state.parserDepth == 0)
-      return loc;
-    assert(symbols.topLevelLexer && "expected valid top-level lexer");
-
-    // Otherwise, we need to remap the location to the main parser. This is
-    // simply offseting the location onto the location of the last nested
-    // parser.
-    size_t offset = loc.getPointer() - state.lex.getBufferBegin();
-    auto *rawLoc =
-        symbols.nestedParserLocs[state.parserDepth - 1].getPointer() + offset;
-    return SMLoc::getFromPointer(rawLoc);
+    return state.lex.getEncodedSourceLocation(loc);
   }
 
   //===--------------------------------------------------------------------===//
@@ -141,6 +116,12 @@ class Parser {
     consumeToken();
   }
 
+  /// Reset the parser to the given lexer position.
+  void resetToken(const char *tokPos) {
+    state.lex.resetPointer(tokPos);
+    state.curToken = state.lex.lexToken();
+  }
+
   /// Consume the specified token if present and return success.  On failure,
   /// output a diagnostic and return failure.
   ParseResult parseToken(Token::Kind expectedToken, const Twine &message);

diff  --git a/mlir/lib/Parser/ParserState.h b/mlir/lib/Parser/ParserState.h
index 7e70f5534197f..4d3ff2774f8e4 100644
--- a/mlir/lib/Parser/ParserState.h
+++ b/mlir/lib/Parser/ParserState.h
@@ -33,17 +33,6 @@ struct SymbolState {
   DenseMap<const OpAsmDialectInterface *,
            llvm::StringMap<std::pair<std::string, AsmDialectResourceHandle>>>
       dialectResources;
-
-  /// A set of locations into the main parser memory buffer for each of the
-  /// active nested parsers. Given that some nested parsers, i.e. custom dialect
-  /// parsers, operate on a temporary memory buffer, this provides an anchor
-  /// point for emitting diagnostics.
-  SmallVector<SMLoc, 1> nestedParserLocs;
-
-  /// The top-level lexer that contains the original memory buffer provided by
-  /// the user. This is used by nested parsers to get a properly encoded source
-  /// location.
-  Lexer *topLevelLexer = nullptr;
 };
 
 //===----------------------------------------------------------------------===//
@@ -56,17 +45,7 @@ struct ParserState {
   ParserState(const llvm::SourceMgr &sourceMgr, const ParserConfig &config,
               SymbolState &symbols, AsmParserState *asmState)
       : config(config), lex(sourceMgr, config.getContext()),
-        curToken(lex.lexToken()), symbols(symbols),
-        parserDepth(symbols.nestedParserLocs.size()), asmState(asmState) {
-    // Set the top level lexer for the symbol state if one doesn't exist.
-    if (!symbols.topLevelLexer)
-      symbols.topLevelLexer = &lex;
-  }
-  ~ParserState() {
-    // Reset the top level lexer if it refers the lexer in our state.
-    if (symbols.topLevelLexer == &lex)
-      symbols.topLevelLexer = nullptr;
-  }
+        curToken(lex.lexToken()), symbols(symbols), asmState(asmState) {}
   ParserState(const ParserState &) = delete;
   void operator=(const ParserState &) = delete;
 
@@ -82,9 +61,6 @@ struct ParserState {
   /// The current state for symbol parsing.
   SymbolState &symbols;
 
-  /// The depth of this parser in the nested parsing stack.
-  size_t parserDepth;
-
   /// An optional pointer to a struct containing high level parser state to be
   /// populated during parsing.
   AsmParserState *asmState;

diff  --git a/mlir/test/Dialect/EmitC/types.mlir b/mlir/test/Dialect/EmitC/types.mlir
index 76f315b1bf296..3d68629a96e17 100644
--- a/mlir/test/Dialect/EmitC/types.mlir
+++ b/mlir/test/Dialect/EmitC/types.mlir
@@ -5,13 +5,13 @@
 // CHECK-LABEL: func @opaque_types() {
 func.func @opaque_types() {
   // CHECK-NEXT: !emitc.opaque<"int">
-  emitc.call "f"() {template_args = [!emitc<"opaque<\"int\">">]} : () -> ()
+  emitc.call "f"() {template_args = [!emitc<opaque<"int">>]} : () -> ()
   // CHECK-NEXT: !emitc.opaque<"byte">
-  emitc.call "f"() {template_args = [!emitc<"opaque<\"byte\">">]} : () -> ()
+  emitc.call "f"() {template_args = [!emitc<opaque<"byte">>]} : () -> ()
   // CHECK-NEXT: !emitc.opaque<"unsigned">
-  emitc.call "f"() {template_args = [!emitc<"opaque<\"unsigned\">">]} : () -> ()
+  emitc.call "f"() {template_args = [!emitc<opaque<"unsigned">>]} : () -> ()
   // CHECK-NEXT: !emitc.opaque<"status_t">
-  emitc.call "f"() {template_args = [!emitc<"opaque<\"status_t\">">]} : () -> ()
+  emitc.call "f"() {template_args = [!emitc<opaque<"status_t">>]} : () -> ()
   // CHECK-NEXT: !emitc.opaque<"std::vector<std::string>">
   emitc.call "f"() {template_args = [!emitc.opaque<"std::vector<std::string>">]} : () -> ()
   // CHECK-NEXT: !emitc.opaque<"SmallVector<int*, 4>">
@@ -23,11 +23,11 @@ func.func @opaque_types() {
 // CHECK-LABEL: func @pointer_types() {
 func.func @pointer_types() {
   // CHECK-NEXT: !emitc.ptr<i32>
-  emitc.call "f"() {template_args = [!emitc<"ptr<i32>">]} : () -> ()
+  emitc.call "f"() {template_args = [!emitc.ptr<i32>]} : () -> ()
   // CHECK-NEXT: !emitc.ptr<i64>
   emitc.call "f"() {template_args = [!emitc.ptr<i64>]} : () -> ()
   // CHECK-NEXT: !emitc.ptr<f32>
-  emitc.call "f"() {template_args = [!emitc<"ptr<f32>">]} : () -> ()
+  emitc.call "f"() {template_args = [!emitc.ptr<f32>]} : () -> ()
   // CHECK-NEXT: !emitc.ptr<f64>
   emitc.call "f"() {template_args = [!emitc.ptr<f64>]} : () -> ()
   // CHECK-NEXT: !emitc.ptr<i32>

diff  --git a/mlir/test/Dialect/GPU/invalid.mlir b/mlir/test/Dialect/GPU/invalid.mlir
index 1e10349f63864..9a8f8849b696c 100644
--- a/mlir/test/Dialect/GPU/invalid.mlir
+++ b/mlir/test/Dialect/GPU/invalid.mlir
@@ -223,7 +223,7 @@ func.func @reduce_op_and_body(%arg0 : f32) {
   %res = "gpu.all_reduce"(%arg0) ({
   ^bb(%lhs : f32, %rhs : f32):
     "gpu.yield"(%lhs) : (f32) -> ()
-  }) {op = #gpu<"all_reduce_op add">} : (f32) -> (f32)
+  }) {op = #gpu<all_reduce_op add>} : (f32) -> (f32)
   return
 }
 
@@ -303,7 +303,7 @@ func.func @reduce_incorrect_yield(%arg0 : f32) {
 
 func.func @shuffle_mismatching_type(%arg0 : f32, %arg1 : i32, %arg2 : i32) {
   // expected-error at +1 {{op failed to verify that all of {value, result} have same type}}
-  %shfl, %pred = "gpu.shuffle"(%arg0, %arg1, %arg2) { mode = #gpu<"shuffle_mode xor"> } : (f32, i32, i32) -> (i32, i1)
+  %shfl, %pred = "gpu.shuffle"(%arg0, %arg1, %arg2) { mode = #gpu<shuffle_mode xor> } : (f32, i32, i32) -> (i32, i1)
   return
 }
 

diff  --git a/mlir/test/Dialect/OpenACC/ops.mlir b/mlir/test/Dialect/OpenACC/ops.mlir
index 9760ee610c81f..48d343b7d2c80 100644
--- a/mlir/test/Dialect/OpenACC/ops.mlir
+++ b/mlir/test/Dialect/OpenACC/ops.mlir
@@ -376,9 +376,9 @@ func.func @testparallelop(%a: memref<10xf32>, %b: memref<10xf32>, %c: memref<10x
   acc.parallel private(%a: memref<10xf32>, %c: memref<10x10xf32>) firstprivate(%b: memref<10xf32>) {
   }
   acc.parallel {
-  } attributes {defaultAttr = #acc<"defaultvalue none">}
+  } attributes {defaultAttr = #acc<defaultvalue none>}
   acc.parallel {
-  } attributes {defaultAttr = #acc<"defaultvalue present">}
+  } attributes {defaultAttr = #acc<defaultvalue present>}
   acc.parallel {
   } attributes {asyncAttr}
   acc.parallel {
@@ -441,9 +441,9 @@ func.func @testparallelop(%a: memref<10xf32>, %b: memref<10xf32>, %c: memref<10x
 // CHECK:      acc.parallel private([[ARGA]]: memref<10xf32>, [[ARGC]]: memref<10x10xf32>) firstprivate([[ARGB]]: memref<10xf32>) {
 // CHECK-NEXT: }
 // CHECK:      acc.parallel {
-// CHECK-NEXT: } attributes {defaultAttr = #acc<"defaultvalue none">}
+// CHECK-NEXT: } attributes {defaultAttr = #acc<defaultvalue none>}
 // CHECK:      acc.parallel {
-// CHECK-NEXT: } attributes {defaultAttr = #acc<"defaultvalue present">}
+// CHECK-NEXT: } attributes {defaultAttr = #acc<defaultvalue present>}
 // CHECK:      acc.parallel {
 // CHECK-NEXT: } attributes {asyncAttr}
 // CHECK:      acc.parallel {
@@ -482,11 +482,11 @@ func.func @testdataop(%a: memref<10xf32>, %b: memref<10xf32>, %c: memref<10x10xf
   acc.data copyin(%b: memref<10xf32>) copyout(%c: memref<10x10xf32>) present(%a: memref<10xf32>) {
   }
   acc.data present(%a : memref<10xf32>) {
-  } attributes { defaultAttr = #acc<"defaultvalue none"> }
+  } attributes { defaultAttr = #acc<defaultvalue none> }
   acc.data present(%a : memref<10xf32>) {
-  } attributes { defaultAttr = #acc<"defaultvalue present"> }
+  } attributes { defaultAttr = #acc<defaultvalue present> }
   acc.data {
-  } attributes { defaultAttr = #acc<"defaultvalue none"> }
+  } attributes { defaultAttr = #acc<defaultvalue none> }
   return
 }
 
@@ -519,11 +519,11 @@ func.func @testdataop(%a: memref<10xf32>, %b: memref<10xf32>, %c: memref<10x10xf
 // CHECK:      acc.data copyin([[ARGB]] : memref<10xf32>) copyout([[ARGC]] : memref<10x10xf32>) present([[ARGA]] : memref<10xf32>) {
 // CHECK-NEXT: }
 // CHECK:      acc.data present([[ARGA]] : memref<10xf32>) {
-// CHECK-NEXT: } attributes {defaultAttr = #acc<"defaultvalue none">}
+// CHECK-NEXT: } attributes {defaultAttr = #acc<defaultvalue none>}
 // CHECK:      acc.data present([[ARGA]] : memref<10xf32>) {
-// CHECK-NEXT: } attributes {defaultAttr = #acc<"defaultvalue present">}
+// CHECK-NEXT: } attributes {defaultAttr = #acc<defaultvalue present>}
 // CHECK:      acc.data {
-// CHECK-NEXT: } attributes {defaultAttr = #acc<"defaultvalue none">}
+// CHECK-NEXT: } attributes {defaultAttr = #acc<defaultvalue none>}
 
 // -----
 

diff  --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir
index b4dccd72aa02d..2682c977cca90 100644
--- a/mlir/test/Dialect/OpenMP/ops.mlir
+++ b/mlir/test/Dialect/OpenMP/ops.mlir
@@ -77,7 +77,7 @@ func.func @omp_parallel(%data_var : memref<i32>, %if_cond : i1, %num_threads : i
     }) {operand_segment_sizes = dense<[1,1,0,0,0]> : vector<5xi32>} : (i1, i32) -> ()
 
     omp.terminator
-  }) {operand_segment_sizes = dense<[1,1,1,1,0]> : vector<5xi32>, proc_bind_val = #omp<"procbindkind spread">} : (i1, i32, memref<i32>, memref<i32>) -> ()
+  }) {operand_segment_sizes = dense<[1,1,1,1,0]> : vector<5xi32>, proc_bind_val = #omp<procbindkind spread>} : (i1, i32, memref<i32>, memref<i32>) -> ()
 
   // test with multiple parameters for single variadic argument
   // CHECK: omp.parallel allocate(%{{.*}} : memref<i32> -> %{{.*}} : memref<i32>)
@@ -149,7 +149,7 @@ func.func @omp_wsloop(%lb : index, %ub : index, %step : index, %data_var : memre
   "omp.wsloop" (%lb, %ub, %step, %data_var, %linear_var) ({
     ^bb0(%iv: index):
       omp.yield
-  }) {operand_segment_sizes = dense<[1,1,1,1,1,0,0]> : vector<7xi32>, schedule_val = #omp<"schedulekind static">} :
+  }) {operand_segment_sizes = dense<[1,1,1,1,1,0,0]> : vector<7xi32>, schedule_val = #omp<schedulekind static>} :
     (index, index, index, memref<i32>, i32) -> ()
 
   // CHECK: omp.wsloop linear(%{{.*}} = %{{.*}} : memref<i32>, %{{.*}} = %{{.*}} : memref<i32>) schedule(static)
@@ -157,7 +157,7 @@ func.func @omp_wsloop(%lb : index, %ub : index, %step : index, %data_var : memre
   "omp.wsloop" (%lb, %ub, %step, %data_var, %data_var, %linear_var, %linear_var) ({
     ^bb0(%iv: index):
       omp.yield
-  }) {operand_segment_sizes = dense<[1,1,1,2,2,0,0]> : vector<7xi32>, schedule_val = #omp<"schedulekind static">} :
+  }) {operand_segment_sizes = dense<[1,1,1,2,2,0,0]> : vector<7xi32>, schedule_val = #omp<schedulekind static>} :
     (index, index, index, memref<i32>, memref<i32>, i32, i32) -> ()
 
   // CHECK: omp.wsloop linear(%{{.*}} = %{{.*}} : memref<i32>) schedule(dynamic = %{{.*}}) ordered(2)
@@ -165,7 +165,7 @@ func.func @omp_wsloop(%lb : index, %ub : index, %step : index, %data_var : memre
   "omp.wsloop" (%lb, %ub, %step, %data_var, %linear_var, %chunk_var) ({
     ^bb0(%iv: index):
       omp.yield
-  }) {operand_segment_sizes = dense<[1,1,1,1,1,0,1]> : vector<7xi32>, schedule_val = #omp<"schedulekind dynamic">, ordered_val = 2} :
+  }) {operand_segment_sizes = dense<[1,1,1,1,1,0,1]> : vector<7xi32>, schedule_val = #omp<schedulekind dynamic>, ordered_val = 2} :
     (index, index, index, memref<i32>, i32, i32) -> ()
 
   // CHECK: omp.wsloop schedule(auto) nowait
@@ -173,7 +173,7 @@ func.func @omp_wsloop(%lb : index, %ub : index, %step : index, %data_var : memre
   "omp.wsloop" (%lb, %ub, %step) ({
     ^bb0(%iv: index):
       omp.yield
-  }) {operand_segment_sizes = dense<[1,1,1,0,0,0,0]> : vector<7xi32>, nowait, schedule_val = #omp<"schedulekind auto">} :
+  }) {operand_segment_sizes = dense<[1,1,1,0,0,0,0]> : vector<7xi32>, nowait, schedule_val = #omp<schedulekind auto>} :
     (index, index, index) -> ()
 
   return

diff  --git a/mlir/test/Dialect/Quant/parse-any-invalid.mlir b/mlir/test/Dialect/Quant/parse-any-invalid.mlir
index ca428e169245f..41c5f93070717 100644
--- a/mlir/test/Dialect/Quant/parse-any-invalid.mlir
+++ b/mlir/test/Dialect/Quant/parse-any-invalid.mlir
@@ -7,8 +7,8 @@
 
 // -----
 // Unrecognized token: missing closing angle bracket
-// expected-error at +1 {{expected '>'}}
-!qalias = !quant<"any<i8<-4:3:f32>">
+// expected-error at +1 {{unbalanced '<' character in pretty dialect name}}
+!qalias = !quant<any<i8<-4:3:f32>>
 
 // -----
 // Unrecognized token: missing type colon

diff  --git a/mlir/test/Dialect/Quant/parse-calibrated-invalid.mlir b/mlir/test/Dialect/Quant/parse-calibrated-invalid.mlir
index fbeb20b951964..643292815af07 100644
--- a/mlir/test/Dialect/Quant/parse-calibrated-invalid.mlir
+++ b/mlir/test/Dialect/Quant/parse-calibrated-invalid.mlir
@@ -8,8 +8,8 @@
 
 // -----
 // Unrecognized token: missing closing angle bracket
-// expected-error at +1 {{expected '>'}}
-!qalias = !quant<"calibrated<f32<-0.998:1.232>">
+// expected-error at +1 {{unbalanced '<' character in pretty dialect name}}
+!qalias = !quant.calibrated<f32<-0.998:1.232>
 
 // -----
 // Unrecognized expressed type: integer type

diff  --git a/mlir/test/Dialect/Quant/parse-uniform-invalid.mlir b/mlir/test/Dialect/Quant/parse-uniform-invalid.mlir
index 61ea54fe16300..a82e8efdb1a3c 100644
--- a/mlir/test/Dialect/Quant/parse-uniform-invalid.mlir
+++ b/mlir/test/Dialect/Quant/parse-uniform-invalid.mlir
@@ -22,8 +22,8 @@
 
 // -----
 // Unrecognized token: missing closing angle bracket
-// expected-error at +1 {{expected '>'}}
-!qalias = !quant<"uniform<i8<-4:3:f32, 0.99872:127>">
+// expected-error at +1 {{unbalanced '<' character in pretty dialect name}}
+!qalias = !quant<uniform<i8<-4:3:f32, 0.99872:127>>
 
 // -----
 // Unrecognized token: missing type colon

diff  --git a/mlir/test/IR/enum-attr-invalid.mlir b/mlir/test/IR/enum-attr-invalid.mlir
index 7000c148a58a0..923736f28dadb 100644
--- a/mlir/test/IR/enum-attr-invalid.mlir
+++ b/mlir/test/IR/enum-attr-invalid.mlir
@@ -3,7 +3,7 @@
 func.func @test_invalid_enum_case() -> () {
   // expected-error at +2 {{expected test::TestEnum to be one of: first, second, third}}
   // expected-error at +1 {{failed to parse TestEnumAttr}}
-  test.op_with_enum #test<"enum fourth">
+  test.op_with_enum #test<enum fourth>
 }
 
 // -----

diff  --git a/mlir/test/IR/enum-attr-roundtrip.mlir b/mlir/test/IR/enum-attr-roundtrip.mlir
index 5594fe77c8a02..8ef4495f0bf03 100644
--- a/mlir/test/IR/enum-attr-roundtrip.mlir
+++ b/mlir/test/IR/enum-attr-roundtrip.mlir
@@ -2,12 +2,12 @@
 
 // CHECK-LABEL: @test_enum_attr_roundtrip
 func.func @test_enum_attr_roundtrip() -> () {
-  // CHECK: value = #test<"enum first">
-  "test.op"() {value = #test<"enum first">} : () -> ()
-  // CHECK: value = #test<"enum second">
-  "test.op"() {value = #test<"enum second">} : () -> ()
-  // CHECK: value = #test<"enum third">
-  "test.op"() {value = #test<"enum third">} : () -> ()
+  // CHECK: value = #test<enum first>
+  "test.op"() {value = #test<enum first>} : () -> ()
+  // CHECK: value = #test<enum second>
+  "test.op"() {value = #test<enum second>} : () -> ()
+  // CHECK: value = #test<enum third>
+  "test.op"() {value = #test<enum third>} : () -> ()
   return
 }
 

diff  --git a/mlir/test/IR/invalid.mlir b/mlir/test/IR/invalid.mlir
index 7d111c9b69be6..1bc82f6787577 100644
--- a/mlir/test/IR/invalid.mlir
+++ b/mlir/test/IR/invalid.mlir
@@ -842,15 +842,8 @@ func.func @dialect_type_empty_namespace(!<"">) -> () { // expected-error {{inval
 
 // -----
 
-func.func @dialect_type_no_string_type_data(!foo<>) -> () { // expected-error {{expected string literal data in dialect symbol}}
+func.func @dialect_type_missing_greater(!foo<) -> () { // expected-error {{unbalanced ')' character in pretty dialect name}}
   return
-}
-
-// -----
-
-func.func @dialect_type_missing_greater(!foo<"") -> () { // expected-error {{expected '>' in dialect symbol}}
-  return
-}
 
 // -----
 

diff  --git a/mlir/test/IR/parser.mlir b/mlir/test/IR/parser.mlir
index a28e63d5e498d..34b667ffa6002 100644
--- a/mlir/test/IR/parser.mlir
+++ b/mlir/test/IR/parser.mlir
@@ -790,10 +790,10 @@ func.func @sparsetensorattr() -> () {
 // CHECK: "foof321"() {bar = sparse<> : tensor<f32>} : () -> ()
   "foof321"(){bar = sparse<> : tensor<f32>} : () -> ()
 
-// CHECK: "foostr"() {bar = sparse<0, "foo"> : tensor<1x1x1x!unknown<"">>} : () -> ()
-  "foostr"(){bar = sparse<0, "foo"> : tensor<1x1x1x!unknown<"">>} : () -> ()
-// CHECK: "foostr"() {bar = sparse<{{\[\[}}1, 1, 0], {{\[}}0, 1, 0], {{\[}}0, 0, 1]], {{\[}}"a", "b", "c"]> : tensor<2x2x2x!unknown<"">>} : () -> ()
-  "foostr"(){bar = sparse<[[1, 1, 0], [0, 1, 0], [0, 0, 1]], ["a", "b", "c"]> : tensor<2x2x2x!unknown<"">>} : () -> ()
+// CHECK: "foostr"() {bar = sparse<0, "foo"> : tensor<1x1x1x!unknown<>>} : () -> ()
+  "foostr"(){bar = sparse<0, "foo"> : tensor<1x1x1x!unknown<>>} : () -> ()
+// CHECK: "foostr"() {bar = sparse<{{\[\[}}1, 1, 0], {{\[}}0, 1, 0], {{\[}}0, 0, 1]], {{\[}}"a", "b", "c"]> : tensor<2x2x2x!unknown<>>} : () -> ()
+  "foostr"(){bar = sparse<[[1, 1, 0], [0, 1, 0], [0, 0, 1]], ["a", "b", "c"]> : tensor<2x2x2x!unknown<>>} : () -> ()
   return
 }
 
@@ -819,16 +819,16 @@ func.func @sparsevectorattr() -> () {
   return
 }
 
-// CHECK-LABEL: func @unknown_dialect_type() -> !bar<""> {
-func.func @unknown_dialect_type() -> !bar<""> {
+// CHECK-LABEL: func @unknown_dialect_type() -> !bar<> {
+func.func @unknown_dialect_type() -> !bar<> {
   // Unregistered dialect 'bar'.
-  // CHECK: "foo"() : () -> !bar<"">
-  %0 = "foo"() : () -> !bar<"">
+  // CHECK: "foo"() : () -> !bar<>
+  %0 = "foo"() : () -> !bar<>
 
   // CHECK: "foo"() : () -> !bar.baz
-  %1 = "foo"() : () -> !bar<"baz">
+  %1 = "foo"() : () -> !bar<baz>
 
-  return %0 : !bar<"">
+  return %0 : !bar<>
 }
 
 // CHECK-LABEL: func @type_alias() -> i32 {
@@ -953,10 +953,6 @@ func.func @pretty_dialect_attribute() {
   // CHECK: "foo.unknown_op"() {foo = #foo.dialect<!x@#!@#>} : () -> ()
   "foo.unknown_op"() {foo = #foo.dialect<!x@#!@#>} : () -> ()
 
-  // Extraneous extra > character can't use the pretty syntax.
-  // CHECK: "foo.unknown_op"() {foo = #foo<"dialect<!x@#!@#>>">} : () -> ()
-  "foo.unknown_op"() {foo = #foo<"dialect<!x@#!@#>>">} : () -> ()
-
   return
 }
 
@@ -978,10 +974,6 @@ func.func @pretty_dialect_type() {
   // CHECK: %{{.*}} = "foo.unknown_op"() : () -> !foo.dialect<!x@#!@#>
   %4 = "foo.unknown_op"() : () -> !foo.dialect<!x@#!@#>
 
-  // Extraneous extra > character can't use the pretty syntax.
-  // CHECK: %{{.*}} = "foo.unknown_op"() : () -> !foo<"dialect<!x@#!@#>>">
-  %5 = "foo.unknown_op"() : () -> !foo<"dialect<!x@#!@#>>">
-
   return
 }
 
@@ -1202,7 +1194,7 @@ func.func @"\"_string_symbol_reference\""() {
 
 // CHECK-LABEL: func private @parse_opaque_attr_escape
 func.func private @parse_opaque_attr_escape() {
-    // CHECK: value = #foo<"\22escaped\\\0A\22">
+    // CHECK: value = #foo<"\"escaped\\\n\"">
     "foo.constant"() {value = #foo<"\"escaped\\\n\"">} : () -> ()
 }
 

diff  --git a/mlir/test/Target/Cpp/types.mlir b/mlir/test/Target/Cpp/types.mlir
index 916f20ed8b761..8b4cecf756120 100644
--- a/mlir/test/Target/Cpp/types.mlir
+++ b/mlir/test/Target/Cpp/types.mlir
@@ -3,13 +3,13 @@
 // CHECK-LABEL: void opaque_types() {
 func.func @opaque_types() {
   // CHECK-NEXT: f<int>();
-  emitc.call "f"() {template_args = [!emitc<"opaque<\"int\">">]} : () -> ()
+  emitc.call "f"() {template_args = [!emitc<opaque<"int">>]} : () -> ()
   // CHECK-NEXT: f<byte>();
-  emitc.call "f"() {template_args = [!emitc<"opaque<\"byte\">">]} : () -> ()
+  emitc.call "f"() {template_args = [!emitc<opaque<"byte">>]} : () -> ()
   // CHECK-NEXT: f<unsigned>();
-  emitc.call "f"() {template_args = [!emitc<"opaque<\"unsigned\">">]} : () -> ()
+  emitc.call "f"() {template_args = [!emitc<opaque<"unsigned">>]} : () -> ()
   // CHECK-NEXT: f<status_t>();
-  emitc.call "f"() {template_args = [!emitc<"opaque<\"status_t\">">]} : () -> ()
+  emitc.call "f"() {template_args = [!emitc<opaque<"status_t">>]} : () -> ()
   // CHECK-NEXT: f<std::vector<std::string>>();
   emitc.call "f"() {template_args = [!emitc.opaque<"std::vector<std::string>">]} : () -> ()
 
@@ -19,11 +19,11 @@ func.func @opaque_types() {
 // CHECK-LABEL: void ptr_types() {
 func.func @ptr_types() {
   // CHECK-NEXT: f<int32_t*>();
-  emitc.call "f"() {template_args = [!emitc<"ptr<i32>">]} : () -> ()
+  emitc.call "f"() {template_args = [!emitc.ptr<i32>]} : () -> ()
   // CHECK-NEXT: f<int64_t*>();
   emitc.call "f"() {template_args = [!emitc.ptr<i64>]} : () -> ()
   // CHECK-NEXT: f<float*>();
-  emitc.call "f"() {template_args = [!emitc<"ptr<f32>">]} : () -> ()
+  emitc.call "f"() {template_args = [!emitc.ptr<f32>]} : () -> ()
   // CHECK-NEXT: f<double*>();
   emitc.call "f"() {template_args = [!emitc.ptr<f64>]} : () -> ()
   // CHECK-NEXT: int32_t* [[V0:[^ ]*]] = f();

diff  --git a/mlir/test/mlir-tblgen/attr-or-type-format-roundtrip.mlir b/mlir/test/mlir-tblgen/attr-or-type-format-roundtrip.mlir
index 569fb093a080b..08e0a629f2cec 100644
--- a/mlir/test/mlir-tblgen/attr-or-type-format-roundtrip.mlir
+++ b/mlir/test/mlir-tblgen/attr-or-type-format-roundtrip.mlir
@@ -1,16 +1,16 @@
 // RUN: mlir-opt %s | mlir-opt | FileCheck %s
 
 // CHECK-LABEL: @test_roundtrip_parameter_parsers
-// CHECK: !test.type_with_format<111, three = #test<"attr_ugly begin 5 : index end">, two = "foo">
+// CHECK: !test.type_with_format<111, three = #test<attr_ugly begin 5 : index end>, two = "foo">
 // CHECK: !test.type_with_format<2147, three = "hi", two = "hi">
-func.func private @test_roundtrip_parameter_parsers(!test.type_with_format<111, three = #test<"attr_ugly begin 5 : index end">, two = "foo">) -> !test.type_with_format<2147, two = "hi", three = "hi">
+func.func private @test_roundtrip_parameter_parsers(!test.type_with_format<111, three = #test<attr_ugly begin 5 : index end>, two = "foo">) -> !test.type_with_format<2147, two = "hi", three = "hi">
 attributes {
   // CHECK: #test.attr_with_format<3 : two = "hello", four = [1, 2, 3] : 42 : i64, [ 10 : i16]
   attr0 = #test.attr_with_format<3 : two = "hello", four = [1, 2, 3] : 42 : i64, [10 : i16]>,
   // CHECK: #test.attr_with_format<5 : two = "a_string", four = [4, 5, 6, 7, 8] : 8 : i8, [ 10 : i16]>,
   attr1 = #test.attr_with_format<5 : two = "a_string", four = [4, 5, 6, 7, 8] : 8 : i8, [10 : i16]>,
-  // CHECK: #test<"attr_ugly begin 5 : index end">
-  attr2 = #test<"attr_ugly begin 5 : index end">,
+  // CHECK: #test<attr_ugly begin 5 : index end>
+  attr2 = #test<attr_ugly begin 5 : index end>,
   // CHECK: #test.attr_params<42, 24>
   attr3 = #test.attr_params<42, 24>,
   // CHECK: #test.attr_with_type<i32, vector<4xi32>>

diff  --git a/mlir/test/mlir-tblgen/attr-or-type-format.mlir b/mlir/test/mlir-tblgen/attr-or-type-format.mlir
index 8f0378fde7668..eb7d967c658b9 100644
--- a/mlir/test/mlir-tblgen/attr-or-type-format.mlir
+++ b/mlir/test/mlir-tblgen/attr-or-type-format.mlir
@@ -1,22 +1,22 @@
 // RUN: mlir-opt --split-input-file %s --verify-diagnostics
 
 func.func private @test_ugly_attr_cannot_be_pretty() -> () attributes {
-  // expected-error at +1 {{expected 'begin'}}
-  attr = #test.attr_ugly
+  // expected-error at below {{expected 'begin'}}
+  attr = #test.attr_ugly,
 }
 
 // -----
 
 func.func private @test_ugly_attr_no_mnemonic() -> () attributes {
   // expected-error at +1 {{expected valid keyword}}
-  attr = #test<"">
+  attr = #test<>
 }
 
 // -----
 
 func.func private @test_ugly_attr_parser_dispatch() -> () attributes {
   // expected-error at +1 {{expected 'begin'}}
-  attr = #test<"attr_ugly">
+  attr = #test<attr_ugly>
 }
 
 // -----
@@ -24,21 +24,21 @@ func.func private @test_ugly_attr_parser_dispatch() -> () attributes {
 func.func private @test_ugly_attr_missing_parameter() -> () attributes {
   // expected-error at +2 {{failed to parse TestAttrUgly parameter 'attr'}}
   // expected-error at +1 {{expected attribute value}}
-  attr = #test<"attr_ugly begin">
+  attr = #test<attr_ugly begin>
 }
 
 // -----
 
 func.func private @test_ugly_attr_missing_literal() -> () attributes {
   // expected-error at +1 {{expected 'end'}}
-  attr = #test<"attr_ugly begin \"string_attr\"">
+  attr = #test<attr_ugly begin "string_attr">
 }
 
 // -----
 
 func.func private @test_pretty_attr_expects_less() -> () attributes {
   // expected-error at +1 {{expected '<'}}
-  attr = #test.attr_with_format
+  attr = #test.attr_with_format,
 }
 
 // -----
@@ -55,7 +55,7 @@ func.func private @test_parse_invalid_param() -> () attributes {
   // Test parameter parser failure is propagated
   // expected-error at +2 {{expected integer value}}
   // expected-error at +1 {{failed to parse TestAttrWithFormat parameter 'one'}}
-  attr = #test.attr_with_format<"hi">
+  attr = #test.attr_with_format<hi>
 }
 
 // -----
@@ -105,7 +105,7 @@ func.func private @test_parse_param_after_struct() -> () attributes {
 // -----
 
 // expected-error at +1 {{expected '<'}}
-func.func private @test_invalid_type() -> !test.type_with_format
+func.func private @test_invalid_type() -> !test.type_with_format,
 
 // -----
 

diff  --git a/mlir/test/mlir-tblgen/testdialect-attrdefs.mlir b/mlir/test/mlir-tblgen/testdialect-attrdefs.mlir
index 33fd88b45f99c..4ccf3bd624094 100644
--- a/mlir/test/mlir-tblgen/testdialect-attrdefs.mlir
+++ b/mlir/test/mlir-tblgen/testdialect-attrdefs.mlir
@@ -7,8 +7,8 @@ func.func private @compoundA() attributes {foo = #test.cmpnd_a<1, !test.smpla, [
 // CHECK: test.result_has_same_type_as_attr #test.attr_with_self_type_param : i32 -> i32
 %a = test.result_has_same_type_as_attr #test.attr_with_self_type_param : i32 -> i32
 
-// CHECK: test.result_has_same_type_as_attr #test<"attr_with_type_builder 10 : i16"> : i16 -> i16
-%b = test.result_has_same_type_as_attr #test<"attr_with_type_builder 10 : i16"> -> i16
+// CHECK: test.result_has_same_type_as_attr #test<attr_with_type_builder 10 : i16> : i16 -> i16
+%b = test.result_has_same_type_as_attr #test<attr_with_type_builder 10 : i16> -> i16
 
 // CHECK-LABEL: @qualifiedAttr()
 // CHECK-SAME: #test.cmpnd_nested_outer_qual<i #test.cmpnd_nested_inner<42 <1, !test.smpla, [5, 6]>>>

diff  --git a/mlir/test/python/ir/attributes.py b/mlir/test/python/ir/attributes.py
index f5efdf3880bb2..97ebdd323fe47 100644
--- a/mlir/test/python/ir/attributes.py
+++ b/mlir/test/python/ir/attributes.py
@@ -248,7 +248,7 @@ def testOpaqueAttr():
     print("oattr value:", oattr.data)
 
     # Test factory methods.
-    # CHECK: default_get: #foobar<"123">
+    # CHECK: default_get: #foobar<123>
     print(
         "default_get:",
         OpaqueAttr.get("foobar", bytes("123", "utf-8"), NoneType.get()))


        


More information about the Mlir-commits mailing list