MLIR  19.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=*/getLastToken().getEndLoc(),
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(
1229  op, nameTok.getLocRange(),
1230  /*endLoc=*/getLastToken().getEndLoc());
1231  }
1232 
1233  return success();
1234 }
1235 
1236 /// Parse a single operation successor.
1237 ///
1238 /// successor ::= block-id
1239 ///
1240 ParseResult OperationParser::parseSuccessor(Block *&dest) {
1241  if (getToken().isCodeCompletion())
1242  return codeCompleteBlock();
1243 
1244  // Verify branch is identifier and get the matching block.
1245  if (!getToken().is(Token::caret_identifier))
1246  return emitWrongTokenError("expected block name");
1247  dest = getBlockNamed(getTokenSpelling(), getToken().getLoc());
1248  consumeToken();
1249  return success();
1250 }
1251 
1252 /// Parse a comma-separated list of operation successors in brackets.
1253 ///
1254 /// successor-list ::= `[` successor (`,` successor )* `]`
1255 ///
1257 OperationParser::parseSuccessors(SmallVectorImpl<Block *> &destinations) {
1258  if (parseToken(Token::l_square, "expected '['"))
1259  return failure();
1260 
1261  auto parseElt = [this, &destinations] {
1262  Block *dest;
1263  ParseResult res = parseSuccessor(dest);
1264  destinations.push_back(dest);
1265  return res;
1266  };
1267  return parseCommaSeparatedListUntil(Token::r_square, parseElt,
1268  /*allowEmptyList=*/false);
1269 }
1270 
1271 namespace {
1272 // RAII-style guard for cleaning up the regions in the operation state before
1273 // deleting them. Within the parser, regions may get deleted if parsing failed,
1274 // and other errors may be present, in particular undominated uses. This makes
1275 // sure such uses are deleted.
1276 struct CleanupOpStateRegions {
1277  ~CleanupOpStateRegions() {
1278  SmallVector<Region *, 4> regionsToClean;
1279  regionsToClean.reserve(state.regions.size());
1280  for (auto &region : state.regions)
1281  if (region)
1282  for (auto &block : *region)
1283  block.dropAllDefinedValueUses();
1284  }
1285  OperationState &state;
1286 };
1287 } // namespace
1288 
1289 ParseResult OperationParser::parseGenericOperationAfterOpName(
1290  OperationState &result,
1291  std::optional<ArrayRef<UnresolvedOperand>> parsedOperandUseInfo,
1292  std::optional<ArrayRef<Block *>> parsedSuccessors,
1293  std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
1294  std::optional<ArrayRef<NamedAttribute>> parsedAttributes,
1295  std::optional<Attribute> propertiesAttribute,
1296  std::optional<FunctionType> parsedFnType) {
1297 
1298  // Parse the operand list, if not explicitly provided.
1300  if (!parsedOperandUseInfo) {
1301  if (parseToken(Token::l_paren, "expected '(' to start operand list") ||
1302  parseOptionalSSAUseList(opInfo) ||
1303  parseToken(Token::r_paren, "expected ')' to end operand list")) {
1304  return failure();
1305  }
1306  parsedOperandUseInfo = opInfo;
1307  }
1308 
1309  // Parse the successor list, if not explicitly provided.
1310  if (!parsedSuccessors) {
1311  if (getToken().is(Token::l_square)) {
1312  // Check if the operation is not a known terminator.
1313  if (!result.name.mightHaveTrait<OpTrait::IsTerminator>())
1314  return emitError("successors in non-terminator");
1315 
1316  SmallVector<Block *, 2> successors;
1317  if (parseSuccessors(successors))
1318  return failure();
1319  result.addSuccessors(successors);
1320  }
1321  } else {
1322  result.addSuccessors(*parsedSuccessors);
1323  }
1324 
1325  // Parse the properties, if not explicitly provided.
1326  if (propertiesAttribute) {
1327  result.propertiesAttr = *propertiesAttribute;
1328  } else if (consumeIf(Token::less)) {
1329  result.propertiesAttr = parseAttribute();
1330  if (!result.propertiesAttr)
1331  return failure();
1332  if (parseToken(Token::greater, "expected '>' to close properties"))
1333  return failure();
1334  }
1335  // Parse the region list, if not explicitly provided.
1336  if (!parsedRegions) {
1337  if (consumeIf(Token::l_paren)) {
1338  do {
1339  // Create temporary regions with the top level region as parent.
1340  result.regions.emplace_back(new Region(topLevelOp));
1341  if (parseRegion(*result.regions.back(), /*entryArguments=*/{}))
1342  return failure();
1343  } while (consumeIf(Token::comma));
1344  if (parseToken(Token::r_paren, "expected ')' to end region list"))
1345  return failure();
1346  }
1347  } else {
1348  result.addRegions(*parsedRegions);
1349  }
1350 
1351  // Parse the attributes, if not explicitly provided.
1352  if (!parsedAttributes) {
1353  if (getToken().is(Token::l_brace)) {
1354  if (parseAttributeDict(result.attributes))
1355  return failure();
1356  }
1357  } else {
1358  result.addAttributes(*parsedAttributes);
1359  }
1360 
1361  // Parse the operation type, if not explicitly provided.
1362  Location typeLoc = result.location;
1363  if (!parsedFnType) {
1364  if (parseToken(Token::colon, "expected ':' followed by operation type"))
1365  return failure();
1366 
1367  typeLoc = getEncodedSourceLocation(getToken().getLoc());
1368  auto type = parseType();
1369  if (!type)
1370  return failure();
1371  auto fnType = dyn_cast<FunctionType>(type);
1372  if (!fnType)
1373  return mlir::emitError(typeLoc, "expected function type");
1374 
1375  parsedFnType = fnType;
1376  }
1377 
1378  result.addTypes(parsedFnType->getResults());
1379 
1380  // Check that we have the right number of types for the operands.
1381  ArrayRef<Type> operandTypes = parsedFnType->getInputs();
1382  if (operandTypes.size() != parsedOperandUseInfo->size()) {
1383  auto plural = "s"[parsedOperandUseInfo->size() == 1];
1384  return mlir::emitError(typeLoc, "expected ")
1385  << parsedOperandUseInfo->size() << " operand type" << plural
1386  << " but had " << operandTypes.size();
1387  }
1388 
1389  // Resolve all of the operands.
1390  for (unsigned i = 0, e = parsedOperandUseInfo->size(); i != e; ++i) {
1391  result.operands.push_back(
1392  resolveSSAUse((*parsedOperandUseInfo)[i], operandTypes[i]));
1393  if (!result.operands.back())
1394  return failure();
1395  }
1396 
1397  return success();
1398 }
1399 
1400 Operation *OperationParser::parseGenericOperation() {
1401  // Get location information for the operation.
1402  auto srcLocation = getEncodedSourceLocation(getToken().getLoc());
1403 
1404  std::string name = getToken().getStringValue();
1405  if (name.empty())
1406  return (emitError("empty operation name is invalid"), nullptr);
1407  if (name.find('\0') != StringRef::npos)
1408  return (emitError("null character not allowed in operation name"), nullptr);
1409 
1410  consumeToken(Token::string);
1411 
1412  OperationState result(srcLocation, name);
1413  CleanupOpStateRegions guard{result};
1414 
1415  // Lazy load dialects in the context as needed.
1416  if (!result.name.isRegistered()) {
1417  StringRef dialectName = StringRef(name).split('.').first;
1418  if (!getContext()->getLoadedDialect(dialectName) &&
1419  !getContext()->getOrLoadDialect(dialectName)) {
1420  if (!getContext()->allowsUnregisteredDialects()) {
1421  // Emit an error if the dialect couldn't be loaded (i.e., it was not
1422  // registered) and unregistered dialects aren't allowed.
1423  emitError("operation being parsed with an unregistered dialect. If "
1424  "this is intended, please use -allow-unregistered-dialect "
1425  "with the MLIR tool used");
1426  return nullptr;
1427  }
1428  } else {
1429  // Reload the OperationName now that the dialect is loaded.
1430  result.name = OperationName(name, getContext());
1431  }
1432  }
1433 
1434  // If we are populating the parser state, start a new operation definition.
1435  if (state.asmState)
1436  state.asmState->startOperationDefinition(result.name);
1437 
1438  if (parseGenericOperationAfterOpName(result))
1439  return nullptr;
1440 
1441  // Operation::create() is not allowed to fail, however setting the properties
1442  // from an attribute is a failable operation. So we save the attribute here
1443  // and set it on the operation post-parsing.
1444  Attribute properties;
1445  std::swap(properties, result.propertiesAttr);
1446 
1447  // If we don't have properties in the textual IR, but the operation now has
1448  // support for properties, we support some backward-compatible generic syntax
1449  // for the operation and as such we accept inherent attributes mixed in the
1450  // dictionary of discardable attributes. We pre-validate these here because
1451  // invalid attributes can't be casted to the properties storage and will be
1452  // silently dropped. For example an attribute { foo = 0 : i32 } that is
1453  // declared as F32Attr in ODS would have a C++ type of FloatAttr in the
1454  // properties array. When setting it we would do something like:
1455  //
1456  // properties.foo = dyn_cast<FloatAttr>(fooAttr);
1457  //
1458  // which would end up with a null Attribute. The diagnostic from the verifier
1459  // would be "missing foo attribute" instead of something like "expects a 32
1460  // bits float attribute but got a 32 bits integer attribute".
1461  if (!properties && !result.getRawProperties()) {
1462  std::optional<RegisteredOperationName> info =
1463  result.name.getRegisteredInfo();
1464  if (info) {
1465  if (failed(info->verifyInherentAttrs(result.attributes, [&]() {
1466  return mlir::emitError(srcLocation) << "'" << name << "' op ";
1467  })))
1468  return nullptr;
1469  }
1470  }
1471 
1472  // Create the operation and try to parse a location for it.
1473  Operation *op = opBuilder.create(result);
1474  if (parseTrailingLocationSpecifier(op))
1475  return nullptr;
1476 
1477  // Try setting the properties for the operation, using a diagnostic to print
1478  // errors.
1479  if (properties) {
1480  auto emitError = [&]() {
1481  return mlir::emitError(srcLocation, "invalid properties ")
1482  << properties << " for op " << name << ": ";
1483  };
1484  if (failed(op->setPropertiesFromAttribute(properties, emitError)))
1485  return nullptr;
1486  }
1487 
1488  return op;
1489 }
1490 
1491 Operation *OperationParser::parseGenericOperation(Block *insertBlock,
1492  Block::iterator insertPt) {
1493  Token nameToken = getToken();
1494 
1495  OpBuilder::InsertionGuard restoreInsertionPoint(opBuilder);
1496  opBuilder.setInsertionPoint(insertBlock, insertPt);
1497  Operation *op = parseGenericOperation();
1498  if (!op)
1499  return nullptr;
1500 
1501  // If we are populating the parser asm state, finalize this operation
1502  // definition.
1503  if (state.asmState)
1504  state.asmState->finalizeOperationDefinition(
1505  op, nameToken.getLocRange(),
1506  /*endLoc=*/getLastToken().getEndLoc());
1507  return op;
1508 }
1509 
1510 namespace {
1511 class CustomOpAsmParser : public AsmParserImpl<OpAsmParser> {
1512 public:
1513  CustomOpAsmParser(
1514  SMLoc nameLoc, ArrayRef<OperationParser::ResultRecord> resultIDs,
1515  function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly,
1516  bool isIsolatedFromAbove, StringRef opName, OperationParser &parser)
1517  : AsmParserImpl<OpAsmParser>(nameLoc, parser), resultIDs(resultIDs),
1518  parseAssembly(parseAssembly), isIsolatedFromAbove(isIsolatedFromAbove),
1519  opName(opName), parser(parser) {
1520  (void)isIsolatedFromAbove; // Only used in assert, silence unused warning.
1521  }
1522 
1523  /// Parse an instance of the operation described by 'opDefinition' into the
1524  /// provided operation state.
1525  ParseResult parseOperation(OperationState &opState) {
1526  if (parseAssembly(*this, opState))
1527  return failure();
1528  // Verify that the parsed attributes does not have duplicate attributes.
1529  // This can happen if an attribute set during parsing is also specified in
1530  // the attribute dictionary in the assembly, or the attribute is set
1531  // multiple during parsing.
1532  std::optional<NamedAttribute> duplicate =
1533  opState.attributes.findDuplicate();
1534  if (duplicate)
1535  return emitError(getNameLoc(), "attribute '")
1536  << duplicate->getName().getValue()
1537  << "' occurs more than once in the attribute list";
1538  return success();
1539  }
1540 
1541  Operation *parseGenericOperation(Block *insertBlock,
1542  Block::iterator insertPt) final {
1543  return parser.parseGenericOperation(insertBlock, insertPt);
1544  }
1545 
1546  FailureOr<OperationName> parseCustomOperationName() final {
1547  return parser.parseCustomOperationName();
1548  }
1549 
1550  ParseResult parseGenericOperationAfterOpName(
1551  OperationState &result,
1552  std::optional<ArrayRef<UnresolvedOperand>> parsedUnresolvedOperands,
1553  std::optional<ArrayRef<Block *>> parsedSuccessors,
1554  std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
1555  std::optional<ArrayRef<NamedAttribute>> parsedAttributes,
1556  std::optional<Attribute> parsedPropertiesAttribute,
1557  std::optional<FunctionType> parsedFnType) final {
1558  return parser.parseGenericOperationAfterOpName(
1559  result, parsedUnresolvedOperands, parsedSuccessors, parsedRegions,
1560  parsedAttributes, parsedPropertiesAttribute, parsedFnType);
1561  }
1562  //===--------------------------------------------------------------------===//
1563  // Utilities
1564  //===--------------------------------------------------------------------===//
1565 
1566  /// Return the name of the specified result in the specified syntax, as well
1567  /// as the subelement in the name. For example, in this operation:
1568  ///
1569  /// %x, %y:2, %z = foo.op
1570  ///
1571  /// getResultName(0) == {"x", 0 }
1572  /// getResultName(1) == {"y", 0 }
1573  /// getResultName(2) == {"y", 1 }
1574  /// getResultName(3) == {"z", 0 }
1575  std::pair<StringRef, unsigned>
1576  getResultName(unsigned resultNo) const override {
1577  // Scan for the resultID that contains this result number.
1578  for (const auto &entry : resultIDs) {
1579  if (resultNo < std::get<1>(entry)) {
1580  // Don't pass on the leading %.
1581  StringRef name = std::get<0>(entry).drop_front();
1582  return {name, resultNo};
1583  }
1584  resultNo -= std::get<1>(entry);
1585  }
1586 
1587  // Invalid result number.
1588  return {"", ~0U};
1589  }
1590 
1591  /// Return the number of declared SSA results. This returns 4 for the foo.op
1592  /// example in the comment for getResultName.
1593  size_t getNumResults() const override {
1594  size_t count = 0;
1595  for (auto &entry : resultIDs)
1596  count += std::get<1>(entry);
1597  return count;
1598  }
1599 
1600  /// Emit a diagnostic at the specified location and return failure.
1601  InFlightDiagnostic emitError(SMLoc loc, const Twine &message) override {
1602  return AsmParserImpl<OpAsmParser>::emitError(loc, "custom op '" + opName +
1603  "' " + message);
1604  }
1605 
1606  //===--------------------------------------------------------------------===//
1607  // Operand Parsing
1608  //===--------------------------------------------------------------------===//
1609 
1610  /// Parse a single operand.
1611  ParseResult parseOperand(UnresolvedOperand &result,
1612  bool allowResultNumber = true) override {
1614  if (parser.parseSSAUse(useInfo, allowResultNumber))
1615  return failure();
1616 
1617  result = {useInfo.location, useInfo.name, useInfo.number};
1618  return success();
1619  }
1620 
1621  /// Parse a single operand if present.
1623  parseOptionalOperand(UnresolvedOperand &result,
1624  bool allowResultNumber = true) override {
1625  if (parser.getToken().isOrIsCodeCompletionFor(Token::percent_identifier))
1626  return parseOperand(result, allowResultNumber);
1627  return std::nullopt;
1628  }
1629 
1630  /// Parse zero or more SSA comma-separated operand references with a specified
1631  /// surrounding delimiter, and an optional required operand count.
1632  ParseResult parseOperandList(SmallVectorImpl<UnresolvedOperand> &result,
1633  Delimiter delimiter = Delimiter::None,
1634  bool allowResultNumber = true,
1635  int requiredOperandCount = -1) override {
1636  // The no-delimiter case has some special handling for better diagnostics.
1637  if (delimiter == Delimiter::None) {
1638  // parseCommaSeparatedList doesn't handle the missing case for "none",
1639  // so we handle it custom here.
1640  Token tok = parser.getToken();
1641  if (!tok.isOrIsCodeCompletionFor(Token::percent_identifier)) {
1642  // If we didn't require any operands or required exactly zero (weird)
1643  // then this is success.
1644  if (requiredOperandCount == -1 || requiredOperandCount == 0)
1645  return success();
1646 
1647  // Otherwise, try to produce a nice error message.
1648  if (tok.isAny(Token::l_paren, Token::l_square))
1649  return parser.emitError("unexpected delimiter");
1650  return parser.emitWrongTokenError("expected operand");
1651  }
1652  }
1653 
1654  auto parseOneOperand = [&]() -> ParseResult {
1655  return parseOperand(result.emplace_back(), allowResultNumber);
1656  };
1657 
1658  auto startLoc = parser.getToken().getLoc();
1659  if (parseCommaSeparatedList(delimiter, parseOneOperand, " in operand list"))
1660  return failure();
1661 
1662  // Check that we got the expected # of elements.
1663  if (requiredOperandCount != -1 &&
1664  result.size() != static_cast<size_t>(requiredOperandCount))
1665  return emitError(startLoc, "expected ")
1666  << requiredOperandCount << " operands";
1667  return success();
1668  }
1669 
1670  /// Resolve an operand to an SSA value, emitting an error on failure.
1671  ParseResult resolveOperand(const UnresolvedOperand &operand, Type type,
1672  SmallVectorImpl<Value> &result) override {
1673  if (auto value = parser.resolveSSAUse(operand, type)) {
1674  result.push_back(value);
1675  return success();
1676  }
1677  return failure();
1678  }
1679 
1680  /// Parse an AffineMap of SSA ids.
1681  ParseResult
1682  parseAffineMapOfSSAIds(SmallVectorImpl<UnresolvedOperand> &operands,
1683  Attribute &mapAttr, StringRef attrName,
1684  NamedAttrList &attrs, Delimiter delimiter) override {
1687 
1688  auto parseElement = [&](bool isSymbol) -> ParseResult {
1689  UnresolvedOperand operand;
1690  if (parseOperand(operand))
1691  return failure();
1692  if (isSymbol)
1693  symOperands.push_back(operand);
1694  else
1695  dimOperands.push_back(operand);
1696  return success();
1697  };
1698 
1699  AffineMap map;
1700  if (parser.parseAffineMapOfSSAIds(map, parseElement, delimiter))
1701  return failure();
1702  // Add AffineMap attribute.
1703  if (map) {
1704  mapAttr = AffineMapAttr::get(map);
1705  attrs.push_back(parser.builder.getNamedAttr(attrName, mapAttr));
1706  }
1707 
1708  // Add dim operands before symbol operands in 'operands'.
1709  operands.assign(dimOperands.begin(), dimOperands.end());
1710  operands.append(symOperands.begin(), symOperands.end());
1711  return success();
1712  }
1713 
1714  /// Parse an AffineExpr of SSA ids.
1715  ParseResult
1716  parseAffineExprOfSSAIds(SmallVectorImpl<UnresolvedOperand> &dimOperands,
1717  SmallVectorImpl<UnresolvedOperand> &symbOperands,
1718  AffineExpr &expr) override {
1719  auto parseElement = [&](bool isSymbol) -> ParseResult {
1720  UnresolvedOperand operand;
1721  if (parseOperand(operand))
1722  return failure();
1723  if (isSymbol)
1724  symbOperands.push_back(operand);
1725  else
1726  dimOperands.push_back(operand);
1727  return success();
1728  };
1729 
1730  return parser.parseAffineExprOfSSAIds(expr, parseElement);
1731  }
1732 
1733  //===--------------------------------------------------------------------===//
1734  // Argument Parsing
1735  //===--------------------------------------------------------------------===//
1736 
1737  /// Parse a single argument with the following syntax:
1738  ///
1739  /// `%ssaname : !type { optionalAttrDict} loc(optionalSourceLoc)`
1740  ///
1741  /// If `allowType` is false or `allowAttrs` are false then the respective
1742  /// parts of the grammar are not parsed.
1743  ParseResult parseArgument(Argument &result, bool allowType = false,
1744  bool allowAttrs = false) override {
1745  NamedAttrList attrs;
1746  if (parseOperand(result.ssaName, /*allowResultNumber=*/false) ||
1747  (allowType && parseColonType(result.type)) ||
1748  (allowAttrs && parseOptionalAttrDict(attrs)) ||
1749  parseOptionalLocationSpecifier(result.sourceLoc))
1750  return failure();
1751  result.attrs = attrs.getDictionary(getContext());
1752  return success();
1753  }
1754 
1755  /// Parse a single argument if present.
1756  OptionalParseResult parseOptionalArgument(Argument &result, bool allowType,
1757  bool allowAttrs) override {
1758  if (parser.getToken().is(Token::percent_identifier))
1759  return parseArgument(result, allowType, allowAttrs);
1760  return std::nullopt;
1761  }
1762 
1763  ParseResult parseArgumentList(SmallVectorImpl<Argument> &result,
1764  Delimiter delimiter, bool allowType,
1765  bool allowAttrs) override {
1766  // The no-delimiter case has some special handling for the empty case.
1767  if (delimiter == Delimiter::None &&
1768  parser.getToken().isNot(Token::percent_identifier))
1769  return success();
1770 
1771  auto parseOneArgument = [&]() -> ParseResult {
1772  return parseArgument(result.emplace_back(), allowType, allowAttrs);
1773  };
1774  return parseCommaSeparatedList(delimiter, parseOneArgument,
1775  " in argument list");
1776  }
1777 
1778  //===--------------------------------------------------------------------===//
1779  // Region Parsing
1780  //===--------------------------------------------------------------------===//
1781 
1782  /// Parse a region that takes `arguments` of `argTypes` types. This
1783  /// effectively defines the SSA values of `arguments` and assigns their type.
1784  ParseResult parseRegion(Region &region, ArrayRef<Argument> arguments,
1785  bool enableNameShadowing) override {
1786  // Try to parse the region.
1787  (void)isIsolatedFromAbove;
1788  assert((!enableNameShadowing || isIsolatedFromAbove) &&
1789  "name shadowing is only allowed on isolated regions");
1790  if (parser.parseRegion(region, arguments, enableNameShadowing))
1791  return failure();
1792  return success();
1793  }
1794 
1795  /// Parses a region if present.
1796  OptionalParseResult parseOptionalRegion(Region &region,
1797  ArrayRef<Argument> arguments,
1798  bool enableNameShadowing) override {
1799  if (parser.getToken().isNot(Token::l_brace))
1800  return std::nullopt;
1801  return parseRegion(region, arguments, enableNameShadowing);
1802  }
1803 
1804  /// Parses a region if present. If the region is present, a new region is
1805  /// allocated and placed in `region`. If no region is present, `region`
1806  /// remains untouched.
1808  parseOptionalRegion(std::unique_ptr<Region> &region,
1809  ArrayRef<Argument> arguments,
1810  bool enableNameShadowing = false) override {
1811  if (parser.getToken().isNot(Token::l_brace))
1812  return std::nullopt;
1813  std::unique_ptr<Region> newRegion = std::make_unique<Region>();
1814  if (parseRegion(*newRegion, arguments, enableNameShadowing))
1815  return failure();
1816 
1817  region = std::move(newRegion);
1818  return success();
1819  }
1820 
1821  //===--------------------------------------------------------------------===//
1822  // Successor Parsing
1823  //===--------------------------------------------------------------------===//
1824 
1825  /// Parse a single operation successor.
1826  ParseResult parseSuccessor(Block *&dest) override {
1827  return parser.parseSuccessor(dest);
1828  }
1829 
1830  /// Parse an optional operation successor and its operand list.
1831  OptionalParseResult parseOptionalSuccessor(Block *&dest) override {
1832  if (!parser.getToken().isOrIsCodeCompletionFor(Token::caret_identifier))
1833  return std::nullopt;
1834  return parseSuccessor(dest);
1835  }
1836 
1837  /// Parse a single operation successor and its operand list.
1838  ParseResult
1839  parseSuccessorAndUseList(Block *&dest,
1840  SmallVectorImpl<Value> &operands) override {
1841  if (parseSuccessor(dest))
1842  return failure();
1843 
1844  // Handle optional arguments.
1845  if (succeeded(parseOptionalLParen()) &&
1846  (parser.parseOptionalSSAUseAndTypeList(operands) || parseRParen())) {
1847  return failure();
1848  }
1849  return success();
1850  }
1851 
1852  //===--------------------------------------------------------------------===//
1853  // Type Parsing
1854  //===--------------------------------------------------------------------===//
1855 
1856  /// Parse a list of assignments of the form
1857  /// (%x1 = %y1, %x2 = %y2, ...).
1858  OptionalParseResult parseOptionalAssignmentList(
1860  SmallVectorImpl<UnresolvedOperand> &rhs) override {
1861  if (failed(parseOptionalLParen()))
1862  return std::nullopt;
1863 
1864  auto parseElt = [&]() -> ParseResult {
1865  if (parseArgument(lhs.emplace_back()) || parseEqual() ||
1866  parseOperand(rhs.emplace_back()))
1867  return failure();
1868  return success();
1869  };
1870  return parser.parseCommaSeparatedListUntil(Token::r_paren, parseElt);
1871  }
1872 
1873  /// Parse a loc(...) specifier if present, filling in result if so.
1874  ParseResult
1875  parseOptionalLocationSpecifier(std::optional<Location> &result) override {
1876  // If there is a 'loc' we parse a trailing location.
1877  if (!parser.consumeIf(Token::kw_loc))
1878  return success();
1879  LocationAttr directLoc;
1880  if (parser.parseToken(Token::l_paren, "expected '(' in location"))
1881  return failure();
1882 
1883  Token tok = parser.getToken();
1884 
1885  // Check to see if we are parsing a location alias.
1886  // Otherwise, we parse the location directly.
1887  if (tok.is(Token::hash_identifier)) {
1888  if (parser.parseLocationAlias(directLoc))
1889  return failure();
1890  } else if (parser.parseLocationInstance(directLoc)) {
1891  return failure();
1892  }
1893 
1894  if (parser.parseToken(Token::r_paren, "expected ')' in location"))
1895  return failure();
1896 
1897  result = directLoc;
1898  return success();
1899  }
1900 
1901 private:
1902  /// Information about the result name specifiers.
1904 
1905  /// The abstract information of the operation.
1906  function_ref<ParseResult(OpAsmParser &, OperationState &)> parseAssembly;
1907  bool isIsolatedFromAbove;
1908  StringRef opName;
1909 
1910  /// The backing operation parser.
1911  OperationParser &parser;
1912 };
1913 } // namespace
1914 
1915 FailureOr<OperationName> OperationParser::parseCustomOperationName() {
1916  Token nameTok = getToken();
1917  StringRef opName = nameTok.getSpelling();
1918  if (opName.empty())
1919  return (emitError("empty operation name is invalid"), failure());
1920  consumeToken();
1921 
1922  // Check to see if this operation name is already registered.
1923  std::optional<RegisteredOperationName> opInfo =
1925  if (opInfo)
1926  return *opInfo;
1927 
1928  // If the operation doesn't have a dialect prefix try using the default
1929  // dialect.
1930  auto opNameSplit = opName.split('.');
1931  StringRef dialectName = opNameSplit.first;
1932  std::string opNameStorage;
1933  if (opNameSplit.second.empty()) {
1934  // If the name didn't have a prefix, check for a code completion request.
1935  if (getToken().isCodeCompletion() && opName.back() == '.')
1936  return codeCompleteOperationName(dialectName);
1937 
1938  dialectName = getState().defaultDialectStack.back();
1939  opNameStorage = (dialectName + "." + opName).str();
1940  opName = opNameStorage;
1941  }
1942 
1943  // Try to load the dialect before returning the operation name to make sure
1944  // the operation has a chance to be registered.
1945  getContext()->getOrLoadDialect(dialectName);
1946  return OperationName(opName, getContext());
1947 }
1948 
1949 Operation *
1950 OperationParser::parseCustomOperation(ArrayRef<ResultRecord> resultIDs) {
1951  SMLoc opLoc = getToken().getLoc();
1952  StringRef originalOpName = getTokenSpelling();
1953 
1954  FailureOr<OperationName> opNameInfo = parseCustomOperationName();
1955  if (failed(opNameInfo))
1956  return nullptr;
1957  StringRef opName = opNameInfo->getStringRef();
1958 
1959  // This is the actual hook for the custom op parsing, usually implemented by
1960  // the op itself (`Op::parse()`). We retrieve it either from the
1961  // RegisteredOperationName or from the Dialect.
1962  OperationName::ParseAssemblyFn parseAssemblyFn;
1963  bool isIsolatedFromAbove = false;
1964 
1965  StringRef defaultDialect = "";
1966  if (auto opInfo = opNameInfo->getRegisteredInfo()) {
1967  parseAssemblyFn = opInfo->getParseAssemblyFn();
1968  isIsolatedFromAbove = opInfo->hasTrait<OpTrait::IsIsolatedFromAbove>();
1969  auto *iface = opInfo->getInterface<OpAsmOpInterface>();
1970  if (iface && !iface->getDefaultDialect().empty())
1971  defaultDialect = iface->getDefaultDialect();
1972  } else {
1973  std::optional<Dialect::ParseOpHook> dialectHook;
1974  Dialect *dialect = opNameInfo->getDialect();
1975  if (!dialect) {
1977  emitError(opLoc) << "Dialect `" << opNameInfo->getDialectNamespace()
1978  << "' not found for custom op '" << originalOpName
1979  << "' ";
1980  if (originalOpName != opName)
1981  diag << " (tried '" << opName << "' as well)";
1982  auto &note = diag.attachNote();
1983  note << "Registered dialects: ";
1984  llvm::interleaveComma(getContext()->getAvailableDialects(), note,
1985  [&](StringRef dialect) { note << dialect; });
1986  note << " ; for more info on dialect registration see "
1987  "https://mlir.llvm.org/getting_started/Faq/"
1988  "#registered-loaded-dependent-whats-up-with-dialects-management";
1989  return nullptr;
1990  }
1991  dialectHook = dialect->getParseOperationHook(opName);
1992  if (!dialectHook) {
1994  emitError(opLoc) << "custom op '" << originalOpName << "' is unknown";
1995  if (originalOpName != opName)
1996  diag << " (tried '" << opName << "' as well)";
1997  return nullptr;
1998  }
1999  parseAssemblyFn = *dialectHook;
2000  }
2001  getState().defaultDialectStack.push_back(defaultDialect);
2002  auto restoreDefaultDialect = llvm::make_scope_exit(
2003  [&]() { getState().defaultDialectStack.pop_back(); });
2004 
2005  // If the custom op parser crashes, produce some indication to help
2006  // debugging.
2007  llvm::PrettyStackTraceFormat fmt("MLIR Parser: custom op parser '%s'",
2008  opNameInfo->getIdentifier().data());
2009 
2010  // Get location information for the operation.
2011  auto srcLocation = getEncodedSourceLocation(opLoc);
2012  OperationState opState(srcLocation, *opNameInfo);
2013 
2014  // If we are populating the parser state, start a new operation definition.
2015  if (state.asmState)
2016  state.asmState->startOperationDefinition(opState.name);
2017 
2018  // Have the op implementation take a crack and parsing this.
2019  CleanupOpStateRegions guard{opState};
2020  CustomOpAsmParser opAsmParser(opLoc, resultIDs, parseAssemblyFn,
2021  isIsolatedFromAbove, opName, *this);
2022  if (opAsmParser.parseOperation(opState))
2023  return nullptr;
2024 
2025  // If it emitted an error, we failed.
2026  if (opAsmParser.didEmitError())
2027  return nullptr;
2028 
2029  Attribute properties = opState.propertiesAttr;
2030  opState.propertiesAttr = Attribute{};
2031 
2032  // Otherwise, create the operation and try to parse a location for it.
2033  Operation *op = opBuilder.create(opState);
2034  if (parseTrailingLocationSpecifier(op))
2035  return nullptr;
2036 
2037  // Try setting the properties for the operation.
2038  if (properties) {
2039  auto emitError = [&]() {
2040  return mlir::emitError(srcLocation, "invalid properties ")
2041  << properties << " for op " << op->getName().getStringRef()
2042  << ": ";
2043  };
2044  if (failed(op->setPropertiesFromAttribute(properties, emitError)))
2045  return nullptr;
2046  }
2047  return op;
2048 }
2049 
2050 ParseResult OperationParser::parseLocationAlias(LocationAttr &loc) {
2051  Token tok = getToken();
2052  consumeToken(Token::hash_identifier);
2053  StringRef identifier = tok.getSpelling().drop_front();
2054  if (identifier.contains('.')) {
2055  return emitError(tok.getLoc())
2056  << "expected location, but found dialect attribute: '#" << identifier
2057  << "'";
2058  }
2059  if (state.asmState)
2060  state.asmState->addAttrAliasUses(identifier, tok.getLocRange());
2061 
2062  // If this alias can be resolved, do it now.
2063  Attribute attr = state.symbols.attributeAliasDefinitions.lookup(identifier);
2064  if (attr) {
2065  if (!(loc = dyn_cast<LocationAttr>(attr)))
2066  return emitError(tok.getLoc())
2067  << "expected location, but found '" << attr << "'";
2068  } else {
2069  // Otherwise, remember this operation and resolve its location later.
2070  // In the meantime, use a special OpaqueLoc as a marker.
2071  loc = OpaqueLoc::get(deferredLocsReferences.size(),
2072  TypeID::get<DeferredLocInfo *>(),
2074  deferredLocsReferences.push_back(DeferredLocInfo{tok.getLoc(), identifier});
2075  }
2076  return success();
2077 }
2078 
2080 OperationParser::parseTrailingLocationSpecifier(OpOrArgument opOrArgument) {
2081  // If there is a 'loc' we parse a trailing location.
2082  if (!consumeIf(Token::kw_loc))
2083  return success();
2084  if (parseToken(Token::l_paren, "expected '(' in location"))
2085  return failure();
2086  Token tok = getToken();
2087 
2088  // Check to see if we are parsing a location alias.
2089  // Otherwise, we parse the location directly.
2090  LocationAttr directLoc;
2091  if (tok.is(Token::hash_identifier)) {
2092  if (parseLocationAlias(directLoc))
2093  return failure();
2094  } else if (parseLocationInstance(directLoc)) {
2095  return failure();
2096  }
2097 
2098  if (parseToken(Token::r_paren, "expected ')' in location"))
2099  return failure();
2100 
2101  if (auto *op = llvm::dyn_cast_if_present<Operation *>(opOrArgument))
2102  op->setLoc(directLoc);
2103  else
2104  opOrArgument.get<BlockArgument>().setLoc(directLoc);
2105  return success();
2106 }
2107 
2108 //===----------------------------------------------------------------------===//
2109 // Region Parsing
2110 //===----------------------------------------------------------------------===//
2111 
2112 ParseResult OperationParser::parseRegion(Region &region,
2113  ArrayRef<Argument> entryArguments,
2114  bool isIsolatedNameScope) {
2115  // Parse the '{'.
2116  Token lBraceTok = getToken();
2117  if (parseToken(Token::l_brace, "expected '{' to begin a region"))
2118  return failure();
2119 
2120  // If we are populating the parser state, start a new region definition.
2121  if (state.asmState)
2122  state.asmState->startRegionDefinition();
2123 
2124  // Parse the region body.
2125  if ((!entryArguments.empty() || getToken().isNot(Token::r_brace)) &&
2126  parseRegionBody(region, lBraceTok.getLoc(), entryArguments,
2127  isIsolatedNameScope)) {
2128  return failure();
2129  }
2130  consumeToken(Token::r_brace);
2131 
2132  // If we are populating the parser state, finalize this region.
2133  if (state.asmState)
2134  state.asmState->finalizeRegionDefinition();
2135 
2136  return success();
2137 }
2138 
2139 ParseResult OperationParser::parseRegionBody(Region &region, SMLoc startLoc,
2140  ArrayRef<Argument> entryArguments,
2141  bool isIsolatedNameScope) {
2142  auto currentPt = opBuilder.saveInsertionPoint();
2143 
2144  // Push a new named value scope.
2145  pushSSANameScope(isIsolatedNameScope);
2146 
2147  // Parse the first block directly to allow for it to be unnamed.
2148  auto owningBlock = std::make_unique<Block>();
2149  Block *block = owningBlock.get();
2150 
2151  // If this block is not defined in the source file, add a definition for it
2152  // now in the assembly state. Blocks with a name will be defined when the name
2153  // is parsed.
2154  if (state.asmState && getToken().isNot(Token::caret_identifier))
2155  state.asmState->addDefinition(block, startLoc);
2156 
2157  // Add arguments to the entry block if we had the form with explicit names.
2158  if (!entryArguments.empty() && !entryArguments[0].ssaName.name.empty()) {
2159  // If we had named arguments, then don't allow a block name.
2160  if (getToken().is(Token::caret_identifier))
2161  return emitError("invalid block name in region with named arguments");
2162 
2163  for (auto &entryArg : entryArguments) {
2164  auto &argInfo = entryArg.ssaName;
2165 
2166  // Ensure that the argument was not already defined.
2167  if (auto defLoc = getReferenceLoc(argInfo.name, argInfo.number)) {
2168  return emitError(argInfo.location, "region entry argument '" +
2169  argInfo.name +
2170  "' is already in use")
2171  .attachNote(getEncodedSourceLocation(*defLoc))
2172  << "previously referenced here";
2173  }
2174  Location loc = entryArg.sourceLoc.has_value()
2175  ? *entryArg.sourceLoc
2176  : getEncodedSourceLocation(argInfo.location);
2177  BlockArgument arg = block->addArgument(entryArg.type, loc);
2178 
2179  // Add a definition of this arg to the assembly state if provided.
2180  if (state.asmState)
2181  state.asmState->addDefinition(arg, argInfo.location);
2182 
2183  // Record the definition for this argument.
2184  if (addDefinition(argInfo, arg))
2185  return failure();
2186  }
2187  }
2188 
2189  if (parseBlock(block))
2190  return failure();
2191 
2192  // Verify that no other arguments were parsed.
2193  if (!entryArguments.empty() &&
2194  block->getNumArguments() > entryArguments.size()) {
2195  return emitError("entry block arguments were already defined");
2196  }
2197 
2198  // Parse the rest of the region.
2199  region.push_back(owningBlock.release());
2200  while (getToken().isNot(Token::r_brace)) {
2201  Block *newBlock = nullptr;
2202  if (parseBlock(newBlock))
2203  return failure();
2204  region.push_back(newBlock);
2205  }
2206 
2207  // Pop the SSA value scope for this region.
2208  if (popSSANameScope())
2209  return failure();
2210 
2211  // Reset the original insertion point.
2212  opBuilder.restoreInsertionPoint(currentPt);
2213  return success();
2214 }
2215 
2216 //===----------------------------------------------------------------------===//
2217 // Block Parsing
2218 //===----------------------------------------------------------------------===//
2219 
2220 /// Block declaration.
2221 ///
2222 /// block ::= block-label? operation*
2223 /// block-label ::= block-id block-arg-list? `:`
2224 /// block-id ::= caret-id
2225 /// block-arg-list ::= `(` ssa-id-and-type-list? `)`
2226 ///
2227 ParseResult OperationParser::parseBlock(Block *&block) {
2228  // The first block of a region may already exist, if it does the caret
2229  // identifier is optional.
2230  if (block && getToken().isNot(Token::caret_identifier))
2231  return parseBlockBody(block);
2232 
2233  SMLoc nameLoc = getToken().getLoc();
2234  auto name = getTokenSpelling();
2235  if (parseToken(Token::caret_identifier, "expected block name"))
2236  return failure();
2237 
2238  // Define the block with the specified name.
2239  auto &blockAndLoc = getBlockInfoByName(name);
2240  blockAndLoc.loc = nameLoc;
2241 
2242  // Use a unique pointer for in-flight block being parsed. Release ownership
2243  // only in the case of a successful parse. This ensures that the Block
2244  // allocated is released if the parse fails and control returns early.
2245  std::unique_ptr<Block> inflightBlock;
2246  auto cleanupOnFailure = llvm::make_scope_exit([&] {
2247  if (inflightBlock)
2248  inflightBlock->dropAllDefinedValueUses();
2249  });
2250 
2251  // If a block has yet to be set, this is a new definition. If the caller
2252  // provided a block, use it. Otherwise create a new one.
2253  if (!blockAndLoc.block) {
2254  if (block) {
2255  blockAndLoc.block = block;
2256  } else {
2257  inflightBlock = std::make_unique<Block>();
2258  blockAndLoc.block = inflightBlock.get();
2259  }
2260 
2261  // Otherwise, the block has a forward declaration. Forward declarations are
2262  // removed once defined, so if we are defining a existing block and it is
2263  // not a forward declaration, then it is a redeclaration. Fail if the block
2264  // was already defined.
2265  } else if (!eraseForwardRef(blockAndLoc.block)) {
2266  return emitError(nameLoc, "redefinition of block '") << name << "'";
2267  } else {
2268  // This was a forward reference block that is now floating. Keep track of it
2269  // as inflight in case of error, so that it gets cleaned up properly.
2270  inflightBlock.reset(blockAndLoc.block);
2271  }
2272 
2273  // Populate the high level assembly state if necessary.
2274  if (state.asmState)
2275  state.asmState->addDefinition(blockAndLoc.block, nameLoc);
2276  block = blockAndLoc.block;
2277 
2278  // If an argument list is present, parse it.
2279  if (getToken().is(Token::l_paren))
2280  if (parseOptionalBlockArgList(block))
2281  return failure();
2282  if (parseToken(Token::colon, "expected ':' after block name"))
2283  return failure();
2284 
2285  // Parse the body of the block.
2286  ParseResult res = parseBlockBody(block);
2287 
2288  // If parsing was successful, drop the inflight block. We relinquish ownership
2289  // back up to the caller.
2290  if (succeeded(res))
2291  (void)inflightBlock.release();
2292  return res;
2293 }
2294 
2295 ParseResult OperationParser::parseBlockBody(Block *block) {
2296  // Set the insertion point to the end of the block to parse.
2297  opBuilder.setInsertionPointToEnd(block);
2298 
2299  // Parse the list of operations that make up the body of the block.
2300  while (getToken().isNot(Token::caret_identifier, Token::r_brace))
2301  if (parseOperation())
2302  return failure();
2303 
2304  return success();
2305 }
2306 
2307 /// Get the block with the specified name, creating it if it doesn't already
2308 /// exist. The location specified is the point of use, which allows
2309 /// us to diagnose references to blocks that are not defined precisely.
2310 Block *OperationParser::getBlockNamed(StringRef name, SMLoc loc) {
2311  BlockDefinition &blockDef = getBlockInfoByName(name);
2312  if (!blockDef.block) {
2313  blockDef = {new Block(), loc};
2314  insertForwardRef(blockDef.block, blockDef.loc);
2315  }
2316 
2317  // Populate the high level assembly state if necessary.
2318  if (state.asmState)
2319  state.asmState->addUses(blockDef.block, loc);
2320 
2321  return blockDef.block;
2322 }
2323 
2324 /// Parse a (possibly empty) list of SSA operands with types as block arguments
2325 /// enclosed in parentheses.
2326 ///
2327 /// value-id-and-type-list ::= value-id-and-type (`,` ssa-id-and-type)*
2328 /// block-arg-list ::= `(` value-id-and-type-list? `)`
2329 ///
2330 ParseResult OperationParser::parseOptionalBlockArgList(Block *owner) {
2331  if (getToken().is(Token::r_brace))
2332  return success();
2333 
2334  // If the block already has arguments, then we're handling the entry block.
2335  // Parse and register the names for the arguments, but do not add them.
2336  bool definingExistingArgs = owner->getNumArguments() != 0;
2337  unsigned nextArgument = 0;
2338 
2339  return parseCommaSeparatedList(Delimiter::Paren, [&]() -> ParseResult {
2340  return parseSSADefOrUseAndType(
2341  [&](UnresolvedOperand useInfo, Type type) -> ParseResult {
2342  BlockArgument arg;
2343 
2344  // If we are defining existing arguments, ensure that the argument
2345  // has already been created with the right type.
2346  if (definingExistingArgs) {
2347  // Otherwise, ensure that this argument has already been created.
2348  if (nextArgument >= owner->getNumArguments())
2349  return emitError("too many arguments specified in argument list");
2350 
2351  // Finally, make sure the existing argument has the correct type.
2352  arg = owner->getArgument(nextArgument++);
2353  if (arg.getType() != type)
2354  return emitError("argument and block argument type mismatch");
2355  } else {
2356  auto loc = getEncodedSourceLocation(useInfo.location);
2357  arg = owner->addArgument(type, loc);
2358  }
2359 
2360  // If the argument has an explicit loc(...) specifier, parse and apply
2361  // it.
2362  if (parseTrailingLocationSpecifier(arg))
2363  return failure();
2364 
2365  // Mark this block argument definition in the parser state if it was
2366  // provided.
2367  if (state.asmState)
2368  state.asmState->addDefinition(arg, useInfo.location);
2369 
2370  return addDefinition(useInfo, arg);
2371  });
2372  });
2373 }
2374 
2375 //===----------------------------------------------------------------------===//
2376 // Code Completion
2377 //===----------------------------------------------------------------------===//
2378 
2379 ParseResult OperationParser::codeCompleteSSAUse() {
2380  std::string detailData;
2381  llvm::raw_string_ostream detailOS(detailData);
2382  for (IsolatedSSANameScope &scope : isolatedNameScopes) {
2383  for (auto &it : scope.values) {
2384  if (it.second.empty())
2385  continue;
2386  Value frontValue = it.second.front().value;
2387 
2388  // If the value isn't a forward reference, we also add the name of the op
2389  // to the detail.
2390  if (auto result = dyn_cast<OpResult>(frontValue)) {
2391  if (!forwardRefPlaceholders.count(result))
2392  detailOS << result.getOwner()->getName() << ": ";
2393  } else {
2394  detailOS << "arg #" << cast<BlockArgument>(frontValue).getArgNumber()
2395  << ": ";
2396  }
2397 
2398  // Emit the type of the values to aid with completion selection.
2399  detailOS << frontValue.getType();
2400 
2401  // FIXME: We should define a policy for packed values, e.g. with a limit
2402  // on the detail size, but it isn't clear what would be useful right now.
2403  // For now we just only emit the first type.
2404  if (it.second.size() > 1)
2405  detailOS << ", ...";
2406 
2407  state.codeCompleteContext->appendSSAValueCompletion(
2408  it.getKey(), std::move(detailOS.str()));
2409  }
2410  }
2411 
2412  return failure();
2413 }
2414 
2415 ParseResult OperationParser::codeCompleteBlock() {
2416  // Don't provide completions if the token isn't empty, e.g. this avoids
2417  // weirdness when we encounter a `.` within the identifier.
2418  StringRef spelling = getTokenSpelling();
2419  if (!(spelling.empty() || spelling == "^"))
2420  return failure();
2421 
2422  for (const auto &it : blocksByName.back())
2423  state.codeCompleteContext->appendBlockCompletion(it.getFirst());
2424  return failure();
2425 }
2426 
2427 //===----------------------------------------------------------------------===//
2428 // Top-level entity parsing.
2429 //===----------------------------------------------------------------------===//
2430 
2431 namespace {
2432 /// This parser handles entities that are only valid at the top level of the
2433 /// file.
2434 class TopLevelOperationParser : public Parser {
2435 public:
2436  explicit TopLevelOperationParser(ParserState &state) : Parser(state) {}
2437 
2438  /// Parse a set of operations into the end of the given Block.
2439  ParseResult parse(Block *topLevelBlock, Location parserLoc);
2440 
2441 private:
2442  /// Parse an attribute alias declaration.
2443  ///
2444  /// attribute-alias-def ::= '#' alias-name `=` attribute-value
2445  ///
2446  ParseResult parseAttributeAliasDef();
2447 
2448  /// Parse a type alias declaration.
2449  ///
2450  /// type-alias-def ::= '!' alias-name `=` type
2451  ///
2452  ParseResult parseTypeAliasDef();
2453 
2454  /// Parse a top-level file metadata dictionary.
2455  ///
2456  /// file-metadata-dict ::= '{-#' file-metadata-entry* `#-}'
2457  ///
2458  ParseResult parseFileMetadataDictionary();
2459 
2460  /// Parse a resource metadata dictionary.
2461  ParseResult parseResourceFileMetadata(
2462  function_ref<ParseResult(StringRef, SMLoc)> parseBody);
2463  ParseResult parseDialectResourceFileMetadata();
2464  ParseResult parseExternalResourceFileMetadata();
2465 };
2466 
2467 /// This class represents an implementation of a resource entry for the MLIR
2468 /// textual format.
2469 class ParsedResourceEntry : public AsmParsedResourceEntry {
2470 public:
2471  ParsedResourceEntry(StringRef key, SMLoc keyLoc, Token value, Parser &p)
2472  : key(key), keyLoc(keyLoc), value(value), p(p) {}
2473  ~ParsedResourceEntry() override = default;
2474 
2475  StringRef getKey() const final { return key; }
2476 
2477  InFlightDiagnostic emitError() const final { return p.emitError(keyLoc); }
2478 
2479  AsmResourceEntryKind getKind() const final {
2480  if (value.isAny(Token::kw_true, Token::kw_false))
2482  return value.getSpelling().starts_with("\"0x")
2485  }
2486 
2487  FailureOr<bool> parseAsBool() const final {
2488  if (value.is(Token::kw_true))
2489  return true;
2490  if (value.is(Token::kw_false))
2491  return false;
2492  return p.emitError(value.getLoc(),
2493  "expected 'true' or 'false' value for key '" + key +
2494  "'");
2495  }
2496 
2497  FailureOr<std::string> parseAsString() const final {
2498  if (value.isNot(Token::string))
2499  return p.emitError(value.getLoc(),
2500  "expected string value for key '" + key + "'");
2501  return value.getStringValue();
2502  }
2503 
2505  parseAsBlob(BlobAllocatorFn allocator) const final {
2506  // Blob data within then textual format is represented as a hex string.
2507  // TODO: We could avoid an additional alloc+copy here if we pre-allocated
2508  // the buffer to use during hex processing.
2509  std::optional<std::string> blobData =
2510  value.is(Token::string) ? value.getHexStringValue() : std::nullopt;
2511  if (!blobData)
2512  return p.emitError(value.getLoc(),
2513  "expected hex string blob for key '" + key + "'");
2514 
2515  // Extract the alignment of the blob data, which gets stored at the
2516  // beginning of the string.
2517  if (blobData->size() < sizeof(uint32_t)) {
2518  return p.emitError(value.getLoc(),
2519  "expected hex string blob for key '" + key +
2520  "' to encode alignment in first 4 bytes");
2521  }
2522  llvm::support::ulittle32_t align;
2523  memcpy(&align, blobData->data(), sizeof(uint32_t));
2524  if (align && !llvm::isPowerOf2_32(align)) {
2525  return p.emitError(value.getLoc(),
2526  "expected hex string blob for key '" + key +
2527  "' to encode alignment in first 4 bytes, but got "
2528  "non-power-of-2 value: " +
2529  Twine(align));
2530  }
2531 
2532  // Get the data portion of the blob.
2533  StringRef data = StringRef(*blobData).drop_front(sizeof(uint32_t));
2534  if (data.empty())
2535  return AsmResourceBlob();
2536 
2537  // Allocate memory for the blob using the provided allocator and copy the
2538  // data into it.
2539  AsmResourceBlob blob = allocator(data.size(), align);
2540  assert(llvm::isAddrAligned(llvm::Align(align), blob.getData().data()) &&
2541  blob.isMutable() &&
2542  "blob allocator did not return a properly aligned address");
2543  memcpy(blob.getMutableData().data(), data.data(), data.size());
2544  return blob;
2545  }
2546 
2547 private:
2548  StringRef key;
2549  SMLoc keyLoc;
2550  Token value;
2551  Parser &p;
2552 };
2553 } // namespace
2554 
2555 ParseResult TopLevelOperationParser::parseAttributeAliasDef() {
2556  assert(getToken().is(Token::hash_identifier));
2557  StringRef aliasName = getTokenSpelling().drop_front();
2558 
2559  // Check for redefinitions.
2560  if (state.symbols.attributeAliasDefinitions.count(aliasName) > 0)
2561  return emitError("redefinition of attribute alias id '" + aliasName + "'");
2562 
2563  // Make sure this isn't invading the dialect attribute namespace.
2564  if (aliasName.contains('.'))
2565  return emitError("attribute names with a '.' are reserved for "
2566  "dialect-defined names");
2567 
2568  SMRange location = getToken().getLocRange();
2569  consumeToken(Token::hash_identifier);
2570 
2571  // Parse the '='.
2572  if (parseToken(Token::equal, "expected '=' in attribute alias definition"))
2573  return failure();
2574 
2575  // Parse the attribute value.
2576  Attribute attr = parseAttribute();
2577  if (!attr)
2578  return failure();
2579 
2580  // Register this alias with the parser state.
2581  if (state.asmState)
2582  state.asmState->addAttrAliasDefinition(aliasName, location, attr);
2583  state.symbols.attributeAliasDefinitions[aliasName] = attr;
2584  return success();
2585 }
2586 
2587 ParseResult TopLevelOperationParser::parseTypeAliasDef() {
2588  assert(getToken().is(Token::exclamation_identifier));
2589  StringRef aliasName = getTokenSpelling().drop_front();
2590 
2591  // Check for redefinitions.
2592  if (state.symbols.typeAliasDefinitions.count(aliasName) > 0)
2593  return emitError("redefinition of type alias id '" + aliasName + "'");
2594 
2595  // Make sure this isn't invading the dialect type namespace.
2596  if (aliasName.contains('.'))
2597  return emitError("type names with a '.' are reserved for "
2598  "dialect-defined names");
2599 
2600  SMRange location = getToken().getLocRange();
2601  consumeToken(Token::exclamation_identifier);
2602 
2603  // Parse the '='.
2604  if (parseToken(Token::equal, "expected '=' in type alias definition"))
2605  return failure();
2606 
2607  // Parse the type.
2608  Type aliasedType = parseType();
2609  if (!aliasedType)
2610  return failure();
2611 
2612  // Register this alias with the parser state.
2613  if (state.asmState)
2614  state.asmState->addTypeAliasDefinition(aliasName, location, aliasedType);
2615  state.symbols.typeAliasDefinitions.try_emplace(aliasName, aliasedType);
2616  return success();
2617 }
2618 
2619 ParseResult TopLevelOperationParser::parseFileMetadataDictionary() {
2620  consumeToken(Token::file_metadata_begin);
2621  return parseCommaSeparatedListUntil(
2622  Token::file_metadata_end, [&]() -> ParseResult {
2623  // Parse the key of the metadata dictionary.
2624  SMLoc keyLoc = getToken().getLoc();
2625  StringRef key;
2626  if (failed(parseOptionalKeyword(&key)))
2627  return emitError("expected identifier key in file "
2628  "metadata dictionary");
2629  if (parseToken(Token::colon, "expected ':'"))
2630  return failure();
2631 
2632  // Process the metadata entry.
2633  if (key == "dialect_resources")
2634  return parseDialectResourceFileMetadata();
2635  if (key == "external_resources")
2636  return parseExternalResourceFileMetadata();
2637  return emitError(keyLoc, "unknown key '" + key +
2638  "' in file metadata dictionary");
2639  });
2640 }
2641 
2642 ParseResult TopLevelOperationParser::parseResourceFileMetadata(
2643  function_ref<ParseResult(StringRef, SMLoc)> parseBody) {
2644  if (parseToken(Token::l_brace, "expected '{'"))
2645  return failure();
2646 
2647  return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2648  // Parse the top-level name entry.
2649  SMLoc nameLoc = getToken().getLoc();
2650  StringRef name;
2651  if (failed(parseOptionalKeyword(&name)))
2652  return emitError("expected identifier key for 'resource' entry");
2653 
2654  if (parseToken(Token::colon, "expected ':'") ||
2655  parseToken(Token::l_brace, "expected '{'"))
2656  return failure();
2657  return parseBody(name, nameLoc);
2658  });
2659 }
2660 
2661 ParseResult TopLevelOperationParser::parseDialectResourceFileMetadata() {
2662  return parseResourceFileMetadata([&](StringRef name,
2663  SMLoc nameLoc) -> ParseResult {
2664  // Lookup the dialect and check that it can handle a resource entry.
2665  Dialect *dialect = getContext()->getOrLoadDialect(name);
2666  if (!dialect)
2667  return emitError(nameLoc, "dialect '" + name + "' is unknown");
2668  const auto *handler = dyn_cast<OpAsmDialectInterface>(dialect);
2669  if (!handler) {
2670  return emitError() << "unexpected 'resource' section for dialect '"
2671  << dialect->getNamespace() << "'";
2672  }
2673 
2674  return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2675  // Parse the name of the resource entry.
2676  SMLoc keyLoc = getToken().getLoc();
2677  StringRef key;
2678  if (failed(parseResourceHandle(handler, key)) ||
2679  parseToken(Token::colon, "expected ':'"))
2680  return failure();
2681  Token valueTok = getToken();
2682  consumeToken();
2683 
2684  ParsedResourceEntry entry(key, keyLoc, valueTok, *this);
2685  return handler->parseResource(entry);
2686  });
2687  });
2688 }
2689 
2690 ParseResult TopLevelOperationParser::parseExternalResourceFileMetadata() {
2691  return parseResourceFileMetadata([&](StringRef name,
2692  SMLoc nameLoc) -> ParseResult {
2693  AsmResourceParser *handler = state.config.getResourceParser(name);
2694 
2695  // TODO: Should we require handling external resources in some scenarios?
2696  if (!handler) {
2697  emitWarning(getEncodedSourceLocation(nameLoc))
2698  << "ignoring unknown external resources for '" << name << "'";
2699  }
2700 
2701  return parseCommaSeparatedListUntil(Token::r_brace, [&]() -> ParseResult {
2702  // Parse the name of the resource entry.
2703  SMLoc keyLoc = getToken().getLoc();
2704  StringRef key;
2705  if (failed(parseOptionalKeyword(&key)))
2706  return emitError(
2707  "expected identifier key for 'external_resources' entry");
2708  if (parseToken(Token::colon, "expected ':'"))
2709  return failure();
2710  Token valueTok = getToken();
2711  consumeToken();
2712 
2713  if (!handler)
2714  return success();
2715  ParsedResourceEntry entry(key, keyLoc, valueTok, *this);
2716  return handler->parseResource(entry);
2717  });
2718  });
2719 }
2720 
2722  Location parserLoc) {
2723  // Create a top-level operation to contain the parsed state.
2724  OwningOpRef<ModuleOp> topLevelOp(ModuleOp::create(parserLoc));
2725  OperationParser opParser(state, topLevelOp.get());
2726  while (true) {
2727  switch (getToken().getKind()) {
2728  default:
2729  // Parse a top-level operation.
2730  if (opParser.parseOperation())
2731  return failure();
2732  break;
2733 
2734  // If we got to the end of the file, then we're done.
2735  case Token::eof: {
2736  if (opParser.finalize())
2737  return failure();
2738 
2739  // Splice the blocks of the parsed operation over to the provided
2740  // top-level block.
2741  auto &parsedOps = topLevelOp->getBody()->getOperations();
2742  auto &destOps = topLevelBlock->getOperations();
2743  destOps.splice(destOps.end(), parsedOps, parsedOps.begin(),
2744  parsedOps.end());
2745  return success();
2746  }
2747 
2748  // If we got an error token, then the lexer already emitted an error, just
2749  // stop. Someday we could introduce error recovery if there was demand
2750  // for it.
2751  case Token::error:
2752  return failure();
2753 
2754  // Parse an attribute alias.
2755  case Token::hash_identifier:
2756  if (parseAttributeAliasDef())
2757  return failure();
2758  break;
2759 
2760  // Parse a type alias.
2761  case Token::exclamation_identifier:
2762  if (parseTypeAliasDef())
2763  return failure();
2764  break;
2765 
2766  // Parse a file-level metadata dictionary.
2767  case Token::file_metadata_begin:
2768  if (parseFileMetadataDictionary())
2769  return failure();
2770  break;
2771  }
2772  }
2773 }
2774 
2775 //===----------------------------------------------------------------------===//
2776 
2778 mlir::parseAsmSourceFile(const llvm::SourceMgr &sourceMgr, Block *block,
2779  const ParserConfig &config, AsmParserState *asmState,
2780  AsmParserCodeCompleteContext *codeCompleteContext) {
2781  const auto *sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
2782 
2783  Location parserLoc =
2784  FileLineColLoc::get(config.getContext(), sourceBuf->getBufferIdentifier(),
2785  /*line=*/0, /*column=*/0);
2786 
2787  SymbolState aliasState;
2788  ParserState state(sourceMgr, config, aliasState, asmState,
2789  codeCompleteContext);
2790  return TopLevelOperationParser(state).parse(block, parserLoc);
2791 }
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:69
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:137
BlockArgument getArgument(unsigned i)
Definition: Block.h:126
unsigned getNumArguments()
Definition: Block.h:125
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:93
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
Definition: Block.cpp:152
OpListType & getOperations()
Definition: Block.h:134
BlockArgListType getArguments()
Definition: Block.h:84
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:350
This class helps build Operations.
Definition: Builders.h:209
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:67
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
Definition: Operation.h:672
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:355
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:352
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:118
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:154
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:110
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:21
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:2778
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:75
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:86
AsmParserState * asmState
An optional pointer to a struct containing high level parser state to be populated during parsing.
Definition: ParserState.h:83
SmallVector< StringRef > defaultDialectStack
Definition: ParserState.h:93
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