MLIR  18.0.0git
Parser.cpp
Go to the documentation of this file.
1 //===- Parser.cpp - MLIR Parser Implementation ----------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the parser for the MLIR textual form.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "Parser.h"
14 #include "AsmParserImpl.h"
18 #include "mlir/IR/AffineExpr.h"
19 #include "mlir/IR/AffineMap.h"
20 #include "mlir/IR/AsmState.h"
21 #include "mlir/IR/Attributes.h"
23 #include "mlir/IR/BuiltinOps.h"
24 #include "mlir/IR/BuiltinTypes.h"
25 #include "mlir/IR/Diagnostics.h"
26 #include "mlir/IR/Dialect.h"
27 #include "mlir/IR/Location.h"
28 #include "mlir/IR/OpDefinition.h"
31 #include "mlir/IR/OwningOpRef.h"
32 #include "mlir/IR/Region.h"
33 #include "mlir/IR/Value.h"
34 #include "mlir/IR/Verifier.h"
35 #include "mlir/IR/Visitors.h"
36 #include "mlir/Support/LLVM.h"
38 #include "mlir/Support/TypeID.h"
39 #include "llvm/ADT/APFloat.h"
40 #include "llvm/ADT/DenseMap.h"
41 #include "llvm/ADT/PointerUnion.h"
42 #include "llvm/ADT/STLExtras.h"
43 #include "llvm/ADT/ScopeExit.h"
44 #include "llvm/ADT/Sequence.h"
45 #include "llvm/ADT/StringMap.h"
46 #include "llvm/ADT/StringSet.h"
47 #include "llvm/Support/Alignment.h"
48 #include "llvm/Support/Casting.h"
49 #include "llvm/Support/Endian.h"
50 #include "llvm/Support/ErrorHandling.h"
51 #include "llvm/Support/MathExtras.h"
52 #include "llvm/Support/PrettyStackTrace.h"
53 #include "llvm/Support/SourceMgr.h"
54 #include "llvm/Support/raw_ostream.h"
55 #include <algorithm>
56 #include <cassert>
57 #include <cstddef>
58 #include <cstdint>
59 #include <cstring>
60 #include <memory>
61 #include <optional>
62 #include <string>
63 #include <tuple>
64 #include <utility>
65 #include <vector>
66 
67 using namespace mlir;
68 using namespace mlir::detail;
69 
70 //===----------------------------------------------------------------------===//
71 // CodeComplete
72 //===----------------------------------------------------------------------===//
73 
75 
76 //===----------------------------------------------------------------------===//
77 // Parser
78 //===----------------------------------------------------------------------===//
79 
80 /// Parse a list of comma-separated items with an optional delimiter. If a
81 /// delimiter is provided, then an empty list is allowed. If not, then at
82 /// least one element will be parsed.
85  function_ref<ParseResult()> parseElementFn,
86  StringRef contextMessage) {
87  switch (delimiter) {
88  case Delimiter::None:
89  break;
91  if (getToken().isNot(Token::l_paren))
92  return success();
93  [[fallthrough]];
94  case Delimiter::Paren:
95  if (parseToken(Token::l_paren, "expected '('" + contextMessage))
96  return failure();
97  // Check for empty list.
98  if (consumeIf(Token::r_paren))
99  return success();
100  break;
102  // Check for absent list.
103  if (getToken().isNot(Token::less))
104  return success();
105  [[fallthrough]];
107  if (parseToken(Token::less, "expected '<'" + contextMessage))
108  return success();
109  // Check for empty list.
110  if (consumeIf(Token::greater))
111  return success();
112  break;
114  if (getToken().isNot(Token::l_square))
115  return success();
116  [[fallthrough]];
117  case Delimiter::Square:
118  if (parseToken(Token::l_square, "expected '['" + contextMessage))
119  return failure();
120  // Check for empty list.
121  if (consumeIf(Token::r_square))
122  return success();
123  break;
125  if (getToken().isNot(Token::l_brace))
126  return success();
127  [[fallthrough]];
128  case Delimiter::Braces:
129  if (parseToken(Token::l_brace, "expected '{'" + contextMessage))
130  return failure();
131  // Check for empty list.
132  if (consumeIf(Token::r_brace))
133  return success();
134  break;
135  }
136 
137  // Non-empty case starts with an element.
138  if (parseElementFn())
139  return failure();
140 
141  // Otherwise we have a list of comma separated elements.
142  while (consumeIf(Token::comma)) {
143  if (parseElementFn())
144  return failure();
145  }
146 
147  switch (delimiter) {
148  case Delimiter::None:
149  return success();
151  case Delimiter::Paren:
152  return parseToken(Token::r_paren, "expected ')'" + contextMessage);
155  return parseToken(Token::greater, "expected '>'" + contextMessage);
157  case Delimiter::Square:
158  return parseToken(Token::r_square, "expected ']'" + contextMessage);
160  case Delimiter::Braces:
161  return parseToken(Token::r_brace, "expected '}'" + contextMessage);
162  }
163  llvm_unreachable("Unknown delimiter");
164 }
165 
166 /// Parse a comma-separated list of elements, terminated with an arbitrary
167 /// token. This allows empty lists if allowEmptyList is true.
168 ///
169 /// abstract-list ::= rightToken // if allowEmptyList == true
170 /// abstract-list ::= element (',' element)* rightToken
171 ///
174  function_ref<ParseResult()> parseElement,
175  bool allowEmptyList) {
176  // Handle the empty case.
177  if (getToken().is(rightToken)) {
178  if (!allowEmptyList)
179  return emitWrongTokenError("expected list element");
180  consumeToken(rightToken);
181  return success();
182  }
183 
184  if (parseCommaSeparatedList(parseElement) ||
185  parseToken(rightToken, "expected ',' or '" +
186  Token::getTokenSpelling(rightToken) + "'"))
187  return failure();
188 
189  return success();
190 }
191 
192 InFlightDiagnostic Parser::emitError(const Twine &message) {
193  auto loc = state.curToken.getLoc();
194  if (state.curToken.isNot(Token::eof))
195  return emitError(loc, message);
196 
197  // If the error is to be emitted at EOF, move it back one character.
198  return emitError(SMLoc::getFromPointer(loc.getPointer() - 1), message);
199 }
200 
201 InFlightDiagnostic Parser::emitError(SMLoc loc, const Twine &message) {
202  auto diag = mlir::emitError(getEncodedSourceLocation(loc), message);
203 
204  // If we hit a parse error in response to a lexer error, then the lexer
205  // already reported the error.
206  if (getToken().is(Token::error))
207  diag.abandon();
208  return diag;
209 }
210 
211 /// Emit an error about a "wrong token". If the current token is at the
212 /// start of a source line, this will apply heuristics to back up and report
213 /// the error at the end of the previous line, which is where the expected
214 /// token is supposed to be.
216  auto loc = state.curToken.getLoc();
217 
218  // If the error is to be emitted at EOF, move it back one character.
219  if (state.curToken.is(Token::eof))
220  loc = SMLoc::getFromPointer(loc.getPointer() - 1);
221 
222  // This is the location we were originally asked to report the error at.
223  auto originalLoc = loc;
224 
225  // Determine if the token is at the start of the current line.
226  const char *bufferStart = state.lex.getBufferBegin();
227  const char *curPtr = loc.getPointer();
228 
229  // Use this StringRef to keep track of what we are going to back up through,
230  // it provides nicer string search functions etc.
231  StringRef startOfBuffer(bufferStart, curPtr - bufferStart);
232 
233  // Back up over entirely blank lines.
234  while (true) {
235  // Back up until we see a \n, but don't look past the buffer start.
236  startOfBuffer = startOfBuffer.rtrim(" \t");
237 
238  // For tokens with no preceding source line, just emit at the original
239  // location.
240  if (startOfBuffer.empty())
241  return emitError(originalLoc, message);
242 
243  // If we found something that isn't the end of line, then we're done.
244  if (startOfBuffer.back() != '\n' && startOfBuffer.back() != '\r')
245  return emitError(SMLoc::getFromPointer(startOfBuffer.end()), message);
246 
247  // Drop the \n so we emit the diagnostic at the end of the line.
248  startOfBuffer = startOfBuffer.drop_back();
249 
250  // Check to see if the preceding line has a comment on it. We assume that a
251  // `//` is the start of a comment, which is mostly correct.
252  // TODO: This will do the wrong thing for // in a string literal.
253  auto prevLine = startOfBuffer;
254  size_t newLineIndex = prevLine.find_last_of("\n\r");
255  if (newLineIndex != StringRef::npos)
256  prevLine = prevLine.drop_front(newLineIndex);
257 
258  // If we find a // in the current line, then emit the diagnostic before it.
259  size_t commentStart = prevLine.find("//");
260  if (commentStart != StringRef::npos)
261  startOfBuffer = startOfBuffer.drop_back(prevLine.size() - commentStart);
262  }
263 }
264 
265 /// Consume the specified token if present and return success. On failure,
266 /// output a diagnostic and return failure.
268  const Twine &message) {
269  if (consumeIf(expectedToken))
270  return success();
271  return emitWrongTokenError(message);
272 }
273 
274 /// Parse an optional integer value from the stream.
276  // Parse `false` and `true` keywords as 0 and 1 respectively.
277  if (consumeIf(Token::kw_false)) {
278  result = false;
279  return success();
280  }
281  if (consumeIf(Token::kw_true)) {
282  result = true;
283  return success();
284  }
285 
286  Token curToken = getToken();
287  if (curToken.isNot(Token::integer, Token::minus))
288  return std::nullopt;
289 
290  bool negative = consumeIf(Token::minus);
291  Token curTok = getToken();
292  if (parseToken(Token::integer, "expected integer value"))
293  return failure();
294 
295  StringRef spelling = curTok.getSpelling();
296  bool isHex = spelling.size() > 1 && spelling[1] == 'x';
297  if (spelling.getAsInteger(isHex ? 0 : 10, result))
298  return emitError(curTok.getLoc(), "integer value too large");
299 
300  // Make sure we have a zero at the top so we return the right signedness.
301  if (result.isNegative())
302  result = result.zext(result.getBitWidth() + 1);
303 
304  // Process the negative sign if present.
305  if (negative)
306  result.negate();
307 
308  return success();
309 }
310 
311 /// Parse a floating point value from an integer literal token.
313  std::optional<APFloat> &result, const Token &tok, bool isNegative,
314  const llvm::fltSemantics &semantics, size_t typeSizeInBits) {
315  SMLoc loc = tok.getLoc();
316  StringRef spelling = tok.getSpelling();
317  bool isHex = spelling.size() > 1 && spelling[1] == 'x';
318  if (!isHex) {
319  return emitError(loc, "unexpected decimal integer literal for a "
320  "floating point value")
321  .attachNote()
322  << "add a trailing dot to make the literal a float";
323  }
324  if (isNegative) {
325  return emitError(loc, "hexadecimal float literal should not have a "
326  "leading minus");
327  }
328 
329  std::optional<uint64_t> value = tok.getUInt64IntegerValue();
330  if (!value)
331  return emitError(loc, "hexadecimal float constant out of range for type");
332 
333  if (&semantics == &APFloat::IEEEdouble()) {
334  result = APFloat(semantics, APInt(typeSizeInBits, *value));
335  return success();
336  }
337 
338  APInt apInt(typeSizeInBits, *value);
339  if (apInt != *value)
340  return emitError(loc, "hexadecimal float constant out of range for type");
341  result = APFloat(semantics, apInt);
342 
343  return success();
344 }
345 
347  // Check that the current token is a keyword.
348  if (!isCurrentTokenAKeyword())
349  return failure();
350 
351  *keyword = getTokenSpelling();
352  consumeToken();
353  return success();
354 }
355 
356 //===----------------------------------------------------------------------===//
357 // Resource Parsing
358 
361  StringRef &name) {
362  assert(dialect && "expected valid dialect interface");
363  SMLoc nameLoc = getToken().getLoc();
364  if (failed(parseOptionalKeyword(&name)))
365  return emitError("expected identifier key for 'resource' entry");
366  auto &resources = getState().symbols.dialectResources;
367 
368  // If this is the first time encountering this handle, ask the dialect to
369  // resolve a reference to this handle. This allows for us to remap the name of
370  // the handle if necessary.
371  std::pair<std::string, AsmDialectResourceHandle> &entry =
372  resources[dialect][name];
373  if (entry.first.empty()) {
375  if (failed(result)) {
376  return emitError(nameLoc)
377  << "unknown 'resource' key '" << name << "' for dialect '"
378  << dialect->getDialect()->getNamespace() << "'";
379  }
380  entry.first = dialect->getResourceKey(*result);
381  entry.second = *result;
382  }
383 
384  name = entry.first;
385  return entry.second;
386 }
387 
390  const auto *interface = dyn_cast<OpAsmDialectInterface>(dialect);
391  if (!interface) {
392  return emitError() << "dialect '" << dialect->getNamespace()
393  << "' does not expect resource handles";
394  }
395  StringRef resourceName;
396  return parseResourceHandle(interface, resourceName);
397 }
398 
399 //===----------------------------------------------------------------------===//
400 // Code Completion
401 
404  return failure();
405 }
406 
408  // Perform some simple validation on the dialect name. This doesn't need to be
409  // extensive, it's more of an optimization (to avoid checking completion
410  // results when we know they will fail).
411  if (dialectName.empty() || dialectName.contains('.'))
412  return failure();
414  return failure();
415 }
416 
418  // Check to see if there is anything else on the current line. This check
419  // isn't strictly necessary, but it does avoid unnecessarily triggering
420  // completions for operations and dialects in situations where we don't want
421  // them (e.g. at the end of an operation).
422  auto shouldIgnoreOpCompletion = [&]() {
423  const char *bufBegin = state.lex.getBufferBegin();
424  const char *it = loc.getPointer() - 1;
425  for (; it > bufBegin && *it != '\n'; --it)
426  if (!StringRef(" \t\r").contains(*it))
427  return true;
428  return false;
429  };
430  if (shouldIgnoreOpCompletion())
431  return failure();
432 
433  // The completion here is either for a dialect name, or an operation name
434  // whose dialect prefix was elided. For this we simply invoke both of the
435  // individual completion methods.
436  (void)codeCompleteDialectName();
438 }
439 
441  // If the name is empty, this is the start of the string and contains the
442  // dialect.
443  if (name.empty())
444  return codeCompleteDialectName();
445 
446  // Otherwise, we treat this as completing an operation name. The current name
447  // is used as the dialect namespace.
448  if (name.consume_back("."))
449  return codeCompleteOperationName(name);
450  return failure();
451 }
452 
454  state.codeCompleteContext->completeExpectedTokens(tokens, /*optional=*/false);
455  return failure();
456 }
458  state.codeCompleteContext->completeExpectedTokens(tokens, /*optional=*/true);
459  return failure();
460 }
461 
465  return {};
466 }
469  return {};
470 }
471 
472 Attribute
473 Parser::codeCompleteDialectSymbol(const llvm::StringMap<Attribute> &aliases) {
475  return {};
476 }
477 Type Parser::codeCompleteDialectSymbol(const llvm::StringMap<Type> &aliases) {
479  return {};
480 }
481 
482 //===----------------------------------------------------------------------===//
483 // OperationParser
484 //===----------------------------------------------------------------------===//
485 
486 namespace {
487 /// This class provides support for parsing operations and regions of
488 /// operations.
489 class OperationParser : public Parser {
490 public:
491  OperationParser(ParserState &state, ModuleOp topLevelOp);
492  ~OperationParser();
493 
494  /// After parsing is finished, this function must be called to see if there
495  /// are any remaining issues.
496  ParseResult finalize();
497 
498  //===--------------------------------------------------------------------===//
499  // SSA Value Handling
500  //===--------------------------------------------------------------------===//
501 
502  using UnresolvedOperand = OpAsmParser::UnresolvedOperand;
503  using Argument = OpAsmParser::Argument;
504 
505  struct DeferredLocInfo {
506  SMLoc loc;
507  StringRef identifier;
508  };
509 
510  /// Push a new SSA name scope to the parser.
511  void pushSSANameScope(bool isIsolated);
512 
513  /// Pop the last SSA name scope from the parser.
514  ParseResult popSSANameScope();
515 
516  /// Register a definition of a value with the symbol table.
517  ParseResult addDefinition(UnresolvedOperand useInfo, Value value);
518 
519  /// Parse an optional list of SSA uses into 'results'.
521  parseOptionalSSAUseList(SmallVectorImpl<UnresolvedOperand> &results);
522 
523  /// Parse a single SSA use into 'result'. If 'allowResultNumber' is true then
524  /// we allow #42 syntax.
525  ParseResult parseSSAUse(UnresolvedOperand &result,
526  bool allowResultNumber = true);
527 
528  /// Given a reference to an SSA value and its type, return a reference. This
529  /// returns null on failure.
530  Value resolveSSAUse(UnresolvedOperand useInfo, Type type);
531 
532  ParseResult parseSSADefOrUseAndType(
533  function_ref<ParseResult(UnresolvedOperand, Type)> action);
534 
535  ParseResult parseOptionalSSAUseAndTypeList(SmallVectorImpl<Value> &results);
536 
537  /// Return the location of the value identified by its name and number if it
538  /// has been already reference.
539  std::optional<SMLoc> getReferenceLoc(StringRef name, unsigned number) {
540  auto &values = isolatedNameScopes.back().values;
541  if (!values.count(name) || number >= values[name].size())
542  return {};
543  if (values[name][number].value)
544  return values[name][number].loc;
545  return {};
546  }
547 
548  //===--------------------------------------------------------------------===//
549  // Operation Parsing
550  //===--------------------------------------------------------------------===//
551 
552  /// Parse an operation instance.
553  ParseResult parseOperation();
554 
555  /// Parse a single operation successor.
556  ParseResult parseSuccessor(Block *&dest);
557 
558  /// Parse a comma-separated list of operation successors in brackets.
559  ParseResult parseSuccessors(SmallVectorImpl<Block *> &destinations);
560 
561  /// Parse an operation instance that is in the generic form.
562  Operation *parseGenericOperation();
563 
564  /// Parse different components, viz., use-info of operand(s), successor(s),
565  /// region(s), attribute(s) and function-type, of the generic form of an
566  /// operation instance and populate the input operation-state 'result' with
567  /// those components. If any of the components is explicitly provided, then
568  /// skip parsing that component.
569  ParseResult parseGenericOperationAfterOpName(
570  OperationState &result,
571  std::optional<ArrayRef<UnresolvedOperand>> parsedOperandUseInfo =
572  std::nullopt,
573  std::optional<ArrayRef<Block *>> parsedSuccessors = std::nullopt,
574  std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions =
575  std::nullopt,
576  std::optional<ArrayRef<NamedAttribute>> parsedAttributes = std::nullopt,
577  std::optional<Attribute> propertiesAttribute = std::nullopt,
578  std::optional<FunctionType> parsedFnType = std::nullopt);
579 
580  /// Parse an operation instance that is in the generic form and insert it at
581  /// the provided insertion point.
582  Operation *parseGenericOperation(Block *insertBlock,
583  Block::iterator insertPt);
584 
585  /// This type is used to keep track of things that are either an Operation or
586  /// a BlockArgument. We cannot use Value for this, because not all Operations
587  /// have results.
589 
590  /// Parse an optional trailing location and add it to the specifier Operation
591  /// or `UnresolvedOperand` if present.
592  ///
593  /// trailing-location ::= (`loc` (`(` location `)` | attribute-alias))?
594  ///
595  ParseResult parseTrailingLocationSpecifier(OpOrArgument opOrArgument);
596 
597  /// Parse a location alias, that is a sequence looking like: #loc42
598  /// The alias may have already be defined or may be defined later, in which
599  /// case an OpaqueLoc is used a placeholder.
600  ParseResult parseLocationAlias(LocationAttr &loc);
601 
602  /// This is the structure of a result specifier in the assembly syntax,
603  /// including the name, number of results, and location.
604  using ResultRecord = std::tuple<StringRef, unsigned, SMLoc>;
605 
606  /// Parse an operation instance that is in the op-defined custom form.
607  /// resultInfo specifies information about the "%name =" specifiers.
608  Operation *parseCustomOperation(ArrayRef<ResultRecord> resultIDs);
609 
610  /// Parse the name of an operation, in the custom form. On success, return a
611  /// an object of type 'OperationName'. Otherwise, failure is returned.
612  FailureOr<OperationName> parseCustomOperationName();
613 
614  //===--------------------------------------------------------------------===//
615  // Region Parsing
616  //===--------------------------------------------------------------------===//
617 
618  /// Parse a region into 'region' with the provided entry block arguments.
619  /// 'isIsolatedNameScope' indicates if the naming scope of this region is
620  /// isolated from those above.
621  ParseResult parseRegion(Region &region, ArrayRef<Argument> entryArguments,
622  bool isIsolatedNameScope = false);
623 
624  /// Parse a region body into 'region'.
625  ParseResult parseRegionBody(Region &region, SMLoc startLoc,
626  ArrayRef<Argument> entryArguments,
627  bool isIsolatedNameScope);
628 
629  //===--------------------------------------------------------------------===//
630  // Block Parsing
631  //===--------------------------------------------------------------------===//
632 
633  /// Parse a new block into 'block'.
634  ParseResult parseBlock(Block *&block);
635 
636  /// Parse a list of operations into 'block'.
637  ParseResult parseBlockBody(Block *block);
638 
639  /// Parse a (possibly empty) list of block arguments.
640  ParseResult parseOptionalBlockArgList(Block *owner);
641 
642  /// Get the block with the specified name, creating it if it doesn't
643  /// already exist. The location specified is the point of use, which allows
644  /// us to diagnose references to blocks that are not defined precisely.
645  Block *getBlockNamed(StringRef name, SMLoc loc);
646 
647  //===--------------------------------------------------------------------===//
648  // Code Completion
649  //===--------------------------------------------------------------------===//
650 
651  /// The set of various code completion methods. Every completion method
652  /// returns `failure` to stop the parsing process after providing completion
653  /// results.
654 
655  ParseResult codeCompleteSSAUse();
656  ParseResult codeCompleteBlock();
657 
658 private:
659  /// This class represents a definition of a Block.
660  struct BlockDefinition {
661  /// A pointer to the defined Block.
662  Block *block;
663  /// The location that the Block was defined at.
664  SMLoc loc;
665  };
666  /// This class represents a definition of a Value.
667  struct ValueDefinition {
668  /// A pointer to the defined Value.
669  Value value;
670  /// The location that the Value was defined at.
671  SMLoc loc;
672  };
673 
674  /// Returns the info for a block at the current scope for the given name.
675  BlockDefinition &getBlockInfoByName(StringRef name) {
676  return blocksByName.back()[name];
677  }
678 
679  /// Insert a new forward reference to the given block.
680  void insertForwardRef(Block *block, SMLoc loc) {
681  forwardRef.back().try_emplace(block, loc);
682  }
683 
684  /// Erase any forward reference to the given block.
685  bool eraseForwardRef(Block *block) { return forwardRef.back().erase(block); }
686 
687  /// Record that a definition was added at the current scope.
688  void recordDefinition(StringRef def);
689 
690  /// Get the value entry for the given SSA name.
691  SmallVectorImpl<ValueDefinition> &getSSAValueEntry(StringRef name);
692 
693  /// Create a forward reference placeholder value with the given location and
694  /// result type.
695  Value createForwardRefPlaceholder(SMLoc loc, Type type);
696 
697  /// Return true if this is a forward reference.
698  bool isForwardRefPlaceholder(Value value) {
699  return forwardRefPlaceholders.count(value);
700  }
701 
702  /// This struct represents an isolated SSA name scope. This scope may contain
703  /// other nested non-isolated scopes. These scopes are used for operations
704  /// that are known to be isolated to allow for reusing names within their
705  /// regions, even if those names are used above.
706  struct IsolatedSSANameScope {
707  /// Record that a definition was added at the current scope.
708  void recordDefinition(StringRef def) {
709  definitionsPerScope.back().insert(def);
710  }
711 
712  /// Push a nested name scope.
713  void pushSSANameScope() { definitionsPerScope.push_back({}); }
714 
715  /// Pop a nested name scope.
716  void popSSANameScope() {
717  for (auto &def : definitionsPerScope.pop_back_val())
718  values.erase(def.getKey());
719  }
720 
721  /// This keeps track of all of the SSA values we are tracking for each name
722  /// scope, indexed by their name. This has one entry per result number.
723  llvm::StringMap<SmallVector<ValueDefinition, 1>> values;
724 
725  /// This keeps track of all of the values defined by a specific name scope.
726  SmallVector<llvm::StringSet<>, 2> definitionsPerScope;
727  };
728 
729  /// A list of isolated name scopes.
730  SmallVector<IsolatedSSANameScope, 2> isolatedNameScopes;
731 
732  /// This keeps track of the block names as well as the location of the first
733  /// reference for each nested name scope. This is used to diagnose invalid
734  /// block references and memorize them.
737 
738  /// These are all of the placeholders we've made along with the location of
739  /// their first reference, to allow checking for use of undefined values.
740  DenseMap<Value, SMLoc> forwardRefPlaceholders;
741 
742  /// Deffered locations: when parsing `loc(#loc42)` we add an entry to this
743  /// map. After parsing the definition `#loc42 = ...` we'll patch back users
744  /// of this location.
745  std::vector<DeferredLocInfo> deferredLocsReferences;
746 
747  /// The builder used when creating parsed operation instances.
748  OpBuilder opBuilder;
749 
750  /// The top level operation that holds all of the parsed operations.
751  Operation *topLevelOp;
752 };
753 } // namespace
754 
755 MLIR_DECLARE_EXPLICIT_TYPE_ID(OperationParser::DeferredLocInfo *)
756 MLIR_DEFINE_EXPLICIT_TYPE_ID(OperationParser::DeferredLocInfo *)
757 
758 OperationParser::OperationParser(ParserState &state, ModuleOp topLevelOp)
759  : Parser(state), opBuilder(topLevelOp.getRegion()), topLevelOp(topLevelOp) {
760  // The top level operation starts a new name scope.
761  pushSSANameScope(/*isIsolated=*/true);
762 
763  // If we are populating the parser state, prepare it for parsing.
764  if (state.asmState)
765  state.asmState->initialize(topLevelOp);
766 }
767 
768 OperationParser::~OperationParser() {
769  for (auto &fwd : forwardRefPlaceholders) {
770  // Drop all uses of undefined forward declared reference and destroy
771  // defining operation.
772  fwd.first.dropAllUses();
773  fwd.first.getDefiningOp()->destroy();
774  }
775  for (const auto &scope : forwardRef) {
776  for (const auto &fwd : scope) {
777  // Delete all blocks that were created as forward references but never
778  // included into a region.
779  fwd.first->dropAllUses();
780  delete fwd.first;
781  }
782  }
783 }
784 
785 /// After parsing is finished, this function must be called to see if there are
786 /// any remaining issues.
787 ParseResult OperationParser::finalize() {
788  // Check for any forward references that are left. If we find any, error
789  // out.
790  if (!forwardRefPlaceholders.empty()) {
792  // Iteration over the map isn't deterministic, so sort by source location.
793  for (auto entry : forwardRefPlaceholders)
794  errors.push_back(entry.second.getPointer());
795  llvm::array_pod_sort(errors.begin(), errors.end());
796 
797  for (const char *entry : errors) {
798  auto loc = SMLoc::getFromPointer(entry);
799  emitError(loc, "use of undeclared SSA value name");
800  }
801  return failure();
802  }
803 
804  // Resolve the locations of any deferred operations.
805  auto &attributeAliases = state.symbols.attributeAliasDefinitions;
806  auto locID = TypeID::get<DeferredLocInfo *>();
807  auto resolveLocation = [&, this](auto &opOrArgument) -> LogicalResult {
808  auto fwdLoc = dyn_cast<OpaqueLoc>(opOrArgument.getLoc());
809  if (!fwdLoc || fwdLoc.getUnderlyingTypeID() != locID)
810  return success();
811  auto locInfo = deferredLocsReferences[fwdLoc.getUnderlyingLocation()];
812  Attribute attr = attributeAliases.lookup(locInfo.identifier);
813  if (!attr)
814  return this->emitError(locInfo.loc)
815  << "operation location alias was never defined";
816  auto locAttr = dyn_cast<LocationAttr>(attr);
817  if (!locAttr)
818  return this->emitError(locInfo.loc)
819  << "expected location, but found '" << attr << "'";
820  opOrArgument.setLoc(locAttr);
821  return success();
822  };
823 
824  auto walkRes = topLevelOp->walk([&](Operation *op) {
825  if (failed(resolveLocation(*op)))
826  return WalkResult::interrupt();
827  for (Region &region : op->getRegions())
828  for (Block &block : region.getBlocks())
829  for (BlockArgument arg : block.getArguments())
830  if (failed(resolveLocation(arg)))
831  return WalkResult::interrupt();
832  return WalkResult::advance();
833  });
834  if (walkRes.wasInterrupted())
835  return failure();
836 
837  // Pop the top level name scope.
838  if (failed(popSSANameScope()))
839  return failure();
840 
841  // Verify that the parsed operations are valid.
842  if (state.config.shouldVerifyAfterParse() && failed(verify(topLevelOp)))
843  return failure();
844 
845  // If we are populating the parser state, finalize the top-level operation.
846  if (state.asmState)
847  state.asmState->finalize(topLevelOp);
848  return success();
849 }
850 
851 //===----------------------------------------------------------------------===//
852 // SSA Value Handling
853 //===----------------------------------------------------------------------===//
854 
855 void OperationParser::pushSSANameScope(bool isIsolated) {
856  blocksByName.push_back(DenseMap<StringRef, BlockDefinition>());
857  forwardRef.push_back(DenseMap<Block *, SMLoc>());
858 
859  // Push back a new name definition scope.
860  if (isIsolated)
861  isolatedNameScopes.push_back({});
862  isolatedNameScopes.back().pushSSANameScope();
863 }
864 
865 ParseResult OperationParser::popSSANameScope() {
866  auto forwardRefInCurrentScope = forwardRef.pop_back_val();
867 
868  // Verify that all referenced blocks were defined.
869  if (!forwardRefInCurrentScope.empty()) {
871  // Iteration over the map isn't deterministic, so sort by source location.
872  for (auto entry : forwardRefInCurrentScope) {
873  errors.push_back({entry.second.getPointer(), entry.first});
874  // Add this block to the top-level region to allow for automatic cleanup.
875  topLevelOp->getRegion(0).push_back(entry.first);
876  }
877  llvm::array_pod_sort(errors.begin(), errors.end());
878 
879  for (auto entry : errors) {
880  auto loc = SMLoc::getFromPointer(entry.first);
881  emitError(loc, "reference to an undefined block");
882  }
883  return failure();
884  }
885 
886  // Pop the next nested namescope. If there is only one internal namescope,
887  // just pop the isolated scope.
888  auto &currentNameScope = isolatedNameScopes.back();
889  if (currentNameScope.definitionsPerScope.size() == 1)
890  isolatedNameScopes.pop_back();
891  else
892  currentNameScope.popSSANameScope();
893 
894  blocksByName.pop_back();
895  return success();
896 }
897 
898 /// Register a definition of a value with the symbol table.
899 ParseResult OperationParser::addDefinition(UnresolvedOperand useInfo,
900  Value value) {
901  auto &entries = getSSAValueEntry(useInfo.name);
902 
903  // Make sure there is a slot for this value.
904  if (entries.size() <= useInfo.number)
905  entries.resize(useInfo.number + 1);
906 
907  // If we already have an entry for this, check to see if it was a definition
908  // or a forward reference.
909  if (auto existing = entries[useInfo.number].value) {
910  if (!isForwardRefPlaceholder(existing)) {
911  return emitError(useInfo.location)
912  .append("redefinition of SSA value '", useInfo.name, "'")
913  .attachNote(getEncodedSourceLocation(entries[useInfo.number].loc))
914  .append("previously defined here");
915  }
916 
917  if (existing.getType() != value.getType()) {
918  return emitError(useInfo.location)
919  .append("definition of SSA value '", useInfo.name, "#",
920  useInfo.number, "' has type ", value.getType())
921  .attachNote(getEncodedSourceLocation(entries[useInfo.number].loc))
922  .append("previously used here with type ", existing.getType());
923  }
924 
925  // If it was a forward reference, update everything that used it to use
926  // the actual definition instead, delete the forward ref, and remove it
927  // from our set of forward references we track.
928  existing.replaceAllUsesWith(value);
929  existing.getDefiningOp()->destroy();
930  forwardRefPlaceholders.erase(existing);
931 
932  // If a definition of the value already exists, replace it in the assembly
933  // state.
934  if (state.asmState)
935  state.asmState->refineDefinition(existing, value);
936  }
937 
938  /// Record this definition for the current scope.
939  entries[useInfo.number] = {value, useInfo.location};
940  recordDefinition(useInfo.name);
941  return success();
942 }
943 
944 /// Parse a (possibly empty) list of SSA operands.
945 ///
946 /// ssa-use-list ::= ssa-use (`,` ssa-use)*
947 /// ssa-use-list-opt ::= ssa-use-list?
948 ///
949 ParseResult OperationParser::parseOptionalSSAUseList(
951  if (!getToken().isOrIsCodeCompletionFor(Token::percent_identifier))
952  return success();
953  return parseCommaSeparatedList([&]() -> ParseResult {
954  UnresolvedOperand result;
955  if (parseSSAUse(result))
956  return failure();
957  results.push_back(result);
958  return success();
959  });
960 }
961 
962 /// Parse a SSA operand for an operation.
963 ///
964 /// ssa-use ::= ssa-id
965 ///
966 ParseResult OperationParser::parseSSAUse(UnresolvedOperand &result,
967  bool allowResultNumber) {
968  if (getToken().isCodeCompletion())
969  return codeCompleteSSAUse();
970 
971  result.name = getTokenSpelling();
972  result.number = 0;
973  result.location = getToken().getLoc();
974  if (parseToken(Token::percent_identifier, "expected SSA operand"))
975  return failure();
976 
977  // If we have an attribute ID, it is a result number.
978  if (getToken().is(Token::hash_identifier)) {
979  if (!allowResultNumber)
980  return emitError("result number not allowed in argument list");
981 
982  if (auto value = getToken().getHashIdentifierNumber())
983  result.number = *value;
984  else
985  return emitError("invalid SSA value result number");
986  consumeToken(Token::hash_identifier);
987  }
988 
989  return success();
990 }
991 
992 /// Given an unbound reference to an SSA value and its type, return the value
993 /// it specifies. This returns null on failure.
994 Value OperationParser::resolveSSAUse(UnresolvedOperand useInfo, Type type) {
995  auto &entries = getSSAValueEntry(useInfo.name);
996 
997  // Functor used to record the use of the given value if the assembly state
998  // field is populated.
999  auto maybeRecordUse = [&](Value value) {
1000  if (state.asmState)
1001  state.asmState->addUses(value, useInfo.location);
1002  return value;
1003  };
1004 
1005  // If we have already seen a value of this name, return it.
1006  if (useInfo.number < entries.size() && entries[useInfo.number].value) {
1007  Value result = entries[useInfo.number].value;
1008  // Check that the type matches the other uses.
1009  if (result.getType() == type)
1010  return maybeRecordUse(result);
1011 
1012  emitError(useInfo.location, "use of value '")
1013  .append(useInfo.name,
1014  "' expects different type than prior uses: ", type, " vs ",
1015  result.getType())
1016  .attachNote(getEncodedSourceLocation(entries[useInfo.number].loc))
1017  .append("prior use here");
1018  return nullptr;
1019  }
1020 
1021  // Make sure we have enough slots for this.
1022  if (entries.size() <= useInfo.number)
1023  entries.resize(useInfo.number + 1);
1024 
1025  // If the value has already been defined and this is an overly large result
1026  // number, diagnose that.
1027  if (entries[0].value && !isForwardRefPlaceholder(entries[0].value))
1028  return (emitError(useInfo.location, "reference to invalid result number"),
1029  nullptr);
1030 
1031  // Otherwise, this is a forward reference. Create a placeholder and remember
1032  // that we did so.
1033  Value result = createForwardRefPlaceholder(useInfo.location, type);
1034  entries[useInfo.number] = {result, useInfo.location};
1035  return maybeRecordUse(result);
1036 }
1037 
1038 /// Parse an SSA use with an associated type.
1039 ///
1040 /// ssa-use-and-type ::= ssa-use `:` type
1041 ParseResult OperationParser::parseSSADefOrUseAndType(
1042  function_ref<ParseResult(UnresolvedOperand, Type)> action) {
1043  UnresolvedOperand useInfo;
1044  if (parseSSAUse(useInfo) ||
1045  parseToken(Token::colon, "expected ':' and type for SSA operand"))
1046  return failure();
1047 
1048  auto type = parseType();
1049  if (!type)
1050  return failure();
1051 
1052  return action(useInfo, type);
1053 }
1054 
1055 /// Parse a (possibly empty) list of SSA operands, followed by a colon, then
1056 /// followed by a type list.
1057 ///
1058 /// ssa-use-and-type-list
1059 /// ::= ssa-use-list ':' type-list-no-parens
1060 ///
1061 ParseResult OperationParser::parseOptionalSSAUseAndTypeList(
1062  SmallVectorImpl<Value> &results) {
1064  if (parseOptionalSSAUseList(valueIDs))
1065  return failure();
1066 
1067  // If there were no operands, then there is no colon or type lists.
1068  if (valueIDs.empty())
1069  return success();
1070 
1071  SmallVector<Type, 4> types;
1072  if (parseToken(Token::colon, "expected ':' in operand list") ||
1073  parseTypeListNoParens(types))
1074  return failure();
1075 
1076  if (valueIDs.size() != types.size())
1077  return emitError("expected ")
1078  << valueIDs.size() << " types to match operand list";
1079 
1080  results.reserve(valueIDs.size());
1081  for (unsigned i = 0, e = valueIDs.size(); i != e; ++i) {
1082  if (auto value = resolveSSAUse(valueIDs[i], types[i]))
1083  results.push_back(value);
1084  else
1085  return failure();
1086  }
1087 
1088  return success();
1089 }
1090 
1091 /// Record that a definition was added at the current scope.
1092 void OperationParser::recordDefinition(StringRef def) {
1093  isolatedNameScopes.back().recordDefinition(def);
1094 }
1095 
1096 /// Get the value entry for the given SSA name.
1097 auto OperationParser::getSSAValueEntry(StringRef name)
1099  return isolatedNameScopes.back().values[name];
1100 }
1101 
1102 /// Create and remember a new placeholder for a forward reference.
1103 Value OperationParser::createForwardRefPlaceholder(SMLoc loc, Type type) {
1104  // Forward references are always created as operations, because we just need
1105  // something with a def/use chain.
1106  //
1107  // We create these placeholders as having an empty name, which we know
1108  // cannot be created through normal user input, allowing us to distinguish
1109  // them.
1110  auto name = OperationName("builtin.unrealized_conversion_cast", getContext());
1111  auto *op = Operation::create(
1112  getEncodedSourceLocation(loc), name, type, /*operands=*/{},
1113  /*attributes=*/std::nullopt, /*properties=*/nullptr, /*successors=*/{},
1114  /*numRegions=*/0);
1115  forwardRefPlaceholders[op->getResult(0)] = loc;
1116  return op->getResult(0);
1117 }
1118 
1119 //===----------------------------------------------------------------------===//
1120 // Operation Parsing
1121 //===----------------------------------------------------------------------===//
1122 
1123 /// Parse an operation.
1124 ///
1125 /// operation ::= op-result-list?
1126 /// (generic-operation | custom-operation)
1127 /// trailing-location?
1128 /// generic-operation ::= string-literal `(` ssa-use-list? `)`
1129 /// successor-list? (`(` region-list `)`)?
1130 /// attribute-dict? `:` function-type
1131 /// custom-operation ::= bare-id custom-operation-format
1132 /// op-result-list ::= op-result (`,` op-result)* `=`
1133 /// op-result ::= ssa-id (`:` integer-literal)
1134 ///
1135 ParseResult OperationParser::parseOperation() {
1136  auto loc = getToken().getLoc();
1137  SmallVector<ResultRecord, 1> resultIDs;
1138  size_t numExpectedResults = 0;
1139  if (getToken().is(Token::percent_identifier)) {
1140  // Parse the group of result ids.
1141  auto parseNextResult = [&]() -> ParseResult {
1142  // Parse the next result id.
1143  Token nameTok = getToken();
1144  if (parseToken(Token::percent_identifier,
1145  "expected valid ssa identifier"))
1146  return failure();
1147 
1148  // If the next token is a ':', we parse the expected result count.
1149  size_t expectedSubResults = 1;
1150  if (consumeIf(Token::colon)) {
1151  // Check that the next token is an integer.
1152  if (!getToken().is(Token::integer))
1153  return emitWrongTokenError("expected integer number of results");
1154 
1155  // Check that number of results is > 0.
1156  auto val = getToken().getUInt64IntegerValue();
1157  if (!val || *val < 1)
1158  return emitError(
1159  "expected named operation to have at least 1 result");
1160  consumeToken(Token::integer);
1161  expectedSubResults = *val;
1162  }
1163 
1164  resultIDs.emplace_back(nameTok.getSpelling(), expectedSubResults,
1165  nameTok.getLoc());
1166  numExpectedResults += expectedSubResults;
1167  return success();
1168  };
1169  if (parseCommaSeparatedList(parseNextResult))
1170  return failure();
1171 
1172  if (parseToken(Token::equal, "expected '=' after SSA name"))
1173  return failure();
1174  }
1175 
1176  Operation *op;
1177  Token nameTok = getToken();
1178  if (nameTok.is(Token::bare_identifier) || nameTok.isKeyword())
1179  op = parseCustomOperation(resultIDs);
1180  else if (nameTok.is(Token::string))
1181  op = parseGenericOperation();
1182  else if (nameTok.isCodeCompletionFor(Token::string))
1183  return codeCompleteStringDialectOrOperationName(nameTok.getStringValue());
1184  else if (nameTok.isCodeCompletion())
1185  return codeCompleteDialectOrElidedOpName(loc);
1186  else
1187  return emitWrongTokenError("expected operation name in quotes");
1188 
1189  // If parsing of the basic operation failed, then this whole thing fails.
1190  if (!op)
1191  return failure();
1192 
1193  // If the operation had a name, register it.
1194  if (!resultIDs.empty()) {
1195  if (op->getNumResults() == 0)
1196  return emitError(loc, "cannot name an operation with no results");
1197  if (numExpectedResults != op->getNumResults())
1198  return emitError(loc, "operation defines ")
1199  << op->getNumResults() << " results but was provided "
1200  << numExpectedResults << " to bind";
1201 
1202  // Add this operation to the assembly state if it was provided to populate.
1203  if (state.asmState) {
1204  unsigned resultIt = 0;
1205  SmallVector<std::pair<unsigned, SMLoc>> asmResultGroups;
1206  asmResultGroups.reserve(resultIDs.size());
1207  for (ResultRecord &record : resultIDs) {
1208  asmResultGroups.emplace_back(resultIt, std::get<2>(record));
1209  resultIt += std::get<1>(record);
1210  }
1211  state.asmState->finalizeOperationDefinition(
1212  op, nameTok.getLocRange(), /*endLoc=*/getToken().getLoc(),
1213  asmResultGroups);
1214  }
1215 
1216  // Add definitions for each of the result groups.
1217  unsigned opResI = 0;
1218  for (ResultRecord &resIt : resultIDs) {
1219  for (unsigned subRes : llvm::seq<unsigned>(0, std::get<1>(resIt))) {
1220  if (addDefinition({std::get<2>(resIt), std::get<0>(resIt), subRes},
1221  op->getResult(opResI++)))
1222  return failure();
1223  }
1224  }
1225 
1226  // Add this operation to the assembly state if it was provided to populate.
1227  } else if (state.asmState) {
1228  state.asmState->finalizeOperationDefinition(op, nameTok.getLocRange(),
1229  /*endLoc=*/getToken().getLoc());
1230  }
1231 
1232  return success();
1233 }
1234 
1235 /// Parse a single operation successor.
1236 ///
1237 /// successor ::= block-id
1238 ///
1239 ParseResult OperationParser::parseSuccessor(Block *&dest) {
1240  if (getToken().isCodeCompletion())
1241  return codeCompleteBlock();
1242 
1243  // Verify branch is identifier and get the matching block.
1244  if (!getToken().is(Token::caret_identifier))
1245  return emitWrongTokenError("expected block name");
1246  dest = getBlockNamed(getTokenSpelling(), getToken().getLoc());
1247  consumeToken();
1248  return success();
1249 }
1250 
1251 /// Parse a comma-separated list of operation successors in brackets.
1252 ///
1253 /// successor-list ::= `[` successor (`,` successor )* `]`
1254 ///
1256 OperationParser::parseSuccessors(SmallVectorImpl<Block *> &destinations) {
1257  if (parseToken(Token::l_square, "expected '['"))
1258  return failure();
1259 
1260  auto parseElt = [this, &destinations] {
1261  Block *dest;
1262  ParseResult res = parseSuccessor(dest);
1263  destinations.push_back(dest);
1264  return res;
1265  };
1266  return parseCommaSeparatedListUntil(Token::r_square, parseElt,
1267  /*allowEmptyList=*/false);
1268 }
1269 
1270 namespace {
1271 // RAII-style guard for cleaning up the regions in the operation state before
1272 // deleting them. Within the parser, regions may get deleted if parsing failed,
1273 // and other errors may be present, in particular undominated uses. This makes
1274 // sure such uses are deleted.
1275 struct CleanupOpStateRegions {
1276  ~CleanupOpStateRegions() {
1277  SmallVector<Region *, 4> regionsToClean;
1278  regionsToClean.reserve(state.regions.size());
1279  for (auto &region : state.regions)
1280  if (region)
1281  for (auto &block : *region)
1282  block.dropAllDefinedValueUses();
1283  }
1284  OperationState &state;
1285 };
1286 } // namespace
1287 
1288 ParseResult OperationParser::parseGenericOperationAfterOpName(
1289  OperationState &result,
1290  std::optional<ArrayRef<UnresolvedOperand>> parsedOperandUseInfo,
1291  std::optional<ArrayRef<Block *>> parsedSuccessors,
1292  std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
1293  std::optional<ArrayRef<NamedAttribute>> parsedAttributes,
1294  std::optional<Attribute> propertiesAttribute,
1295  std::optional<FunctionType> parsedFnType) {
1296 
1297  // Parse the operand list, if not explicitly provided.
1299  if (!parsedOperandUseInfo) {
1300  if (parseToken(Token::l_paren, "expected '(' to start operand list") ||
1301  parseOptionalSSAUseList(opInfo) ||
1302  parseToken(Token::r_paren, "expected ')' to end operand list")) {
1303  return failure();
1304  }
1305  parsedOperandUseInfo = opInfo;
1306  }
1307 
1308  // Parse the successor list, if not explicitly provided.
1309  if (!parsedSuccessors) {
1310  if (getToken().is(Token::l_square)) {
1311  // Check if the operation is not a known terminator.
1312  if (!result.name.mightHaveTrait<OpTrait::IsTerminator>())
1313  return emitError("successors in non-terminator");
1314 
1315  SmallVector<Block *, 2> successors;
1316  if (parseSuccessors(successors))
1317  return failure();
1318  result.addSuccessors(successors);
1319  }
1320  } else {
1321  result.addSuccessors(*parsedSuccessors);
1322  }
1323 
1324  // Parse the properties, if not explicitly provided.
1325  if (propertiesAttribute) {
1326  result.propertiesAttr = *propertiesAttribute;
1327  } else if (consumeIf(Token::less)) {
1328  result.propertiesAttr = parseAttribute();
1329  if (!result.propertiesAttr)
1330  return failure();
1331  if (parseToken(Token::greater, "expected '>' to close properties"))
1332  return failure();
1333  }
1334  // Parse the region list, if not explicitly provided.
1335  if (!parsedRegions) {
1336  if (consumeIf(Token::l_paren)) {
1337  do {
1338  // Create temporary regions with the top level region as parent.
1339  result.regions.emplace_back(new Region(topLevelOp));
1340  if (parseRegion(*result.regions.back(), /*entryArguments=*/{}))
1341  return failure();
1342  } while (consumeIf(Token::comma));
1343  if (parseToken(Token::r_paren, "expected ')' to end region list"))
1344  return failure();
1345  }
1346  } else {
1347  result.addRegions(*parsedRegions);
1348  }
1349 
1350  // Parse the attributes, if not explicitly provided.
1351  if (!parsedAttributes) {
1352  if (getToken().is(Token::l_brace)) {
1353  if (parseAttributeDict(result.attributes))
1354  return failure();
1355  }
1356  } else {
1357  result.addAttributes(*parsedAttributes);
1358  }
1359 
1360  // Parse the operation type, if not explicitly provided.
1361  Location typeLoc = result.location;
1362  if (!parsedFnType) {
1363  if (parseToken(Token::colon, "expected ':' followed by operation type"))
1364  return failure();
1365 
1366  typeLoc = getEncodedSourceLocation(getToken().getLoc());
1367  auto type = parseType();
1368  if (!type)
1369  return failure();
1370  auto fnType = dyn_cast<FunctionType>(type);
1371  if (!fnType)
1372  return mlir::emitError(typeLoc, "expected function type");
1373 
1374  parsedFnType = fnType;
1375  }
1376 
1377  result.addTypes(parsedFnType->getResults());
1378 
1379  // Check that we have the right number of types for the operands.
1380  ArrayRef<Type> operandTypes = parsedFnType->getInputs();
1381  if (operandTypes.size() != parsedOperandUseInfo->size()) {
1382  auto plural = "s"[parsedOperandUseInfo->size() == 1];
1383  return mlir::emitError(typeLoc, "expected ")
1384  << parsedOperandUseInfo->size() << " operand type" << plural
1385  << " but had " << operandTypes.size();
1386  }
1387 
1388  // Resolve all of the operands.
1389  for (unsigned i = 0, e = parsedOperandUseInfo->size(); i != e; ++i) {
1390  result.operands.push_back(
1391  resolveSSAUse((*parsedOperandUseInfo)[i], operandTypes[i]));
1392  if (!result.operands.back())
1393  return failure();
1394  }
1395 
1396  return success();
1397 }
1398 
1399 Operation *OperationParser::parseGenericOperation() {
1400  // Get location information for the operation.
1401  auto srcLocation = getEncodedSourceLocation(getToken().getLoc());
1402 
1403  std::string name = getToken().getStringValue();
1404  if (name.empty())
1405  return (emitError("empty operation name is invalid"), nullptr);
1406  if (name.find('\0') != StringRef::npos)
1407  return (emitError("null character not allowed in operation name"), nullptr);
1408 
1409  consumeToken(Token::string);
1410 
1411  OperationState result(srcLocation, name);
1412  CleanupOpStateRegions guard{result};
1413 
1414  // Lazy load dialects in the context as needed.
1415  if (!result.name.isRegistered()) {
1416  StringRef dialectName = StringRef(name).split('.').first;
1417  if (!getContext()->getLoadedDialect(dialectName) &&
1418  !getContext()->getOrLoadDialect(dialectName)) {
1419  if (!getContext()->allowsUnregisteredDialects()) {
1420  // Emit an error if the dialect couldn't be loaded (i.e., it was not
1421  // registered) and unregistered dialects aren't allowed.
1422  emitError("operation being parsed with an unregistered dialect. If "
1423  "this is intended, please use -allow-unregistered-dialect "
1424  "with the MLIR tool used");
1425  return nullptr;
1426  }
1427  } else {
1428  // Reload the OperationName now that the dialect is loaded.
1429  result.name = OperationName(name, getContext());
1430  }
1431  }
1432 
1433  // If we are populating the parser state, start a new operation definition.
1434  if (state.asmState)
1435  state.asmState->startOperationDefinition(result.name);
1436 
1437  if (parseGenericOperationAfterOpName(result))
1438  return nullptr;
1439 
1440  // Operation::create() is not allowed to fail, however setting the properties
1441  // from an attribute is a failable operation. So we save the attribute here
1442  // and set it on the operation post-parsing.
1443  Attribute properties;
1444  std::swap(properties, result.propertiesAttr);
1445 
1446  // If we don't have properties in the textual IR, but the operation now has
1447  // support for properties, we support some backward-compatible generic syntax
1448  // for the operation and as such we accept inherent attributes mixed in the
1449  // dictionary of discardable attributes. We pre-validate these here because
1450  // invalid attributes can't be casted to the properties storage and will be
1451  // silently dropped. For example an attribute { foo = 0 : i32 } that is
1452  // declared as F32Attr in ODS would have a C++ type of FloatAttr in the
1453  // properties array. When setting it we would do something like:
1454  //
1455  // properties.foo = dyn_cast<FloatAttr>(fooAttr);
1456  //
1457  // which would end up with a null Attribute. The diagnostic from the verifier
1458  // would be "missing foo attribute" instead of something like "expects a 32
1459  // bits float attribute but got a 32 bits integer attribute".
1460  if (!properties && !result.getRawProperties()) {
1461  std::optional<RegisteredOperationName> info =
1462  result.name.getRegisteredInfo();
1463  if (info) {
1464  if (failed(info->verifyInherentAttrs(result.attributes, [&]() {
1465  return mlir::emitError(srcLocation) << "'" << name << "' op ";
1466  })))
1467  return nullptr;
1468  }
1469  }
1470 
1471  // Create the operation and try to parse a location for it.
1472  Operation *op = opBuilder.create(result);
1473  if (parseTrailingLocationSpecifier(op))
1474  return nullptr;
1475 
1476  // Try setting the properties for the operation, using a diagnostic to print
1477  // errors.
1478  if (properties) {
1479  auto emitError = [&]() {
1480  return mlir::emitError(srcLocation, "invalid properties ")
1481  << properties << " for op " << name << ": ";
1482  };
1483  if (failed(op->setPropertiesFromAttribute(properties, emitError)))
1484  return nullptr;
1485  }
1486 
1487  return op;
1488 }
1489 
1490 Operation *OperationParser::parseGenericOperation(Block *insertBlock,
1491  Block::iterator insertPt) {
1492  Token nameToken = getToken();
1493 
1494  OpBuilder::InsertionGuard restoreInsertionPoint(opBuilder);
1495  opBuilder.setInsertionPoint(insertBlock, insertPt);
1496  Operation *op = parseGenericOperation();
1497  if (!op)
1498  return nullptr;
1499 
1500  // If we are populating the parser asm state, finalize this operation
1501  // definition.
1502  if (state.asmState)
1503  state.asmState->finalizeOperationDefinition(op, nameToken.getLocRange(),
1504  /*endLoc=*/getToken().getLoc());
1505  return op;
1506 }
1507 
1508 namespace {
1509 class CustomOpAsmParser : public AsmParserImpl<OpAsmParser> {
1510 public:
1511  CustomOpAsmParser(
1512  SMLoc nameLoc, ArrayRef<OperationParser::ResultRecord> resultIDs,
1513  function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly,
1514  bool isIsolatedFromAbove, StringRef opName, OperationParser &parser)
1515  : AsmParserImpl<OpAsmParser>(nameLoc, parser), resultIDs(resultIDs),
1516  parseAssembly(parseAssembly), isIsolatedFromAbove(isIsolatedFromAbove),
1517  opName(opName), parser(parser) {
1518  (void)isIsolatedFromAbove; // Only used in assert, silence unused warning.
1519  }
1520 
1521  /// Parse an instance of the operation described by 'opDefinition' into the
1522  /// provided operation state.
1523  ParseResult parseOperation(OperationState &opState) {
1524  if (parseAssembly(*this, opState))
1525  return failure();
1526  // Verify that the parsed attributes does not have duplicate attributes.
1527  // This can happen if an attribute set during parsing is also specified in
1528  // the attribute dictionary in the assembly, or the attribute is set
1529  // multiple during parsing.
1530  std::optional<NamedAttribute> duplicate =
1531  opState.attributes.findDuplicate();
1532  if (duplicate)
1533  return emitError(getNameLoc(), "attribute '")
1534  << duplicate->getName().getValue()
1535  << "' occurs more than once in the attribute list";
1536  return success();
1537  }
1538 
1539  Operation *parseGenericOperation(Block *insertBlock,
1540  Block::iterator insertPt) final {
1541  return parser.parseGenericOperation(insertBlock, insertPt);
1542  }
1543 
1544  FailureOr<OperationName> parseCustomOperationName() final {
1545  return parser.parseCustomOperationName();
1546  }
1547 
1548  ParseResult parseGenericOperationAfterOpName(
1549  OperationState &result,
1550  std::optional<ArrayRef<UnresolvedOperand>> parsedUnresolvedOperands,
1551  std::optional<ArrayRef<Block *>> parsedSuccessors,
1552  std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
1553  std::optional<ArrayRef<NamedAttribute>> parsedAttributes,
1554  std::optional<Attribute> parsedPropertiesAttribute,
1555  std::optional<FunctionType> parsedFnType) final {
1556  return parser.parseGenericOperationAfterOpName(
1557  result, parsedUnresolvedOperands, parsedSuccessors, parsedRegions,
1558  parsedAttributes, parsedPropertiesAttribute, parsedFnType);
1559  }
1560  //===--------------------------------------------------------------------===//
1561  // Utilities
1562  //===--------------------------------------------------------------------===//
1563 
1564  /// Return the name of the specified result in the specified syntax, as well
1565  /// as the subelement in the name. For example, in this operation:
1566  ///
1567  /// %x, %y:2, %z = foo.op
1568  ///
1569  /// getResultName(0) == {"x", 0 }
1570  /// getResultName(1) == {"y", 0 }
1571  /// getResultName(2) == {"y", 1 }
1572  /// getResultName(3) == {"z", 0 }
1573  std::pair<StringRef, unsigned>
1574  getResultName(unsigned resultNo) const override {
1575  // Scan for the resultID that contains this result number.
1576  for (const auto &entry : resultIDs) {
1577  if (resultNo < std::get<1>(entry)) {
1578  // Don't pass on the leading %.
1579  StringRef name = std::get<0>(entry).drop_front();
1580  return {name, resultNo};
1581  }
1582  resultNo -= std::get<1>(entry);
1583  }
1584 
1585  // Invalid result number.
1586  return {"", ~0U};
1587  }
1588 
1589  /// Return the number of declared SSA results. This returns 4 for the foo.op
1590  /// example in the comment for getResultName.
1591  size_t getNumResults() const override {
1592  size_t count = 0;
1593  for (auto &entry : resultIDs)
1594  count += std::get<1>(entry);
1595  return count;
1596  }
1597 
1598  /// Emit a diagnostic at the specified location and return failure.
1599  InFlightDiagnostic emitError(SMLoc loc, const Twine &message) override {
1600  return AsmParserImpl<OpAsmParser>::emitError(loc, "custom op '" + opName +
1601  "' " + message);
1602  }
1603 
1604  //===--------------------------------------------------------------------===//
1605  // Operand Parsing
1606  //===--------------------------------------------------------------------===//
1607 
1608  /// Parse a single operand.
1609  ParseResult parseOperand(UnresolvedOperand &result,
1610  bool allowResultNumber = true) override {
1612  if (parser.parseSSAUse(useInfo, allowResultNumber))
1613  return failure();
1614 
1615  result = {useInfo.location, useInfo.name, useInfo.number};
1616  return success();
1617  }
1618 
1619  /// Parse a single operand if present.
1621  parseOptionalOperand(UnresolvedOperand &result,
1622  bool allowResultNumber = true) override {
1623  if (parser.getToken().isOrIsCodeCompletionFor(Token::percent_identifier))
1624  return parseOperand(result, allowResultNumber);
1625  return std::nullopt;
1626  }
1627 
1628  /// Parse zero or more SSA comma-separated operand references with a specified
1629  /// surrounding delimiter, and an optional required operand count.
1630  ParseResult parseOperandList(SmallVectorImpl<UnresolvedOperand> &result,
1631  Delimiter delimiter = Delimiter::None,
1632  bool allowResultNumber = true,
1633  int requiredOperandCount = -1) override {
1634  // The no-delimiter case has some special handling for better diagnostics.
1635  if (delimiter == Delimiter::None) {
1636  // parseCommaSeparatedList doesn't handle the missing case for "none",
1637  // so we handle it custom here.
1638  Token tok = parser.getToken();
1639  if (!tok.isOrIsCodeCompletionFor(Token::percent_identifier)) {
1640  // If we didn't require any operands or required exactly zero (weird)
1641  // then this is success.
1642  if (requiredOperandCount == -1 || requiredOperandCount == 0)
1643  return success();
1644 
1645  // Otherwise, try to produce a nice error message.
1646  if (tok.isAny(Token::l_paren, Token::l_square))
1647  return parser.emitError("unexpected delimiter");
1648  return parser.emitWrongTokenError("expected operand");
1649  }
1650  }
1651 
1652  auto parseOneOperand = [&]() -> ParseResult {
1653  return parseOperand(result.emplace_back(), allowResultNumber);
1654  };
1655 
1656  auto startLoc = parser.getToken().getLoc();
1657  if (parseCommaSeparatedList(delimiter, parseOneOperand, " in operand list"))
1658  return failure();
1659 
1660  // Check that we got the expected # of elements.
1661  if (requiredOperandCount != -1 &&
1662  result.size() != static_cast<size_t>(requiredOperandCount))
1663  return emitError(startLoc, "expected ")
1664  << requiredOperandCount << " operands";
1665  return success();
1666  }
1667 
1668  /// Resolve an operand to an SSA value, emitting an error on failure.
1669  ParseResult resolveOperand(const UnresolvedOperand &operand, Type type,
1670  SmallVectorImpl<Value> &result) override {
1671  if (auto value = parser.resolveSSAUse(operand, type)) {
1672  result.push_back(value);
1673  return success();
1674  }
1675  return failure();
1676  }
1677 
1678  /// Parse an AffineMap of SSA ids.
1679  ParseResult
1680  parseAffineMapOfSSAIds(SmallVectorImpl<UnresolvedOperand> &operands,
1681  Attribute &mapAttr, StringRef attrName,
1682  NamedAttrList &attrs, Delimiter delimiter) override {
1685 
1686  auto parseElement = [&](bool isSymbol) -> ParseResult {
1687  UnresolvedOperand operand;
1688  if (parseOperand(operand))
1689  return failure();
1690  if (isSymbol)
1691  symOperands.push_back(operand);
1692  else
1693  dimOperands.push_back(operand);
1694  return success();
1695  };
1696 
1697  AffineMap map;
1698  if (parser.parseAffineMapOfSSAIds(map, parseElement, delimiter))
1699  return failure();
1700  // Add AffineMap attribute.
1701  if (map) {
1702  mapAttr = AffineMapAttr::get(map);
1703  attrs.push_back(parser.builder.getNamedAttr(attrName, mapAttr));
1704  }
1705 
1706  // Add dim operands before symbol operands in 'operands'.
1707  operands.assign(dimOperands.begin(), dimOperands.end());
1708  operands.append(symOperands.begin(), symOperands.end());
1709  return success();
1710  }
1711 
1712  /// Parse an AffineExpr of SSA ids.
1713  ParseResult
1714  parseAffineExprOfSSAIds(SmallVectorImpl<UnresolvedOperand> &dimOperands,
1715  SmallVectorImpl<UnresolvedOperand> &symbOperands,
1716  AffineExpr &expr) override {
1717  auto parseElement = [&](bool isSymbol) -> ParseResult {
1718  UnresolvedOperand operand;
1719  if (parseOperand(operand))
1720  return failure();
1721  if (isSymbol)
1722  symbOperands.push_back(operand);
1723  else
1724  dimOperands.push_back(operand);
1725  return success();
1726  };
1727 
1728  return parser.parseAffineExprOfSSAIds(expr, parseElement);
1729  }
1730 
1731  //===--------------------------------------------------------------------===//
1732  // Argument Parsing
1733  //===--------------------------------------------------------------------===//
1734 
1735  /// Parse a single argument with the following syntax:
1736  ///
1737  /// `%ssaname : !type { optionalAttrDict} loc(optionalSourceLoc)`
1738  ///
1739  /// If `allowType` is false or `allowAttrs` are false then the respective
1740  /// parts of the grammar are not parsed.
1741  ParseResult parseArgument(Argument &result, bool allowType = false,
1742  bool allowAttrs = false) override {
1743  NamedAttrList attrs;
1744  if (parseOperand(result.ssaName, /*allowResultNumber=*/false) ||
1745  (allowType && parseColonType(result.type)) ||
1746  (allowAttrs && parseOptionalAttrDict(attrs)) ||
1747  parseOptionalLocationSpecifier(result.sourceLoc))
1748  return failure();
1749  result.attrs = attrs.getDictionary(getContext());
1750  return success();
1751  }
1752 
1753  /// Parse a single argument if present.
1754  OptionalParseResult parseOptionalArgument(Argument &result, bool allowType,
1755  bool allowAttrs) override {
1756  if (parser.getToken().is(Token::percent_identifier))
1757  return parseArgument(result, allowType, allowAttrs);
1758  return std::nullopt;
1759  }
1760 
1761  ParseResult parseArgumentList(SmallVectorImpl<Argument> &result,
1762  Delimiter delimiter, bool allowType,
1763  bool allowAttrs) override {
1764  // The no-delimiter case has some special handling for the empty case.
1765  if (delimiter == Delimiter::None &&
1766  parser.getToken().isNot(Token::percent_identifier))
1767  return success();
1768 
1769  auto parseOneArgument = [&]() -> ParseResult {
1770  return parseArgument(result.emplace_back(), allowType, allowAttrs);
1771  };
1772  return parseCommaSeparatedList(delimiter, parseOneArgument,
1773  " in argument list");
1774  }
1775 
1776  //===--------------------------------------------------------------------===//
1777  // Region Parsing
1778  //===--------------------------------------------------------------------===//
1779 
1780  /// Parse a region that takes `arguments` of `argTypes` types. This
1781  /// effectively defines the SSA values of `arguments` and assigns their type.
1782  ParseResult parseRegion(Region &region, ArrayRef<Argument> arguments,
1783  bool enableNameShadowing) override {
1784  // Try to parse the region.
1785  (void)isIsolatedFromAbove;
1786  assert((!enableNameShadowing || isIsolatedFromAbove) &&
1787  "name shadowing is only allowed on isolated regions");
1788  if (parser.parseRegion(region, arguments, enableNameShadowing))
1789  return failure();
1790  return success();
1791  }
1792 
1793  /// Parses a region if present.
1794  OptionalParseResult parseOptionalRegion(Region &region,
1795  ArrayRef<Argument> arguments,
1796  bool enableNameShadowing) override {
1797  if (parser.getToken().isNot(Token::l_brace))
1798  return std::nullopt;
1799  return parseRegion(region, arguments, enableNameShadowing);
1800  }
1801 
1802  /// Parses a region if present. If the region is present, a new region is
1803  /// allocated and placed in `region`. If no region is present, `region`
1804  /// remains untouched.
1806  parseOptionalRegion(std::unique_ptr<Region> &region,
1807  ArrayRef<Argument> arguments,
1808  bool enableNameShadowing = false) override {
1809  if (parser.getToken().isNot(Token::l_brace))
1810  return std::nullopt;
1811  std::unique_ptr<Region> newRegion = std::make_unique<Region>();
1812  if (parseRegion(*newRegion, arguments, enableNameShadowing))
1813  return failure();
1814 
1815  region = std::move(newRegion);
1816  return success();
1817  }
1818 
1819  //===--------------------------------------------------------------------===//
1820  // Successor Parsing
1821  //===--------------------------------------------------------------------===//
1822 
1823  /// Parse a single operation successor.
1824  ParseResult parseSuccessor(Block *&dest) override {
1825  return parser.parseSuccessor(dest);
1826  }
1827 
1828  /// Parse an optional operation successor and its operand list.
1829  OptionalParseResult parseOptionalSuccessor(Block *&dest) override {
1830  if (!parser.getToken().isOrIsCodeCompletionFor(Token::caret_identifier))
1831  return std::nullopt;
1832  return parseSuccessor(dest);
1833  }
1834 
1835  /// Parse a single operation successor and its operand list.
1836  ParseResult
1837  parseSuccessorAndUseList(Block *&dest,
1838  SmallVectorImpl<Value> &operands) override {
1839  if (parseSuccessor(dest))
1840  return failure();
1841 
1842  // Handle optional arguments.
1843  if (succeeded(parseOptionalLParen()) &&
1844  (parser.parseOptionalSSAUseAndTypeList(operands) || parseRParen())) {
1845  return failure();
1846  }
1847  return success();
1848  }
1849 
1850  //===--------------------------------------------------------------------===//
1851  // Type Parsing
1852  //===--------------------------------------------------------------------===//
1853 
1854  /// Parse a list of assignments of the form
1855  /// (%x1 = %y1, %x2 = %y2, ...).
1856  OptionalParseResult parseOptionalAssignmentList(
1858  SmallVectorImpl<UnresolvedOperand> &rhs) override {
1859  if (failed(parseOptionalLParen()))
1860  return std::nullopt;
1861 
1862  auto parseElt = [&]() -> ParseResult {
1863  if (parseArgument(lhs.emplace_back()) || parseEqual() ||
1864  parseOperand(rhs.emplace_back()))
1865  return failure();
1866  return success();
1867  };
1868  return parser.parseCommaSeparatedListUntil(Token::r_paren, parseElt);
1869  }
1870 
1871  /// Parse a loc(...) specifier if present, filling in result if so.
1872  ParseResult
1873  parseOptionalLocationSpecifier(std::optional<Location> &result) override {
1874  // If there is a 'loc' we parse a trailing location.
1875  if (!parser.consumeIf(Token::kw_loc))
1876  return success();
1877  LocationAttr directLoc;
1878  if (parser.parseToken(Token::l_paren, "expected '(' in location"))
1879  return failure();
1880 
1881  Token tok = parser.getToken();
1882 
1883  // Check to see if we are parsing a location alias.
1884  // Otherwise, we parse the location directly.
1885  if (tok.is(Token::hash_identifier)) {
1886  if (parser.parseLocationAlias(directLoc))
1887  return failure();
1888  } else if (parser.parseLocationInstance(directLoc)) {
1889  return failure();
1890  }
1891 
1892  if (parser.parseToken(Token::r_paren, "expected ')' in location"))
1893  return failure();
1894 
1895  result = directLoc;
1896  return success();
1897  }
1898 
1899 private:
1900  /// Information about the result name specifiers.
1902 
1903  /// The abstract information of the operation.
1904  function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly;
1905  bool isIsolatedFromAbove;
1906  StringRef opName;
1907 
1908  /// The backing operation parser.
1909  OperationParser &parser;
1910 };
1911 } // namespace
1912 
1913 FailureOr<OperationName> OperationParser::parseCustomOperationName() {
1914  Token nameTok = getToken();
1915  StringRef opName = nameTok.getSpelling();
1916  if (opName.empty())
1917  return (emitError("empty operation name is invalid"), failure());
1918  consumeToken();
1919 
1920  // Check to see if this operation name is already registered.
1921  std::optional<RegisteredOperationName> opInfo =
1923  if (opInfo)
1924  return *opInfo;
1925 
1926  // If the operation doesn't have a dialect prefix try using the default
1927  // dialect.
1928  auto opNameSplit = opName.split('.');
1929  StringRef dialectName = opNameSplit.first;
1930  std::string opNameStorage;
1931  if (opNameSplit.second.empty()) {
1932  // If the name didn't have a prefix, check for a code completion request.
1933  if (getToken().isCodeCompletion() && opName.back() == '.')
1934  return codeCompleteOperationName(dialectName);
1935 
1936  dialectName = getState().defaultDialectStack.back();
1937  opNameStorage = (dialectName + "." + opName).str();
1938  opName = opNameStorage;
1939  }
1940 
1941  // Try to load the dialect before returning the operation name to make sure
1942  // the operation has a chance to be registered.
1943  getContext()->getOrLoadDialect(dialectName);
1944  return OperationName(opName, getContext());
1945 }
1946 
1947 Operation *
1948 OperationParser::parseCustomOperation(ArrayRef<ResultRecord> resultIDs) {
1949  SMLoc opLoc = getToken().getLoc();
1950  StringRef originalOpName = getTokenSpelling();
1951 
1952  FailureOr<OperationName> opNameInfo = parseCustomOperationName();
1953  if (failed(opNameInfo))
1954  return nullptr;
1955  StringRef opName = opNameInfo->getStringRef();
1956 
1957  // This is the actual hook for the custom op parsing, usually implemented by
1958  // the op itself (`Op::parse()`). We retrieve it either from the
1959  // RegisteredOperationName or from the Dialect.
1960  OperationName::ParseAssemblyFn parseAssemblyFn;
1961  bool isIsolatedFromAbove = false;
1962 
1963  StringRef defaultDialect = "";
1964  if (auto opInfo = opNameInfo->getRegisteredInfo()) {
1965  parseAssemblyFn = opInfo->getParseAssemblyFn();
1966  isIsolatedFromAbove = opInfo->hasTrait<OpTrait::IsIsolatedFromAbove>();
1967  auto *iface = opInfo->getInterface<OpAsmOpInterface>();
1968  if (iface && !iface->getDefaultDialect().empty())
1969  defaultDialect = iface->getDefaultDialect();
1970  } else {
1971  std::optional<Dialect::ParseOpHook> dialectHook;
1972  Dialect *dialect = opNameInfo->getDialect();
1973  if (!dialect) {
1975  emitError(opLoc) << "Dialect `" << opNameInfo->getDialectNamespace()
1976  << "' not found for custom op '" << originalOpName
1977  << "' ";
1978  if (originalOpName != opName)
1979  diag << " (tried '" << opName << "' as well)";
1980  auto &note = diag.attachNote();
1981  note << "Registered dialects: ";
1982  llvm::interleaveComma(getContext()->getAvailableDialects(), note,
1983  [&](StringRef dialect) { note << dialect; });
1984  note << " ; for more info on dialect registration see "
1985  "https://mlir.llvm.org/getting_started/Faq/"
1986  "#registered-loaded-dependent-whats-up-with-dialects-management";
1987  return nullptr;
1988  }
1989  dialectHook = dialect->getParseOperationHook(opName);
1990  if (!dialectHook) {
1992  emitError(opLoc) << "custom op '" << originalOpName << "' is unknown";
1993  if (originalOpName != opName)
1994  diag << " (tried '" << opName << "' as well)";
1995  return nullptr;
1996  }
1997  parseAssemblyFn = *dialectHook;
1998  }
1999  getState().defaultDialectStack.push_back(defaultDialect);
2000  auto restoreDefaultDialect = llvm::make_scope_exit(
2001  [&]() { getState().defaultDialectStack.pop_back(); });
2002 
2003  // If the custom op parser crashes, produce some indication to help
2004  // debugging.
2005  llvm::PrettyStackTraceFormat fmt("MLIR Parser: custom op parser '%s'",
2006  opNameInfo->getIdentifier().data());
2007 
2008  // Get location information for the operation.
2009  auto srcLocation = getEncodedSourceLocation(opLoc);
2010  OperationState opState(srcLocation, *opNameInfo);
2011 
2012  // If we are populating the parser state, start a new operation definition.
2013  if (state.asmState)
2014  state.asmState->startOperationDefinition(opState.name);
2015 
2016  // Have the op implementation take a crack and parsing this.
2017  CleanupOpStateRegions guard{opState};
2018  CustomOpAsmParser opAsmParser(opLoc, resultIDs, parseAssemblyFn,
2019  isIsolatedFromAbove, opName, *this);
2020  if (opAsmParser.parseOperation(opState))
2021  return nullptr;
2022 
2023  // If it emitted an error, we failed.
2024  if (opAsmParser.didEmitError())
2025  return nullptr;
2026 
2027  Attribute properties = opState.propertiesAttr;
2028  opState.propertiesAttr = Attribute{};
2029 
2030  // Otherwise, create the operation and try to parse a location for it.
2031  Operation *op = opBuilder.create(opState);
2032  if (parseTrailingLocationSpecifier(op))
2033  return nullptr;
2034 
2035  // Try setting the properties for the operation.
2036  if (properties) {
2037  auto emitError = [&]() {
2038  return mlir::emitError(srcLocation, "invalid properties ")
2039  << properties << " for op " << op->getName().getStringRef()
2040  << ": ";
2041  };
2042  if (failed(op->setPropertiesFromAttribute(properties, emitError)))
2043  return nullptr;
2044  }
2045  return op;
2046 }
2047 
2048 ParseResult OperationParser::parseLocationAlias(LocationAttr &loc) {
2049  Token tok = getToken();
2050  consumeToken(Token::hash_identifier);
2051  StringRef identifier = tok.getSpelling().drop_front();
2052  if (identifier.contains('.')) {
2053  return emitError(tok.getLoc())
2054  << "expected location, but found dialect attribute: '#" << identifier
2055  << "'";
2056  }
2057  if (state.asmState)
2058  state.asmState->addAttrAliasUses(identifier, tok.getLocRange());
2059 
2060  // If this alias can be resolved, do it now.
2061  Attribute attr = state.symbols.attributeAliasDefinitions.lookup(identifier);
2062  if (attr) {
2063  if (!(loc = dyn_cast<LocationAttr>(attr)))
2064  return emitError(tok.getLoc())
2065  << "expected location, but found '" << attr << "'";
2066  } else {
2067  // Otherwise, remember this operation and resolve its location later.
2068  // In the meantime, use a special OpaqueLoc as a marker.
2069  loc = OpaqueLoc::get(deferredLocsReferences.size(),
2070  TypeID::get<DeferredLocInfo *>(),
2072  deferredLocsReferences.push_back(DeferredLocInfo{tok.getLoc(), identifier});
2073  }
2074  return success();
2075 }
2076 
2078 OperationParser::parseTrailingLocationSpecifier(OpOrArgument opOrArgument) {
2079  // If there is a 'loc' we parse a trailing location.
2080  if (!consumeIf(Token::kw_loc))
2081  return success();
2082  if (parseToken(Token::l_paren, "expected '(' in location"))
2083  return failure();
2084  Token tok = getToken();
2085 
2086  // Check to see if we are parsing a location alias.
2087  // Otherwise, we parse the location directly.
2088  LocationAttr directLoc;
2089  if (tok.is(Token::hash_identifier)) {
2090  if (parseLocationAlias(directLoc))
2091  return failure();
2092  } else if (parseLocationInstance(directLoc)) {
2093  return failure();
2094  }
2095 
2096  if (parseToken(Token::r_paren, "expected ')' in location"))
2097  return failure();
2098 
2099  if (auto *op = llvm::dyn_cast_if_present<Operation *>(opOrArgument))
2100  op->setLoc(directLoc);
2101  else
2102  opOrArgument.get<BlockArgument>().setLoc(directLoc);
2103  return success();
2104 }
2105 
2106 //===----------------------------------------------------------------------===//
2107 // Region Parsing
2108 //===----------------------------------------------------------------------===//
2109 
2110 ParseResult OperationParser::parseRegion(Region &region,
2111  ArrayRef<Argument> entryArguments,
2112  bool isIsolatedNameScope) {
2113  // Parse the '{'.
2114  Token lBraceTok = getToken();
2115  if (parseToken(Token::l_brace, "expected '{' to begin a region"))
2116  return failure();
2117 
2118  // If we are populating the parser state, start a new region definition.
2119  if (state.asmState)
2120  state.asmState->startRegionDefinition();
2121 
2122  // Parse the region body.
2123  if ((!entryArguments.empty() || getToken().isNot(Token::r_brace)) &&
2124  parseRegionBody(region, lBraceTok.getLoc(), entryArguments,
2125  isIsolatedNameScope)) {
2126  return failure();
2127  }
2128  consumeToken(Token::r_brace);
2129 
2130  // If we are populating the parser state, finalize this region.
2131  if (state.asmState)
2132  state.asmState->finalizeRegionDefinition();
2133 
2134  return success();
2135 }
2136 
2137 ParseResult OperationParser::parseRegionBody(Region &region, SMLoc startLoc,
2138  ArrayRef<Argument> entryArguments,
2139  bool isIsolatedNameScope) {
2140  auto currentPt = opBuilder.saveInsertionPoint();
2141 
2142  // Push a new named value scope.
2143  pushSSANameScope(isIsolatedNameScope);
2144 
2145  // Parse the first block directly to allow for it to be unnamed.
2146  auto owningBlock = std::make_unique<Block>();
2147  Block *block = owningBlock.get();
2148 
2149  // If this block is not defined in the source file, add a definition for it
2150  // now in the assembly state. Blocks with a name will be defined when the name
2151  // is parsed.
2152  if (state.asmState && getToken().isNot(Token::caret_identifier))
2153  state.asmState->addDefinition(block, startLoc);
2154 
2155  // Add arguments to the entry block if we had the form with explicit names.
2156  if (!entryArguments.empty() && !entryArguments[0].ssaName.name.empty()) {
2157  // If we had named arguments, then don't allow a block name.
2158  if (getToken().is(Token::caret_identifier))
2159  return emitError("invalid block name in region with named arguments");
2160 
2161  for (auto &entryArg : entryArguments) {
2162  auto &argInfo = entryArg.ssaName;
2163 
2164  // Ensure that the argument was not already defined.
2165  if (auto defLoc = getReferenceLoc(argInfo.name, argInfo.number)) {
2166  return emitError(argInfo.location, "region entry argument '" +
2167  argInfo.name +
2168  "' is already in use")
2169  .attachNote(getEncodedSourceLocation(*defLoc))
2170  << "previously referenced here";
2171  }
2172  Location loc = entryArg.sourceLoc.has_value()
2173  ? *entryArg.sourceLoc
2174  : getEncodedSourceLocation(argInfo.location);
2175  BlockArgument arg = block->addArgument(entryArg.type, loc);
2176 
2177  // Add a definition of this arg to the assembly state if provided.
2178  if (state.asmState)
2179  state.asmState->addDefinition(arg, argInfo.location);
2180 
2181  // Record the definition for this argument.
2182  if (addDefinition(argInfo, arg))
2183  return failure();
2184  }
2185  }
2186 
2187  if (parseBlock(block))
2188  return failure();
2189 
2190  // Verify that no other arguments were parsed.
2191  if (!entryArguments.empty() &&
2192  block->getNumArguments() > entryArguments.size()) {
2193  return emitError("entry block arguments were already defined");
2194  }
2195 
2196  // Parse the rest of the region.
2197  region.push_back(owningBlock.release());
2198  while (getToken().isNot(Token::r_brace)) {
2199  Block *newBlock = nullptr;
2200  if (parseBlock(newBlock))
2201  return failure();
2202  region.push_back(newBlock);
2203  }
2204 
2205  // Pop the SSA value scope for this region.
2206  if (popSSANameScope())
2207  return failure();
2208 
2209  // Reset the original insertion point.
2210  opBuilder.restoreInsertionPoint(currentPt);
2211  return success();
2212 }
2213 
2214 //===----------------------------------------------------------------------===//
2215 // Block Parsing
2216 //===----------------------------------------------------------------------===//
2217 
2218 /// Block declaration.
2219 ///
2220 /// block ::= block-label? operation*
2221 /// block-label ::= block-id block-arg-list? `:`
2222 /// block-id ::= caret-id
2223 /// block-arg-list ::= `(` ssa-id-and-type-list? `)`
2224 ///
2225 ParseResult OperationParser::parseBlock(Block *&block) {
2226  // The first block of a region may already exist, if it does the caret
2227  // identifier is optional.
2228  if (block && getToken().isNot(Token::caret_identifier))
2229  return parseBlockBody(block);
2230 
2231  SMLoc nameLoc = getToken().getLoc();
2232  auto name = getTokenSpelling();
2233  if (parseToken(Token::caret_identifier, "expected block name"))
2234  return failure();
2235 
2236  // Define the block with the specified name.
2237  auto &blockAndLoc = getBlockInfoByName(name);
2238  blockAndLoc.loc = nameLoc;
2239 
2240  // Use a unique pointer for in-flight block being parsed. Release ownership
2241  // only in the case of a successful parse. This ensures that the Block
2242  // allocated is released if the parse fails and control returns early.
2243  std::unique_ptr<Block> inflightBlock;
2244  auto cleanupOnFailure = llvm::make_scope_exit([&] {
2245  if (inflightBlock)
2246  inflightBlock->dropAllDefinedValueUses();
2247  });
2248 
2249  // If a block has yet to be set, this is a new definition. If the caller
2250  // provided a block, use it. Otherwise create a new one.
2251  if (!blockAndLoc.block) {
2252  if (block) {
2253  blockAndLoc.block = block;
2254  } else {
2255  inflightBlock = std::make_unique<Block>();
2256  blockAndLoc.block = inflightBlock.get();
2257  }
2258 
2259  // Otherwise, the block has a forward declaration. Forward declarations are
2260  // removed once defined, so if we are defining a existing block and it is
2261  // not a forward declaration, then it is a redeclaration. Fail if the block
2262  // was already defined.
2263  } else if (!eraseForwardRef(blockAndLoc.block)) {
2264  return emitError(nameLoc, "redefinition of block '") << name << "'";
2265  } else {
2266  // This was a forward reference block that is now floating. Keep track of it
2267  // as inflight in case of error, so that it gets cleaned up properly.
2268  inflightBlock.reset(blockAndLoc.block);
2269  }
2270 
2271  // Populate the high level assembly state if necessary.
2272  if (state.asmState)
2273  state.asmState->addDefinition(blockAndLoc.block, nameLoc);
2274  block = blockAndLoc.block;
2275 
2276  // If an argument list is present, parse it.
2277  if (getToken().is(Token::l_paren))
2278  if (parseOptionalBlockArgList(block))
2279  return failure();
2280  if (parseToken(Token::colon, "expected ':' after block name"))
2281  return failure();
2282 
2283  // Parse the body of the block.
2284  ParseResult res = parseBlockBody(block);
2285 
2286  // If parsing was successful, drop the inflight block. We relinquish ownership
2287  // back up to the caller.
2288  if (succeeded(res))
2289  (void)inflightBlock.release();
2290  return res;
2291 }
2292 
2293 ParseResult OperationParser::parseBlockBody(Block *block) {
2294  // Set the insertion point to the end of the block to parse.
2295  opBuilder.setInsertionPointToEnd(block);
2296 
2297  // Parse the list of operations that make up the body of the block.
2298  while (getToken().isNot(Token::caret_identifier, Token::r_brace))
2299  if (parseOperation())
2300  return failure();
2301 
2302  return success();
2303 }
2304 
2305 /// Get the block with the specified name, creating it if it doesn't already
2306 /// exist. The location specified is the point of use, which allows
2307 /// us to diagnose references to blocks that are not defined precisely.
2308 Block *OperationParser::getBlockNamed(StringRef name, SMLoc loc) {
2309  BlockDefinition &blockDef = getBlockInfoByName(name);
2310  if (!blockDef.block) {
2311  blockDef = {new Block(), loc};
2312  insertForwardRef(blockDef.block, blockDef.loc);
2313  }
2314 
2315  // Populate the high level assembly state if necessary.
2316  if (state.asmState)
2317  state.asmState->addUses(blockDef.block, loc);
2318 
2319  return blockDef.block;
2320 }
2321 
2322 /// Parse a (possibly empty) list of SSA operands with types as block arguments
2323 /// enclosed in parentheses.
2324 ///
2325 /// value-id-and-type-list ::= value-id-and-type (`,` ssa-id-and-type)*
2326 /// block-arg-list ::= `(` value-id-and-type-list? `)`
2327 ///
2328 ParseResult OperationParser::parseOptionalBlockArgList(Block *owner) {
2329  if (getToken().is(Token::r_brace))
2330  return success();
2331 
2332  // If the block already has arguments, then we're handling the entry block.
2333  // Parse and register the names for the arguments, but do not add them.
2334  bool definingExistingArgs = owner->getNumArguments() != 0;
2335  unsigned nextArgument = 0;
2336 
2337  return parseCommaSeparatedList(Delimiter::Paren, [&]() -> ParseResult {
2338  return parseSSADefOrUseAndType(
2339  [&](UnresolvedOperand useInfo, Type type) -> ParseResult {
2340  BlockArgument arg;
2341 
2342  // If we are defining existing arguments, ensure that the argument
2343  // has already been created with the right type.
2344  if (definingExistingArgs) {
2345  // Otherwise, ensure that this argument has already been created.
2346  if (nextArgument >= owner->getNumArguments())
2347  return emitError("too many arguments specified in argument list");
2348 
2349  // Finally, make sure the existing argument has the correct type.
2350  arg = owner->getArgument(nextArgument++);
2351  if (arg.getType() != type)
2352  return emitError("argument and block argument type mismatch");
2353  } else {
2354  auto loc = getEncodedSourceLocation(useInfo.location);
2355  arg = owner->addArgument(type, loc);
2356  }
2357 
2358  // If the argument has an explicit loc(...) specifier, parse and apply
2359  // it.
2360  if (parseTrailingLocationSpecifier(arg))
2361  return failure();
2362 
2363  // Mark this block argument definition in the parser state if it was
2364  // provided.
2365  if (state.asmState)
2366  state.asmState->addDefinition(arg, useInfo.location);
2367 
2368  return addDefinition(useInfo, arg);
2369  });
2370  });
2371 }
2372 
2373 //===----------------------------------------------------------------------===//
2374 // Code Completion
2375 //===----------------------------------------------------------------------===//
2376 
2377 ParseResult OperationParser::codeCompleteSSAUse() {
2378  std::string detailData;
2379  llvm::raw_string_ostream detailOS(detailData);
2380  for (IsolatedSSANameScope &scope : isolatedNameScopes) {
2381  for (auto &it : scope.values) {
2382  if (it.second.empty())
2383  continue;
2384  Value frontValue = it.second.front().value;
2385 
2386  // If the value isn't a forward reference, we also add the name of the op
2387  // to the detail.
2388  if (auto result = dyn_cast<OpResult>(frontValue)) {
2389  if (!forwardRefPlaceholders.count(result))
2390  detailOS << result.getOwner()->getName() << ": ";
2391  } else {
2392  detailOS << "arg #" << cast<BlockArgument>(frontValue).getArgNumber()
2393  << ": ";
2394  }
2395 
2396  // Emit the type of the values to aid with completion selection.
2397  detailOS << frontValue.getType();
2398 
2399  // FIXME: We should define a policy for packed values, e.g. with a limit
2400  // on the detail size, but it isn't clear what would be useful right now.
2401  // For now we just only emit the first type.
2402  if (it.second.size() > 1)
2403  detailOS << ", ...";
2404 
2405  state.codeCompleteContext->appendSSAValueCompletion(
2406  it.getKey(), std::move(detailOS.str()));
2407  }
2408  }
2409 
2410  return failure();
2411 }
2412 
2413 ParseResult OperationParser::codeCompleteBlock() {
2414  // Don't provide completions if the token isn't empty, e.g. this avoids
2415  // weirdness when we encounter a `.` within the identifier.
2416  StringRef spelling = getTokenSpelling();
2417  if (!(spelling.empty() || spelling == "^"))
2418  return failure();
2419 
2420  for (const auto &it : blocksByName.back())
2421  state.codeCompleteContext->appendBlockCompletion(it.getFirst());
2422  return failure();
2423 }
2424 
2425 //===----------------------------------------------------------------------===//
2426 // Top-level entity parsing.
2427 //===----------------------------------------------------------------------===//
2428 
2429 namespace {
2430 /// This parser handles entities that are only valid at the top level of the
2431 /// file.
2432 class TopLevelOperationParser : public Parser {
2433 public:
2434  explicit TopLevelOperationParser(ParserState &state) : Parser(state) {}
2435 
2436  /// Parse a set of operations into the end of the given Block.
2437  ParseResult parse(Block *topLevelBlock, Location parserLoc);
2438 
2439 private:
2440  /// Parse an attribute alias declaration.
2441  ///
2442  /// attribute-alias-def ::= '#' alias-name `=` attribute-value
2443  ///
2444  ParseResult parseAttributeAliasDef();
2445 
2446  /// Parse a type alias declaration.
2447  ///
2448  /// type-alias-def ::= '!' alias-name `=` type
2449  ///
2450  ParseResult parseTypeAliasDef();
2451 
2452  /// Parse a top-level file metadata dictionary.
2453  ///
2454  /// file-metadata-dict ::= '{-#' file-metadata-entry* `#-}'
2455  ///
2456  ParseResult parseFileMetadataDictionary();
2457 
2458  /// Parse a resource metadata dictionary.
2459  ParseResult parseResourceFileMetadata(
2460  function_ref<ParseResult(StringRef, SMLoc)> parseBody);
2461  ParseResult parseDialectResourceFileMetadata();
2462  ParseResult parseExternalResourceFileMetadata();
2463 };
2464 
2465 /// This class represents an implementation of a resource entry for the MLIR
2466 /// textual format.
2467 class ParsedResourceEntry : public AsmParsedResourceEntry {
2468 public:
2469  ParsedResourceEntry(StringRef key, SMLoc keyLoc, Token value, Parser &p)
2470  : key(key), keyLoc(keyLoc), value(value), p(p) {}
2471  ~ParsedResourceEntry() override = default;
2472 
2473  StringRef getKey() const final { return key; }
2474 
2475  InFlightDiagnostic emitError() const final { return p.emitError(keyLoc); }
2476 
2477  AsmResourceEntryKind getKind() const final {
2478  if (value.isAny(Token::kw_true, Token::kw_false))
2480  return value.getSpelling().startswith("\"0x")
2483  }
2484 
2485  FailureOr<bool> parseAsBool() const final {
2486  if (value.is(Token::kw_true))
2487  return true;
2488  if (value.is(Token::kw_false))
2489  return false;
2490  return p.emitError(value.getLoc(),
2491  "expected 'true' or 'false' value for key '" + key +
2492  "'");
2493  }
2494 
2495  FailureOr<std::string> parseAsString() const final {
2496  if (value.isNot(Token::string))
2497  return p.emitError(value.getLoc(),
2498  "expected string value for key '" + key + "'");
2499  return value.getStringValue();
2500  }
2501 
2503  parseAsBlob(BlobAllocatorFn allocator) const final {
2504  // Blob data within then textual format is represented as a hex string.
2505  // TODO: We could avoid an additional alloc+copy here if we pre-allocated
2506  // the buffer to use during hex processing.
2507  std::optional<std::string> blobData =
2508  value.is(Token::string) ? value.getHexStringValue() : std::nullopt;
2509  if (!blobData)
2510  return p.emitError(value.getLoc(),
2511  "expected hex string blob for key '" + key + "'");
2512 
2513  // Extract the alignment of the blob data, which gets stored at the
2514  // beginning of the string.
2515  if (blobData->size() < sizeof(uint32_t)) {
2516  return p.emitError(value.getLoc(),
2517  "expected hex string blob for key '" + key +
2518  "' to encode alignment in first 4 bytes");
2519  }
2520  llvm::support::ulittle32_t align;
2521  memcpy(&align, blobData->data(), sizeof(uint32_t));
2522  if (align && !llvm::isPowerOf2_32(align)) {
2523  return p.emitError(value.getLoc(),
2524  "expected hex string blob for key '" + key +
2525  "' to encode alignment in first 4 bytes, but got "
2526  "non-power-of-2 value: " +
2527  Twine(align));
2528  }
2529 
2530  // Get the data portion of the blob.
2531  StringRef data = StringRef(*blobData).drop_front(sizeof(uint32_t));
2532  if (data.empty())
2533  return AsmResourceBlob();
2534 
2535  // Allocate memory for the blob using the provided allocator and copy the
2536  // data into it.
2537  AsmResourceBlob blob = allocator(data.size(), align);
2538  assert(llvm::isAddrAligned(llvm::Align(align), blob.getData().data()) &&
2539  blob.isMutable() &&
2540  "blob allocator did not return a properly aligned address");
2541  memcpy(blob.getMutableData().data(), data.data(), data.size());
2542  return blob;
2543  }
2544 
2545 private:
2546  StringRef key;
2547  SMLoc keyLoc;
2548  Token value;
2549  Parser &p;
2550 };
2551 } // namespace
2552 
2553 ParseResult TopLevelOperationParser::parseAttributeAliasDef() {
2554  assert(getToken().is(Token::hash_identifier));
2555  StringRef aliasName = getTokenSpelling().drop_front();
2556 
2557  // Check for redefinitions.
2558  if (state.symbols.attributeAliasDefinitions.count(aliasName) > 0)
2559  return emitError("redefinition of attribute alias id '" + aliasName + "'");
2560 
2561  // Make sure this isn't invading the dialect attribute namespace.
2562  if (aliasName.contains('.'))
2563  return emitError("attribute names with a '.' are reserved for "
2564  "dialect-defined names");
2565 
2566  SMRange location = getToken().getLocRange();
2567  consumeToken(Token::hash_identifier);
2568 
2569  // Parse the '='.
2570  if (parseToken(Token::equal, "expected '=' in attribute alias definition"))
2571  return failure();
2572 
2573  // Parse the attribute value.
2574  Attribute attr = parseAttribute();
2575  if (!attr)
2576  return failure();
2577 
2578  // Register this alias with the parser state.
2579  if (state.asmState)
2580  state.asmState->addAttrAliasDefinition(aliasName, location, attr);
2581  state.symbols.attributeAliasDefinitions[aliasName] = attr;
2582  return success();
2583 }
2584 
2585 ParseResult TopLevelOperationParser::parseTypeAliasDef() {
2586  assert(getToken().is(Token::exclamation_identifier));
2587  StringRef aliasName = getTokenSpelling().drop_front();
2588 
2589  // Check for redefinitions.
2590  if (state.symbols.typeAliasDefinitions.count(aliasName) > 0)
2591  return emitError("redefinition of type alias id '" + aliasName + "'");
2592 
2593  // Make sure this isn't invading the dialect type namespace.
2594  if (aliasName.contains('.'))
2595  return emitError("type names with a '.' are reserved for "
2596  "dialect-defined names");
2597 
2598  SMRange location = getToken().getLocRange();
2599  consumeToken(Token::exclamation_identifier);
2600 
2601  // Parse the '='.
2602  if (parseToken(Token::equal, "expected '=' in type alias definition"))
2603  return failure();
2604 
2605  // Parse the type.
2606  Type aliasedType = parseType();
2607  if (!aliasedType)
2608  return failure();
2609 
2610  // Register this alias with the parser state.
2611  if (state.asmState)
2612  state.asmState->addTypeAliasDefinition(aliasName, location, aliasedType);
2613  state.symbols.typeAliasDefinitions.try_emplace(aliasName, aliasedType);
2614  return success();
2615 }
2616 
2617 ParseResult TopLevelOperationParser::parseFileMetadataDictionary() {
2618  consumeToken(Token::file_metadata_begin);
2619  return parseCommaSeparatedListUntil(
2620  Token::file_metadata_end, [&]() -> ParseResult {
2621  // Parse the key of the metadata dictionary.
2622  SMLoc keyLoc = getToken().getLoc();
2623  StringRef key;
2624  if (failed(parseOptionalKeyword(&key)))
2625  return emitError("expected identifier key in file "
2626  "metadata dictionary");
2627  if (parseToken(Token::colon, "expected ':'"))
2628  return failure();
2629 
2630  // Process the metadata entry.
2631  if (key == "dialect_resources")
2632  return parseDialectResourceFileMetadata();
2633  if (key == "external_resources")
2634  return parseExternalResourceFileMetadata();
2635  return emitError(keyLoc, "unknown key '" + key +
2636  "' in file metadata dictionary");
2637  });
2638 }
2639 
2640 ParseResult TopLevelOperationParser::parseResourceFileMetadata(
2641  function_ref<ParseResult(StringRef, SMLoc)> parseBody) {
2642  if (parseToken(Token::l_brace, "expected '{'"))
2643  return failure();
2644 
2645  return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2646  // Parse the top-level name entry.
2647  SMLoc nameLoc = getToken().getLoc();
2648  StringRef name;
2649  if (failed(parseOptionalKeyword(&name)))
2650  return emitError("expected identifier key for 'resource' entry");
2651 
2652  if (parseToken(Token::colon, "expected ':'") ||
2653  parseToken(Token::l_brace, "expected '{'"))
2654  return failure();
2655  return parseBody(name, nameLoc);
2656  });
2657 }
2658 
2659 ParseResult TopLevelOperationParser::parseDialectResourceFileMetadata() {
2660  return parseResourceFileMetadata([&](StringRef name,
2661  SMLoc nameLoc) -> ParseResult {
2662  // Lookup the dialect and check that it can handle a resource entry.
2663  Dialect *dialect = getContext()->getOrLoadDialect(name);
2664  if (!dialect)
2665  return emitError(nameLoc, "dialect '" + name + "' is unknown");
2666  const auto *handler = dyn_cast<OpAsmDialectInterface>(dialect);
2667  if (!handler) {
2668  return emitError() << "unexpected 'resource' section for dialect '"
2669  << dialect->getNamespace() << "'";
2670  }
2671 
2672  return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2673  // Parse the name of the resource entry.
2674  SMLoc keyLoc = getToken().getLoc();
2675  StringRef key;
2676  if (failed(parseResourceHandle(handler, key)) ||
2677  parseToken(Token::colon, "expected ':'"))
2678  return failure();
2679  Token valueTok = getToken();
2680  consumeToken();
2681 
2682  ParsedResourceEntry entry(key, keyLoc, valueTok, *this);
2683  return handler->parseResource(entry);
2684  });
2685  });
2686 }
2687 
2688 ParseResult TopLevelOperationParser::parseExternalResourceFileMetadata() {
2689  return parseResourceFileMetadata([&](StringRef name,
2690  SMLoc nameLoc) -> ParseResult {
2691  AsmResourceParser *handler = state.config.getResourceParser(name);
2692 
2693  // TODO: Should we require handling external resources in some scenarios?
2694  if (!handler) {
2695  emitWarning(getEncodedSourceLocation(nameLoc))
2696  << "ignoring unknown external resources for '" << name << "'";
2697  }
2698 
2699  return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2700  // Parse the name of the resource entry.
2701  SMLoc keyLoc = getToken().getLoc();
2702  StringRef key;
2703  if (failed(parseOptionalKeyword(&key)))
2704  return emitError(
2705  "expected identifier key for 'external_resources' entry");
2706  if (parseToken(Token::colon, "expected ':'"))
2707  return failure();
2708  Token valueTok = getToken();
2709  consumeToken();
2710 
2711  if (!handler)
2712  return success();
2713  ParsedResourceEntry entry(key, keyLoc, valueTok, *this);
2714  return handler->parseResource(entry);
2715  });
2716  });
2717 }
2718 
2720  Location parserLoc) {
2721  // Create a top-level operation to contain the parsed state.
2722  OwningOpRef<ModuleOp> topLevelOp(ModuleOp::create(parserLoc));
2723  OperationParser opParser(state, topLevelOp.get());
2724  while (true) {
2725  switch (getToken().getKind()) {
2726  default:
2727  // Parse a top-level operation.
2728  if (opParser.parseOperation())
2729  return failure();
2730  break;
2731 
2732  // If we got to the end of the file, then we're done.
2733  case Token::eof: {
2734  if (opParser.finalize())
2735  return failure();
2736 
2737  // Splice the blocks of the parsed operation over to the provided
2738  // top-level block.
2739  auto &parsedOps = topLevelOp->getBody()->getOperations();
2740  auto &destOps = topLevelBlock->getOperations();
2741  destOps.splice(destOps.end(), parsedOps, parsedOps.begin(),
2742  parsedOps.end());
2743  return success();
2744  }
2745 
2746  // If we got an error token, then the lexer already emitted an error, just
2747  // stop. Someday we could introduce error recovery if there was demand
2748  // for it.
2749  case Token::error:
2750  return failure();
2751 
2752  // Parse an attribute alias.
2753  case Token::hash_identifier:
2754  if (parseAttributeAliasDef())
2755  return failure();
2756  break;
2757 
2758  // Parse a type alias.
2759  case Token::exclamation_identifier:
2760  if (parseTypeAliasDef())
2761  return failure();
2762  break;
2763 
2764  // Parse a file-level metadata dictionary.
2765  case Token::file_metadata_begin:
2766  if (parseFileMetadataDictionary())
2767  return failure();
2768  break;
2769  }
2770  }
2771 }
2772 
2773 //===----------------------------------------------------------------------===//
2774 
2776 mlir::parseAsmSourceFile(const llvm::SourceMgr &sourceMgr, Block *block,
2777  const ParserConfig &config, AsmParserState *asmState,
2778  AsmParserCodeCompleteContext *codeCompleteContext) {
2779  const auto *sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
2780 
2781  Location parserLoc =
2782  FileLineColLoc::get(config.getContext(), sourceBuf->getBufferIdentifier(),
2783  /*line=*/0, /*column=*/0);
2784 
2785  SymbolState aliasState;
2786  ParserState state(sourceMgr, config, aliasState, asmState,
2787  codeCompleteContext);
2788  return TopLevelOperationParser(state).parse(block, parserLoc);
2789 }
static MLIRContext * getContext(OpFoldResult val)
@ None
static std::string diag(const llvm::Value &value)
#define MLIR_DECLARE_EXPLICIT_TYPE_ID(CLASS_NAME)
Definition: TypeID.h:249
#define MLIR_DEFINE_EXPLICIT_TYPE_ID(CLASS_NAME)
Definition: TypeID.h:263
Base type for affine expression.
Definition: AffineExpr.h:68
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition: AffineMap.h:47
This class represents a single parsed resource entry.
Definition: AsmState.h:283
This class provides an abstract interface into the parser for hooking in code completion events.
Definition: CodeComplete.h:24
virtual void completeExpectedTokens(ArrayRef< StringRef > tokens, bool optional)=0
Signal a completion for the given expected tokens, which are optional if optional is set.
virtual void completeAttribute(const llvm::StringMap< Attribute > &aliases)=0
Signal a completion for an attribute.
virtual void completeDialectAttributeOrAlias(const llvm::StringMap< Attribute > &aliases)=0
virtual void completeType(const llvm::StringMap< Type > &aliases)=0
Signal a completion for a type.
virtual void completeOperationName(StringRef dialectName)=0
Signal code completion for an operation name within the given dialect.
virtual void completeDialectName(StringRef prefix)=0
Signal code completion for a dialect name, with an optional prefix.
virtual void completeDialectTypeOrAlias(const llvm::StringMap< Type > &aliases)=0
This class represents state from a parsed MLIR textual format string.
void initialize(Operation *topLevelOp)
Initialize the state in preparation for populating more parser state under the given top-level operat...
Delimiter
These are the supported delimiters around operand lists and region argument lists,...
@ Paren
Parens surrounding zero or more operands.
@ None
Zero or more operands with no delimiters.
@ OptionalLessGreater
<> brackets supporting zero or more ops, or nothing.
@ Braces
{} brackets surrounding zero or more operands.
@ OptionalBraces
{} brackets surrounding zero or more operands, or nothing.
@ OptionalParen
Parens supporting zero or more operands, or nothing.
@ Square
Square brackets surrounding zero or more operands.
@ LessGreater
<> brackets surrounding zero or more operands.
@ OptionalSquare
Square brackets supporting zero or more ops, or nothing.
The following classes enable support for parsing and printing resources within MLIR assembly formats.
Definition: AsmState.h:88
MutableArrayRef< char > getMutableData()
Return a mutable reference to the raw underlying data of this blob.
Definition: AsmState.h:154
ArrayRef< char > getData() const
Return the raw underlying data of this blob.
Definition: AsmState.h:142
bool isMutable() const
Return if the data of this blob is mutable.
Definition: AsmState.h:161
This class represents an instance of a resource parser.
Definition: AsmState.h:330
virtual LogicalResult parseResource(AsmParsedResourceEntry &entry)=0
Parse the given resource entry.
Attributes are known-constant values of operations.
Definition: Attributes.h:25
This class represents an argument of a Block.
Definition: Value.h:315
Block represents an ordered list of Operations.
Definition: Block.h:30
OpListType::iterator iterator
Definition: Block.h:133
BlockArgument getArgument(unsigned i)
Definition: Block.h:122
unsigned getNumArguments()
Definition: Block.h:121
void dropAllDefinedValueUses()
This drops all uses of values defined in this block or in the blocks of nested regions wherever the u...
Definition: Block.cpp:88
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
Definition: Block.cpp:147
OpListType & getOperations()
Definition: Block.h:130
BlockArgListType getArguments()
Definition: Block.h:80
Diagnostic & append(Arg1 &&arg1, Arg2 &&arg2, Args &&...args)
Append arguments to the diagnostic.
Definition: Diagnostics.h:228
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition: Dialect.h:41
virtual std::optional< ParseOpHook > getParseOperationHook(StringRef opName) const
Return the hook to parse an operation registered to this dialect, if any.
Definition: Dialect.cpp:79
StringRef getNamespace() const
Definition: Dialect.h:57
This class provides support for representing a failure result, or a valid value of type T.
Definition: LogicalResult.h:78
This class represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:308
Diagnostic & attachNote(std::optional< Location > noteLoc=std::nullopt)
Attaches a note to this diagnostic.
Definition: Diagnostics.h:346
InFlightDiagnostic & append(Args &&...args) &
Append arguments to the diagnostic.
Definition: Diagnostics.h:334
const char * getBufferBegin()
Returns the start of the buffer.
Definition: Lexer.h:41
Location objects represent source locations information in MLIR.
Definition: Location.h:31
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:63
T * getOrLoadDialect()
Get (or create) a dialect for the given derived dialect type.
Definition: MLIRContext.h:97
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
DictionaryAttr getDictionary(MLIRContext *context) const
Return a dictionary attribute for the underlying dictionary.
void push_back(NamedAttribute newAttribute)
Add an attribute with the specified name.
std::optional< NamedAttribute > findDuplicate() const
Returns an entry with a duplicate name the list, if it exists, else returns std::nullopt.
virtual std::string getResourceKey(const AsmDialectResourceHandle &handle) const
Return a key to use for the given resource.
virtual FailureOr< AsmDialectResourceHandle > declareResource(StringRef key) const
Declare a resource with the given key, returning a handle to use for any references of this resource ...
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
RAII guard to reset the insertion point of the builder when destroyed.
Definition: Builders.h:333
This class helps build Operations.
Definition: Builders.h:206
This class provides the API for ops that are known to be isolated from above.
This class provides the API for ops that are known to be terminators.
Definition: OpDefinition.h:762
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
llvm::unique_function< ParseResult(OpAsmParser &, OperationState &)> ParseAssemblyFn
std::optional< RegisteredOperationName > getRegisteredInfo() const
If this operation is registered, returns the registered information, std::nullopt otherwise.
bool mightHaveTrait() const
Returns true if the operation might have the provided trait.
bool isRegistered() const
Return if this operation is registered.
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
void setLoc(Location loc)
Set the source location the operation was defined or derived from.
Definition: Operation.h:226
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Definition: Operation.h:402
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:223
static Operation * create(Location location, OperationName name, TypeRange resultTypes, ValueRange operands, NamedAttrList &&attributes, OpaqueProperties properties, BlockRange successors, unsigned numRegions)
Create a new Operation with the specific fields.
Definition: Operation.cpp:66
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
Definition: Operation.h:655
OperationName getName()
The name of an operation is the key identifier for it.
Definition: Operation.h:119
LogicalResult setPropertiesFromAttribute(Attribute attr, function_ref< InFlightDiagnostic()> emitError)
Set the properties from the provided attribute.
Definition: Operation.cpp:354
unsigned getNumResults()
Return the number of results held by this operation.
Definition: Operation.h:399
This class implements Optional functionality for ParseResult.
Definition: OpDefinition.h:39
This class represents success/failure for parsing-like operations that find it important to chain tog...
This class represents a configuration for the MLIR assembly parser.
Definition: AsmState.h:460
MLIRContext * getContext() const
Return the MLIRContext to be used when parsing.
Definition: AsmState.h:474
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
void push_back(Block *block)
Definition: Region.h:61
static std::optional< RegisteredOperationName > lookup(StringRef name, MLIRContext *ctx)
Lookup the registered operation information for the given operation.
This represents a token in the MLIR syntax.
Definition: Token.h:20
bool isCodeCompletionFor(Kind kind) const
Returns true if the current token represents a code completion for the "normal" token type.
Definition: Token.cpp:203
SMRange getLocRange() const
Definition: Token.cpp:30
bool isKeyword() const
Return true if this is one of the keyword token kinds (e.g. kw_if).
Definition: Token.cpp:192
static StringRef getTokenSpelling(Kind kind)
Given a punctuation or keyword token kind, return the spelling of the token as a string.
Definition: Token.cpp:177
SMLoc getLoc() const
Definition: Token.cpp:24
bool is(Kind k) const
Definition: Token.h:38
std::string getStringValue() const
Given a token containing a string literal, return its value, including removing the quote characters ...
Definition: Token.cpp:86
static std::optional< uint64_t > getUInt64IntegerValue(StringRef spelling)
For an integer token, return its value as an uint64_t.
Definition: Token.cpp:45
bool isAny(Kind k1, Kind k2) const
Definition: Token.h:40
bool isNot(Kind k) const
Definition: Token.h:50
bool isCodeCompletion() const
Returns true if the current token represents a code completion.
Definition: Token.h:62
StringRef getSpelling() const
Definition: Token.h:34
bool isOrIsCodeCompletionFor(Kind kind) const
Returns true if the current token is the given type, or represents a code completion for that type.
Definition: Token.h:70
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
Type getType() const
Return the type of this value.
Definition: Value.h:125
static WalkResult advance()
Definition: Visitors.h:52
static WalkResult interrupt()
Definition: Visitors.h:51
This class provides the implementation of the generic parser methods within AsmParser.
Definition: AsmParserImpl.h:28
InFlightDiagnostic emitError(SMLoc loc, const Twine &message) override
Emit a diagnostic at the specified location and return failure.
Definition: AsmParserImpl.h:45
This class implement support for parsing global entities like attributes and types.
Definition: Parser.h:26
ParseResult parseOptionalKeyword(StringRef *keyword)
Parse a keyword, if present, into 'keyword'.
Definition: Parser.cpp:346
ParseResult parseToken(Token::Kind expectedToken, const Twine &message)
Consume the specified token if present and return success.
Definition: Parser.cpp:267
ParseResult parseCommaSeparatedListUntil(Token::Kind rightToken, function_ref< ParseResult()> parseElement, bool allowEmptyList=true)
Parse a comma-separated list of elements up until the specified end token.
Definition: Parser.cpp:173
ParseResult codeCompleteOperationName(StringRef dialectName)
Definition: Parser.cpp:407
ParserState & getState() const
Definition: Parser.h:36
Type codeCompleteType()
Definition: Parser.cpp:467
Location getEncodedSourceLocation(SMLoc loc)
Encode the specified source location information into an attribute for attachment to the IR.
Definition: Parser.h:93
InFlightDiagnostic emitError(const Twine &message={})
Emit an error and return failure.
Definition: Parser.cpp:192
ParserState & state
The Parser is subclassed and reinstantiated.
Definition: Parser.h:347
ParseResult codeCompleteDialectName()
The set of various code completion methods.
Definition: Parser.cpp:402
StringRef getTokenSpelling() const
Definition: Parser.h:103
void consumeToken()
Advance the current lexer onto the next token.
Definition: Parser.h:115
ParseResult codeCompleteExpectedTokens(ArrayRef< StringRef > tokens)
Definition: Parser.cpp:453
Attribute codeCompleteAttribute()
Definition: Parser.cpp:462
ParseResult codeCompleteDialectOrElidedOpName(SMLoc loc)
Definition: Parser.cpp:417
InFlightDiagnostic emitWrongTokenError(const Twine &message={})
Emit an error about a "wrong token".
Definition: Parser.cpp:215
ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())
Parse a list of comma-separated items with an optional delimiter.
Definition: Parser.cpp:84
OptionalParseResult parseOptionalInteger(APInt &result)
Parse an optional integer value from the stream.
Definition: Parser.cpp:275
bool isCurrentTokenAKeyword() const
Returns true if the current token corresponds to a keyword.
Definition: Parser.h:149
ParseResult codeCompleteStringDialectOrOperationName(StringRef name)
Definition: Parser.cpp:440
ParseResult parseFloatFromIntegerLiteral(std::optional< APFloat > &result, const Token &tok, bool isNegative, const llvm::fltSemantics &semantics, size_t typeSizeInBits)
Parse a floating point value from an integer literal token.
Definition: Parser.cpp:312
ParseResult codeCompleteOptionalTokens(ArrayRef< StringRef > tokens)
Definition: Parser.cpp:457
const Token & getToken() const
Return the current token the parser is inspecting.
Definition: Parser.h:102
FailureOr< AsmDialectResourceHandle > parseResourceHandle(const OpAsmDialectInterface *dialect, StringRef &name)
Parse a handle to a dialect resource within the assembly format.
Definition: Parser.cpp:360
bool consumeIf(Token::Kind kind)
If the current token has the specified kind, consume it and return true.
Definition: Parser.h:107
Attribute codeCompleteDialectSymbol(const llvm::StringMap< Attribute > &aliases)
Definition: Parser.cpp:473
LogicalResult parseCommaSeparatedList(llvm::cl::Option &opt, StringRef argName, StringRef optionStr, function_ref< LogicalResult(StringRef)> elementParseFn)
Parse a string containing a list of comma-delimited elements, invoking the given parser for each sub-...
Detect if any of the given parameter types has a sub-element handler.
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Definition: Query.cpp:19
llvm::PointerUnion< NamedAttribute *, NamedProperty *, NamedTypeConstraint * > Argument
Definition: Argument.h:64
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
InFlightDiagnostic emitWarning(Location loc)
Utility method to emit a warning message using this location.
LogicalResult parseAsmSourceFile(const llvm::SourceMgr &sourceMgr, Block *block, const ParserConfig &config, AsmParserState *asmState=nullptr, AsmParserCodeCompleteContext *codeCompleteContext=nullptr)
This parses the file specified by the indicated SourceMgr and appends parsed operations to the given ...
Definition: Parser.cpp:2776
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value.
Definition: LogicalResult.h:68
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
Attribute parseAttribute(llvm::StringRef attrStr, MLIRContext *context, Type type={}, size_t *numRead=nullptr, bool isKnownNullTerminated=false)
This parses a single MLIR attribute to an MLIR context if it was valid.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
Type parseType(llvm::StringRef typeStr, MLIRContext *context, size_t *numRead=nullptr, bool isKnownNullTerminated=false)
This parses a single MLIR type to an MLIR context if it was valid.
AsmResourceEntryKind
This enum represents the different kinds of resource values.
Definition: AsmState.h:272
@ String
A string value.
@ Bool
A boolean value.
@ Blob
A blob of data with an accompanying alignment.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
Definition: Verifier.cpp:421
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
This is the representation of an operand reference.
This represents an operation in an abstracted form, suitable for use with the builder APIs.
void addRegions(MutableArrayRef< std::unique_ptr< Region >> regions)
Take ownership of a set of regions that should be attached to the Operation.
OpaqueProperties getRawProperties()
SmallVector< Value, 4 > operands
void addAttributes(ArrayRef< NamedAttribute > newAttributes)
Add an array of named attributes.
void addSuccessors(Block *successor)
void addTypes(ArrayRef< Type > newTypes)
SmallVector< std::unique_ptr< Region >, 1 > regions
Regions that the op will hold.
NamedAttrList attributes
This class refers to all of the state maintained globally by the parser, such as the current lexer po...
Definition: ParserState.h:51
SymbolState & symbols
The current state for symbol parsing.
Definition: ParserState.h:72
Lexer lex
The lexer for the source file we're parsing.
Definition: ParserState.h:66
Token curToken
This is the next token that hasn't been consumed yet.
Definition: ParserState.h:69
AsmParserCodeCompleteContext * codeCompleteContext
An optional code completion context.
Definition: ParserState.h:83
AsmParserState * asmState
An optional pointer to a struct containing high level parser state to be populated during parsing.
Definition: ParserState.h:80
SmallVector< StringRef > defaultDialectStack
Definition: ParserState.h:90
This class contains record of any parsed top-level symbols.
Definition: ParserState.h:28
llvm::StringMap< Attribute > attributeAliasDefinitions
A map from attribute alias identifier to Attribute.
Definition: ParserState.h:30
DenseMap< const OpAsmDialectInterface *, llvm::StringMap< std::pair< std::string, AsmDialectResourceHandle > > > dialectResources
A map of dialect resource keys to the resolved resource name and handle to use during parsing.
Definition: ParserState.h:39
llvm::StringMap< Type > typeAliasDefinitions
A map from type alias identifier to Type.
Definition: ParserState.h:33