MLIR 24.0.0git
Parser.cpp
Go to the documentation of this file.
1//===- Parser.cpp ---------------------------------------------------------===//
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
10#include "Lexer.h"
25#include "llvm/ADT/StringExtras.h"
26#include "llvm/ADT/TypeSwitch.h"
27#include "llvm/Support/FormatVariadic.h"
28#include "llvm/Support/SaveAndRestore.h"
29#include "llvm/Support/ScopedPrinter.h"
30#include "llvm/Support/VirtualFileSystem.h"
31#include "llvm/TableGen/Error.h"
32#include "llvm/TableGen/Parser.h"
33#include <cstdint>
34#include <optional>
35#include <string>
36
37using namespace mlir;
38using namespace mlir::pdll;
39
40//===----------------------------------------------------------------------===//
41// Parser
42//===----------------------------------------------------------------------===//
43
44namespace {
45class Parser {
46public:
47 Parser(ast::Context &ctx, llvm::SourceMgr &sourceMgr,
48 bool enableDocumentation, CodeCompleteContext *codeCompleteContext)
49 : ctx(ctx), lexer(sourceMgr, ctx.getDiagEngine(), codeCompleteContext),
50 curToken(lexer.lexToken()), enableDocumentation(enableDocumentation),
51 typeTy(ast::TypeType::get(ctx)), valueTy(ast::ValueType::get(ctx)),
52 typeRangeTy(ast::TypeRangeType::get(ctx)),
53 valueRangeTy(ast::ValueRangeType::get(ctx)),
54 attrTy(ast::AttributeType::get(ctx)),
55 codeCompleteContext(codeCompleteContext) {}
56
57 /// Try to parse a new module. Returns nullptr in the case of failure.
58 FailureOr<ast::Module *> parseModule();
59
60private:
61 /// The current context of the parser. It allows for the parser to know a bit
62 /// about the construct it is nested within during parsing. This is used
63 /// specifically to provide additional verification during parsing, e.g. to
64 /// prevent using rewrites within a match context, matcher constraints within
65 /// a rewrite section, etc.
66 enum class ParserContext {
67 /// The parser is in the global context.
68 Global,
69 /// The parser is currently within a Constraint, which disallows all types
70 /// of rewrites (e.g. `erase`, `replace`, calls to Rewrites, etc.).
71 Constraint,
72 /// The parser is currently within the matcher portion of a Pattern, which
73 /// is allows a terminal operation rewrite statement but no other rewrite
74 /// transformations.
75 PatternMatch,
76 /// The parser is currently within a Rewrite, which disallows calls to
77 /// constraints, requires operation expressions to have names, etc.
78 Rewrite,
79 };
80
81 /// The current specification context of an operations result type. This
82 /// indicates how the result types of an operation may be inferred.
83 enum class OpResultTypeContext {
84 /// The result types of the operation are not known to be inferred.
85 Explicit,
86 /// The result types of the operation are inferred from the root input of a
87 /// `replace` statement.
88 Replacement,
89 /// The result types of the operation are inferred by using the
90 /// `InferTypeOpInterface` interface provided by the operation.
91 Interface,
92 };
93
94 //===--------------------------------------------------------------------===//
95 // Parsing
96 //===--------------------------------------------------------------------===//
97
98 /// Push a new decl scope onto the lexer.
99 ast::DeclScope *pushDeclScope() {
100 ast::DeclScope *newScope =
101 new (scopeAllocator.Allocate()) ast::DeclScope(curDeclScope);
102 return (curDeclScope = newScope);
103 }
104 void pushDeclScope(ast::DeclScope *scope) { curDeclScope = scope; }
105
106 /// Pop the last decl scope from the lexer.
107 void popDeclScope() { curDeclScope = curDeclScope->getParentScope(); }
109 /// Parse the body of an AST module.
110 LogicalResult parseModuleBody(SmallVectorImpl<ast::Decl *> &decls);
111
112 /// Try to convert the given expression to `type`. Returns failure and emits
113 /// an error if a conversion is not viable. On failure, `noteAttachFn` is
114 /// invoked to attach notes to the emitted error diagnostic. On success,
115 /// `expr` is updated to the expression used to convert to `type`.
116 LogicalResult convertExpressionTo(
117 ast::Expr *&expr, ast::Type type,
118 function_ref<void(ast::Diagnostic &diag)> noteAttachFn = {});
119 LogicalResult
120 convertOpExpressionTo(ast::Expr *&expr, ast::OperationType exprType,
121 ast::Type type,
123 LogicalResult convertTupleExpressionTo(
124 ast::Expr *&expr, ast::TupleType exprType, ast::Type type,
126 function_ref<void(ast::Diagnostic &diag)> noteAttachFn);
127
128 /// Given an operation expression, convert it to a Value or ValueRange
129 /// typed expression.
130 ast::Expr *convertOpToValue(const ast::Expr *opExpr);
131
132 /// Lookup ODS information for the given operation, returns nullptr if no
133 /// information is found.
134 const ods::Operation *lookupODSOperation(std::optional<StringRef> opName) {
135 return opName ? ctx.getODSContext().lookupOperation(*opName) : nullptr;
136 }
137
138 /// Process the given documentation string, or return an empty string if
139 /// documentation isn't enabled.
140 StringRef processDoc(StringRef doc) {
141 return enableDocumentation ? doc : StringRef();
142 }
143
144 /// Process the given documentation string and format it, or return an empty
145 /// string if documentation isn't enabled.
146 std::string processAndFormatDoc(const Twine &doc) {
147 if (!enableDocumentation)
148 return "";
149 std::string docStr;
150 {
151 llvm::raw_string_ostream docOS(docStr);
152 std::string tmpDocStr = doc.str();
153 raw_indented_ostream(docOS).printReindented(
154 StringRef(tmpDocStr).rtrim(" \t"));
155 }
156 return docStr;
157 }
158
159 //===--------------------------------------------------------------------===//
160 // Directives
161
162 LogicalResult parseDirective(SmallVectorImpl<ast::Decl *> &decls);
163 LogicalResult parseInclude(SmallVectorImpl<ast::Decl *> &decls);
164 LogicalResult parseTdInclude(StringRef filename, SMRange fileLoc,
165 SmallVectorImpl<ast::Decl *> &decls);
166
167 /// Process the records of a parsed tablegen include file.
168 void processTdIncludeRecords(const llvm::RecordKeeper &tdRecords,
169 SmallVectorImpl<ast::Decl *> &decls);
170
171 /// Create a user defined native constraint for a constraint imported from
172 /// ODS.
173 template <typename ConstraintT>
174 ast::Decl *
175 createODSNativePDLLConstraintDecl(StringRef name, StringRef codeBlock,
176 SMRange loc, ast::Type type,
177 StringRef nativeType, StringRef docString);
178 template <typename ConstraintT>
179 ast::Decl *
180 createODSNativePDLLConstraintDecl(const tblgen::Constraint &constraint,
181 SMRange loc, ast::Type type,
182 StringRef nativeType);
183
184 //===--------------------------------------------------------------------===//
185 // Decls
186
187 /// This structure contains the set of pattern metadata that may be parsed.
188 struct ParsedPatternMetadata {
189 std::optional<uint16_t> benefit;
190 bool hasBoundedRecursion = false;
191 };
192
193 FailureOr<ast::Decl *> parseTopLevelDecl();
194 FailureOr<ast::NamedAttributeDecl *>
195 parseNamedAttributeDecl(std::optional<StringRef> parentOpName);
196
197 /// Parse an argument variable as part of the signature of a
198 /// UserConstraintDecl or UserRewriteDecl.
199 FailureOr<ast::VariableDecl *> parseArgumentDecl();
200
201 /// Parse a result variable as part of the signature of a UserConstraintDecl
202 /// or UserRewriteDecl.
203 FailureOr<ast::VariableDecl *> parseResultDecl(unsigned resultNum);
204
205 /// Parse a UserConstraintDecl. `isInline` signals if the constraint is being
206 /// defined in a non-global context.
207 FailureOr<ast::UserConstraintDecl *>
208 parseUserConstraintDecl(bool isInline = false);
209
210 /// Parse an inline UserConstraintDecl. An inline decl is one defined in a
211 /// non-global context, such as within a Pattern/Constraint/etc.
212 FailureOr<ast::UserConstraintDecl *> parseInlineUserConstraintDecl();
213
214 /// Parse a PDLL (i.e. non-native) UserRewriteDecl whose body is defined using
215 /// PDLL constructs.
216 FailureOr<ast::UserConstraintDecl *> parseUserPDLLConstraintDecl(
217 const ast::Name &name, bool isInline,
218 ArrayRef<ast::VariableDecl *> arguments, ast::DeclScope *argumentScope,
219 ArrayRef<ast::VariableDecl *> results, ast::Type resultType);
220
221 /// Parse a parseUserRewriteDecl. `isInline` signals if the rewrite is being
222 /// defined in a non-global context.
223 FailureOr<ast::UserRewriteDecl *> parseUserRewriteDecl(bool isInline = false);
224
225 /// Parse an inline UserRewriteDecl. An inline decl is one defined in a
226 /// non-global context, such as within a Pattern/Rewrite/etc.
227 FailureOr<ast::UserRewriteDecl *> parseInlineUserRewriteDecl();
228
229 /// Parse a PDLL (i.e. non-native) UserRewriteDecl whose body is defined using
230 /// PDLL constructs.
231 FailureOr<ast::UserRewriteDecl *> parseUserPDLLRewriteDecl(
232 const ast::Name &name, bool isInline,
233 ArrayRef<ast::VariableDecl *> arguments, ast::DeclScope *argumentScope,
234 ArrayRef<ast::VariableDecl *> results, ast::Type resultType);
235
236 /// Parse either a UserConstraintDecl or UserRewriteDecl. These decls have
237 /// effectively the same syntax, and only differ on slight semantics (given
238 /// the different parsing contexts).
239 template <typename T, typename ParseUserPDLLDeclFnT>
240 FailureOr<T *> parseUserConstraintOrRewriteDecl(
241 ParseUserPDLLDeclFnT &&parseUserPDLLFn, ParserContext declContext,
242 StringRef anonymousNamePrefix, bool isInline);
243
244 /// Parse a native (i.e. non-PDLL) UserConstraintDecl or UserRewriteDecl.
245 /// These decls have effectively the same syntax.
246 template <typename T>
247 FailureOr<T *> parseUserNativeConstraintOrRewriteDecl(
248 const ast::Name &name, bool isInline,
249 ArrayRef<ast::VariableDecl *> arguments,
250 ArrayRef<ast::VariableDecl *> results, ast::Type resultType);
251
252 /// Parse the functional signature (i.e. the arguments and results) of a
253 /// UserConstraintDecl or UserRewriteDecl.
254 LogicalResult parseUserConstraintOrRewriteSignature(
255 SmallVectorImpl<ast::VariableDecl *> &arguments,
256 SmallVectorImpl<ast::VariableDecl *> &results,
257 ast::DeclScope *&argumentScope, ast::Type &resultType);
258
259 /// Validate the return (which if present is specified by bodyIt) of a
260 /// UserConstraintDecl or UserRewriteDecl.
261 LogicalResult validateUserConstraintOrRewriteReturn(
262 StringRef declType, ast::CompoundStmt *body,
263 ArrayRef<ast::Stmt *>::iterator bodyIt,
264 ArrayRef<ast::Stmt *>::iterator bodyE,
265 ArrayRef<ast::VariableDecl *> results, ast::Type &resultType);
266
267 FailureOr<ast::CompoundStmt *>
268 parseLambdaBody(function_ref<LogicalResult(ast::Stmt *&)> processStatementFn,
269 bool expectTerminalSemicolon = true);
270 FailureOr<ast::CompoundStmt *> parsePatternLambdaBody();
271 FailureOr<ast::Decl *> parsePatternDecl();
272 LogicalResult parsePatternDeclMetadata(ParsedPatternMetadata &metadata);
273
274 /// Check to see if a decl has already been defined with the given name, if
275 /// one has emit and error and return failure. Returns success otherwise.
276 LogicalResult checkDefineNamedDecl(const ast::Name &name);
277
278 /// Try to define a variable decl with the given components, returns the
279 /// variable on success.
280 FailureOr<ast::VariableDecl *>
281 defineVariableDecl(StringRef name, SMRange nameLoc, ast::Type type,
282 ast::Expr *initExpr,
283 ArrayRef<ast::ConstraintRef> constraints);
284 FailureOr<ast::VariableDecl *>
285 defineVariableDecl(StringRef name, SMRange nameLoc, ast::Type type,
286 ArrayRef<ast::ConstraintRef> constraints);
287
288 /// Parse the constraint reference list for a variable decl.
289 LogicalResult parseVariableDeclConstraintList(
290 SmallVectorImpl<ast::ConstraintRef> &constraints);
291
292 /// Parse the expression used within a type constraint, e.g. Attr<type-expr>.
293 FailureOr<ast::Expr *> parseTypeConstraintExpr();
294
295 /// Try to parse a single reference to a constraint. `typeConstraint` is the
296 /// location of a previously parsed type constraint for the entity that will
297 /// be constrained by the parsed constraint. `existingConstraints` are any
298 /// existing constraints that have already been parsed for the same entity
299 /// that will be constrained by this constraint. `allowInlineTypeConstraints`
300 /// allows the use of inline Type constraints, e.g. `Value<valueType: Type>`.
301 FailureOr<ast::ConstraintRef>
302 parseConstraint(std::optional<SMRange> &typeConstraint,
303 ArrayRef<ast::ConstraintRef> existingConstraints,
304 bool allowInlineTypeConstraints);
305
306 /// Try to parse the constraint for a UserConstraintDecl/UserRewriteDecl
307 /// argument or result variable. The constraints for these variables do not
308 /// allow inline type constraints, and only permit a single constraint.
309 FailureOr<ast::ConstraintRef> parseArgOrResultConstraint();
310
311 //===--------------------------------------------------------------------===//
312 // Exprs
313
314 FailureOr<ast::Expr *> parseExpr();
315
316 /// Identifier expressions.
317 FailureOr<ast::Expr *> parseAttributeExpr();
318 FailureOr<ast::Expr *> parseCallExpr(ast::Expr *parentExpr,
319 bool isNegated = false);
320 FailureOr<ast::Expr *> parseDeclRefExpr(StringRef name, SMRange loc);
321 FailureOr<ast::Expr *> parseIdentifierExpr();
322 FailureOr<ast::Expr *> parseInlineConstraintLambdaExpr();
323 FailureOr<ast::Expr *> parseInlineRewriteLambdaExpr();
324 FailureOr<ast::Expr *> parseMemberAccessExpr(ast::Expr *parentExpr);
325 FailureOr<ast::Expr *> parseNegatedExpr();
326 FailureOr<ast::OpNameDecl *> parseOperationName(bool allowEmptyName = false);
327 FailureOr<ast::OpNameDecl *> parseWrappedOperationName(bool allowEmptyName);
328 FailureOr<ast::Expr *>
329 parseOperationExpr(OpResultTypeContext inputResultTypeContext =
330 OpResultTypeContext::Explicit);
331 FailureOr<ast::Expr *> parseTupleExpr();
332 FailureOr<ast::Expr *> parseTypeExpr();
333 FailureOr<ast::Expr *> parseUnderscoreExpr();
334
335 //===--------------------------------------------------------------------===//
336 // Stmts
337
338 FailureOr<ast::Stmt *> parseStmt(bool expectTerminalSemicolon = true);
339 FailureOr<ast::CompoundStmt *> parseCompoundStmt();
340 FailureOr<ast::EraseStmt *> parseEraseStmt();
341 FailureOr<ast::LetStmt *> parseLetStmt();
342 FailureOr<ast::ReplaceStmt *> parseReplaceStmt();
343 FailureOr<ast::ReturnStmt *> parseReturnStmt();
344 FailureOr<ast::RewriteStmt *> parseRewriteStmt();
345
346 //===--------------------------------------------------------------------===//
347 // Creation+Analysis
348 //===--------------------------------------------------------------------===//
349
350 //===--------------------------------------------------------------------===//
351 // Decls
352
353 /// Try to extract a callable from the given AST node. Returns nullptr on
354 /// failure.
355 ast::CallableDecl *tryExtractCallableDecl(ast::Node *node);
356
357 /// Try to create a pattern decl with the given components, returning the
358 /// Pattern on success.
359 FailureOr<ast::PatternDecl *>
360 createPatternDecl(SMRange loc, const ast::Name *name,
361 const ParsedPatternMetadata &metadata,
362 ast::CompoundStmt *body);
363
364 /// Build the result type for a UserConstraintDecl/UserRewriteDecl given a set
365 /// of results, defined as part of the signature.
366 ast::Type
367 createUserConstraintRewriteResultType(ArrayRef<ast::VariableDecl *> results);
368
369 /// Create a PDLL (i.e. non-native) UserConstraintDecl or UserRewriteDecl.
370 template <typename T>
371 FailureOr<T *> createUserPDLLConstraintOrRewriteDecl(
372 const ast::Name &name, ArrayRef<ast::VariableDecl *> arguments,
373 ArrayRef<ast::VariableDecl *> results, ast::Type resultType,
374 ast::CompoundStmt *body);
375
376 /// Try to create a variable decl with the given components, returning the
377 /// Variable on success.
378 FailureOr<ast::VariableDecl *>
379 createVariableDecl(StringRef name, SMRange loc, ast::Expr *initializer,
380 ArrayRef<ast::ConstraintRef> constraints);
381
382 /// Create a variable for an argument or result defined as part of the
383 /// signature of a UserConstraintDecl/UserRewriteDecl.
384 FailureOr<ast::VariableDecl *>
385 createArgOrResultVariableDecl(StringRef name, SMRange loc,
386 const ast::ConstraintRef &constraint);
387
388 /// Validate the constraints used to constraint a variable decl.
389 /// `inferredType` is the type of the variable inferred by the constraints
390 /// within the list, and is updated to the most refined type as determined by
391 /// the constraints. Returns success if the constraint list is valid, failure
392 /// otherwise.
393 LogicalResult
394 validateVariableConstraints(ArrayRef<ast::ConstraintRef> constraints,
395 ast::Type &inferredType);
396 /// Validate a single reference to a constraint. `inferredType` contains the
397 /// currently inferred variabled type and is refined within the type defined
398 /// by the constraint. Returns success if the constraint is valid, failure
399 /// otherwise.
400 LogicalResult validateVariableConstraint(const ast::ConstraintRef &ref,
401 ast::Type &inferredType);
402 LogicalResult validateTypeConstraintExpr(const ast::Expr *typeExpr);
403 LogicalResult validateTypeRangeConstraintExpr(const ast::Expr *typeExpr);
404
405 //===--------------------------------------------------------------------===//
406 // Exprs
407
408 FailureOr<ast::CallExpr *>
409 createCallExpr(SMRange loc, ast::Expr *parentExpr,
410 MutableArrayRef<ast::Expr *> arguments,
411 bool isNegated = false);
412 FailureOr<ast::DeclRefExpr *> createDeclRefExpr(SMRange loc, ast::Decl *decl);
413 FailureOr<ast::DeclRefExpr *>
414 createInlineVariableExpr(ast::Type type, StringRef name, SMRange loc,
415 ArrayRef<ast::ConstraintRef> constraints);
416 FailureOr<ast::MemberAccessExpr *>
417 createMemberAccessExpr(ast::Expr *parentExpr, StringRef name, SMRange loc);
418
419 /// Validate the member access `name` into the given parent expression. On
420 /// success, this also returns the type of the member accessed.
421 FailureOr<ast::Type> validateMemberAccess(ast::Expr *parentExpr,
422 StringRef name, SMRange loc);
423 FailureOr<ast::OperationExpr *>
424 createOperationExpr(SMRange loc, const ast::OpNameDecl *name,
425 OpResultTypeContext resultTypeContext,
426 SmallVectorImpl<ast::Expr *> &operands,
427 MutableArrayRef<ast::NamedAttributeDecl *> attributes,
428 SmallVectorImpl<ast::Expr *> &results);
429 LogicalResult
430 validateOperationOperands(SMRange loc, std::optional<StringRef> name,
431 const ods::Operation *odsOp,
432 SmallVectorImpl<ast::Expr *> &operands);
433 LogicalResult validateOperationResults(SMRange loc,
434 std::optional<StringRef> name,
435 const ods::Operation *odsOp,
436 SmallVectorImpl<ast::Expr *> &results);
437 void checkOperationResultTypeInferrence(SMRange loc, StringRef name,
438 const ods::Operation *odsOp);
439 LogicalResult validateOperationOperandsOrResults(
440 StringRef groupName, SMRange loc, std::optional<SMRange> odsOpLoc,
441 std::optional<StringRef> name, SmallVectorImpl<ast::Expr *> &values,
442 ArrayRef<ods::OperandOrResult> odsValues, ast::Type singleTy,
443 ast::RangeType rangeTy);
444 FailureOr<ast::TupleExpr *> createTupleExpr(SMRange loc,
445 ArrayRef<ast::Expr *> elements,
446 ArrayRef<StringRef> elementNames);
447
448 //===--------------------------------------------------------------------===//
449 // Stmts
450
451 FailureOr<ast::EraseStmt *> createEraseStmt(SMRange loc, ast::Expr *rootOp);
452 FailureOr<ast::ReplaceStmt *>
453 createReplaceStmt(SMRange loc, ast::Expr *rootOp,
454 MutableArrayRef<ast::Expr *> replValues);
455 FailureOr<ast::RewriteStmt *>
456 createRewriteStmt(SMRange loc, ast::Expr *rootOp,
457 ast::CompoundStmt *rewriteBody);
458
459 //===--------------------------------------------------------------------===//
460 // Code Completion
461 //===--------------------------------------------------------------------===//
462
463 /// The set of various code completion methods. Every completion method
464 /// returns `failure` to stop the parsing process after providing completion
465 /// results.
466
467 LogicalResult codeCompleteMemberAccess(ast::Expr *parentExpr);
468 LogicalResult codeCompleteAttributeName(std::optional<StringRef> opName);
469 LogicalResult codeCompleteConstraintName(ast::Type inferredType,
470 bool allowInlineTypeConstraints);
471 LogicalResult codeCompleteDialectName();
472 LogicalResult codeCompleteOperationName(StringRef dialectName);
473 LogicalResult codeCompletePatternMetadata();
474 LogicalResult codeCompleteIncludeFilename(StringRef curPath);
475
476 void codeCompleteCallSignature(ast::Node *parent, unsigned currentNumArgs);
477 void codeCompleteOperationOperandsSignature(std::optional<StringRef> opName,
478 unsigned currentNumOperands);
479 void codeCompleteOperationResultsSignature(std::optional<StringRef> opName,
480 unsigned currentNumResults);
481
482 //===--------------------------------------------------------------------===//
483 // Lexer Utilities
484 //===--------------------------------------------------------------------===//
485
486 /// If the current token has the specified kind, consume it and return true.
487 /// If not, return false.
488 bool consumeIf(Token::Kind kind) {
489 if (curToken.isNot(kind))
490 return false;
491 consumeToken(kind);
492 return true;
493 }
494
495 /// Advance the current lexer onto the next token.
496 void consumeToken() {
497 assert(curToken.isNot(Token::eof, Token::error) &&
498 "shouldn't advance past EOF or errors");
499 curToken = lexer.lexToken();
500 }
501
502 /// Advance the current lexer onto the next token, asserting what the expected
503 /// current token is. This is preferred to the above method because it leads
504 /// to more self-documenting code with better checking.
505 void consumeToken(Token::Kind kind) {
506 assert(curToken.is(kind) && "consumed an unexpected token");
507 consumeToken();
508 }
509
510 /// Reset the lexer to the location at the given position.
511 void resetToken(SMRange tokLoc) {
512 lexer.resetPointer(tokLoc.Start.getPointer());
513 curToken = lexer.lexToken();
514 }
515
516 /// Consume the specified token if present and return success. On failure,
517 /// output a diagnostic and return failure.
518 LogicalResult parseToken(Token::Kind kind, const Twine &msg) {
519 if (curToken.getKind() != kind)
520 return emitError(curToken.getLoc(), msg);
521 consumeToken();
522 return success();
523 }
524 LogicalResult emitError(SMRange loc, const Twine &msg) {
525 lexer.emitError(loc, msg);
526 return failure();
527 }
528 LogicalResult emitError(const Twine &msg) {
529 return emitError(curToken.getLoc(), msg);
530 }
531 LogicalResult emitErrorAndNote(SMRange loc, const Twine &msg, SMRange noteLoc,
532 const Twine &note) {
533 lexer.emitErrorAndNote(loc, msg, noteLoc, note);
534 return failure();
535 }
536
537 //===--------------------------------------------------------------------===//
538 // Fields
539 //===--------------------------------------------------------------------===//
540
541 /// The owning AST context.
542 ast::Context &ctx;
543
544 /// The lexer of this parser.
545 Lexer lexer;
546
547 /// The current token within the lexer.
548 Token curToken;
549
550 /// A flag indicating if the parser should add documentation to AST nodes when
551 /// viable.
552 bool enableDocumentation;
553
554 /// The most recently defined decl scope.
555 ast::DeclScope *curDeclScope = nullptr;
556 llvm::SpecificBumpPtrAllocator<ast::DeclScope> scopeAllocator;
557
558 /// The current context of the parser.
559 ParserContext parserContext = ParserContext::Global;
560
561 /// Cached types to simplify verification and expression creation.
562 ast::Type typeTy, valueTy;
563 ast::RangeType typeRangeTy, valueRangeTy;
564 ast::Type attrTy;
565
566 /// A counter used when naming anonymous constraints and rewrites.
567 unsigned anonymousDeclNameCounter = 0;
568
569 /// The optional code completion context.
570 CodeCompleteContext *codeCompleteContext;
571};
572} // namespace
573
574FailureOr<ast::Module *> Parser::parseModule() {
575 SMLoc moduleLoc = curToken.getStartLoc();
576 pushDeclScope();
577
578 // Parse the top-level decls of the module.
579 SmallVector<ast::Decl *> decls;
580 if (failed(parseModuleBody(decls)))
581 return popDeclScope(), failure();
582
583 popDeclScope();
584 return ast::Module::create(ctx, moduleLoc, decls);
585}
586
587LogicalResult Parser::parseModuleBody(SmallVectorImpl<ast::Decl *> &decls) {
588 while (curToken.isNot(Token::eof)) {
589 if (curToken.is(Token::directive)) {
590 if (failed(parseDirective(decls)))
591 return failure();
592 continue;
593 }
594
595 FailureOr<ast::Decl *> decl = parseTopLevelDecl();
596 if (failed(decl))
597 return failure();
598 decls.push_back(*decl);
599 }
600 return success();
601}
602
603ast::Expr *Parser::convertOpToValue(const ast::Expr *opExpr) {
604 return ast::AllResultsMemberAccessExpr::create(ctx, opExpr->getLoc(), opExpr,
605 valueRangeTy);
606}
607
608LogicalResult Parser::convertExpressionTo(
609 ast::Expr *&expr, ast::Type type,
610 function_ref<void(ast::Diagnostic &diag)> noteAttachFn) {
611 ast::Type exprType = expr->getType();
612 if (exprType == type)
613 return success();
614
615 auto emitConvertError = [&]() -> ast::InFlightDiagnostic {
616 ast::InFlightDiagnostic diag = ctx.getDiagEngine().emitError(
617 expr->getLoc(), llvm::formatv("unable to convert expression of type "
618 "`{0}` to the expected type of "
619 "`{1}`",
620 exprType, type));
621 if (noteAttachFn)
622 noteAttachFn(*diag);
623 return diag;
624 };
625
626 if (auto exprOpType = dyn_cast<ast::OperationType>(exprType))
627 return convertOpExpressionTo(expr, exprOpType, type, emitConvertError);
628
629 // FIXME: Decide how to allow/support converting a single result to multiple,
630 // and multiple to a single result. For now, we just allow Single->Range,
631 // but this isn't something really supported in the PDL dialect. We should
632 // figure out some way to support both.
633 if ((exprType == valueTy || exprType == valueRangeTy) &&
634 (type == valueTy || type == valueRangeTy))
635 return success();
636 if ((exprType == typeTy || exprType == typeRangeTy) &&
637 (type == typeTy || type == typeRangeTy))
638 return success();
639
640 // Handle tuple types.
641 if (auto exprTupleType = dyn_cast<ast::TupleType>(exprType))
642 return convertTupleExpressionTo(expr, exprTupleType, type, emitConvertError,
643 noteAttachFn);
644
645 return emitConvertError();
646}
647
648LogicalResult Parser::convertOpExpressionTo(
649 ast::Expr *&expr, ast::OperationType exprType, ast::Type type,
650 function_ref<ast::InFlightDiagnostic()> emitErrorFn) {
651 // Two operation types are compatible if they have the same name, or if the
652 // expected type is more general.
653 if (auto opType = dyn_cast<ast::OperationType>(type)) {
654 if (opType.getName())
655 return emitErrorFn();
656 return success();
657 }
658
659 // An operation can always convert to a ValueRange.
660 if (type == valueRangeTy) {
661 expr = ast::AllResultsMemberAccessExpr::create(ctx, expr->getLoc(), expr,
662 valueRangeTy);
663 return success();
664 }
665
666 // Allow conversion to a single value by constraining the result range.
667 if (type == valueTy) {
668 // If the operation is registered, we can verify if it can ever have a
669 // single result.
670 if (const ods::Operation *odsOp = exprType.getODSOperation()) {
671 if (odsOp->getResults().empty()) {
672 return emitErrorFn()->attachNote(
673 llvm::formatv("see the definition of `{0}`, which was defined "
674 "with zero results",
675 odsOp->getName()),
676 odsOp->getLoc());
677 }
678
679 unsigned numSingleResults = llvm::count_if(
680 odsOp->getResults(), [](const ods::OperandOrResult &result) {
681 return result.getVariableLengthKind() ==
682 ods::VariableLengthKind::Single;
683 });
684 if (numSingleResults > 1) {
685 return emitErrorFn()->attachNote(
686 llvm::formatv("see the definition of `{0}`, which was defined "
687 "with at least {1} results",
688 odsOp->getName(), numSingleResults),
689 odsOp->getLoc());
690 }
691 }
692
693 expr = ast::AllResultsMemberAccessExpr::create(ctx, expr->getLoc(), expr,
694 valueTy);
695 return success();
696 }
697 return emitErrorFn();
698}
699
700LogicalResult Parser::convertTupleExpressionTo(
701 ast::Expr *&expr, ast::TupleType exprType, ast::Type type,
702 function_ref<ast::InFlightDiagnostic()> emitErrorFn,
703 function_ref<void(ast::Diagnostic &diag)> noteAttachFn) {
704 // Handle conversions between tuples.
705 if (auto tupleType = dyn_cast<ast::TupleType>(type)) {
706 if (tupleType.size() != exprType.size())
707 return emitErrorFn();
708
709 // Build a new tuple expression using each of the elements of the current
710 // tuple.
711 SmallVector<ast::Expr *> newExprs;
712 for (unsigned i = 0, e = exprType.size(); i < e; ++i) {
713 newExprs.push_back(ast::MemberAccessExpr::create(
714 ctx, expr->getLoc(), expr, llvm::to_string(i),
715 exprType.getElementTypes()[i]));
716
717 auto diagFn = [&](ast::Diagnostic &diag) {
718 diag.attachNote(llvm::formatv("when converting element #{0} of `{1}`",
719 i, exprType));
720 if (noteAttachFn)
721 noteAttachFn(diag);
722 };
723 if (failed(convertExpressionTo(newExprs.back(),
724 tupleType.getElementTypes()[i], diagFn)))
725 return failure();
726 }
727 expr = ast::TupleExpr::create(ctx, expr->getLoc(), newExprs,
728 tupleType.getElementNames());
729 return success();
730 }
731
732 // Handle conversion to a range.
733 auto convertToRange = [&](ArrayRef<ast::Type> allowedElementTypes,
734 ast::RangeType resultTy) -> LogicalResult {
735 // TODO: We currently only allow range conversion within a rewrite context.
736 if (parserContext != ParserContext::Rewrite) {
737 return emitErrorFn()->attachNote("Tuple to Range conversion is currently "
738 "only allowed within a rewrite context");
739 }
740
741 // All of the tuple elements must be allowed types.
742 for (ast::Type elementType : exprType.getElementTypes())
743 if (!llvm::is_contained(allowedElementTypes, elementType))
744 return emitErrorFn();
745
746 // Build a new tuple expression using each of the elements of the current
747 // tuple.
748 SmallVector<ast::Expr *> newExprs;
749 for (unsigned i = 0, e = exprType.size(); i < e; ++i) {
750 newExprs.push_back(ast::MemberAccessExpr::create(
751 ctx, expr->getLoc(), expr, llvm::to_string(i),
752 exprType.getElementTypes()[i]));
753 }
754 expr = ast::RangeExpr::create(ctx, expr->getLoc(), newExprs, resultTy);
755 return success();
756 };
757 if (type == valueRangeTy)
758 return convertToRange({valueTy, valueRangeTy}, valueRangeTy);
759 if (type == typeRangeTy)
760 return convertToRange({typeTy, typeRangeTy}, typeRangeTy);
761
762 return emitErrorFn();
763}
764
765//===----------------------------------------------------------------------===//
766// Directives
767//===----------------------------------------------------------------------===//
768
769LogicalResult Parser::parseDirective(SmallVectorImpl<ast::Decl *> &decls) {
770 StringRef directive = curToken.getSpelling();
771 if (directive == "#include")
772 return parseInclude(decls);
773
774 return emitError("unknown directive `" + directive + "`");
775}
776
777LogicalResult Parser::parseInclude(SmallVectorImpl<ast::Decl *> &decls) {
778 SMRange loc = curToken.getLoc();
779 consumeToken(Token::directive);
780
781 // Handle code completion of the include file path.
782 if (curToken.is(Token::code_complete_string))
783 return codeCompleteIncludeFilename(curToken.getStringValue());
784
785 // Parse the file being included.
786 if (!curToken.isString())
787 return emitError(loc,
788 "expected string file name after `include` directive");
789 SMRange fileLoc = curToken.getLoc();
790 std::string filenameStr = curToken.getStringValue();
791 StringRef filename = filenameStr;
792 consumeToken();
793
794 // Check the type of include. If ending with `.pdll`, this is another pdl file
795 // to be parsed along with the current module.
796 if (filename.ends_with(".pdll")) {
797 if (failed(lexer.pushInclude(filename, fileLoc)))
798 return emitError(fileLoc,
799 "unable to open include file `" + filename + "`");
800
801 // If we added the include successfully, parse it into the current module.
802 // Make sure to update to the next token after we finish parsing the nested
803 // file.
804 curToken = lexer.lexToken();
805 LogicalResult result = parseModuleBody(decls);
806 curToken = lexer.lexToken();
807 return result;
808 }
809
810 // Otherwise, this must be a `.td` include.
811 if (filename.ends_with(".td"))
812 return parseTdInclude(filename, fileLoc, decls);
813
814 return emitError(fileLoc,
815 "expected include filename to end with `.pdll` or `.td`");
816}
817
818LogicalResult Parser::parseTdInclude(StringRef filename, llvm::SMRange fileLoc,
819 SmallVectorImpl<ast::Decl *> &decls) {
820 llvm::SourceMgr &parserSrcMgr = lexer.getSourceMgr();
821
822 // Use the source manager to open the file, but don't yet add it.
823 std::string includedFile;
824 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> includeBuffer =
825 parserSrcMgr.OpenIncludeFile(filename.str(), includedFile);
826 if (!includeBuffer)
827 return emitError(fileLoc, "unable to open include file `" + filename + "`");
828
829 // Setup the source manager for parsing the tablegen file.
830 llvm::SourceMgr tdSrcMgr;
831 tdSrcMgr.AddNewSourceBuffer(std::move(*includeBuffer), SMLoc());
832 tdSrcMgr.setIncludeDirs(parserSrcMgr.getIncludeDirs());
833 tdSrcMgr.setVirtualFileSystem(llvm::vfs::getRealFileSystem());
834
835 // This class provides a context argument for the llvm::SourceMgr diagnostic
836 // handler.
837 struct DiagHandlerContext {
838 Parser &parser;
839 StringRef filename;
840 llvm::SMRange loc;
841 } handlerContext{*this, filename, fileLoc};
842
843 // Set the diagnostic handler for the tablegen source manager.
844 tdSrcMgr.setDiagHandler(
845 [](const llvm::SMDiagnostic &diag, void *rawHandlerContext) {
846 auto *ctx = reinterpret_cast<DiagHandlerContext *>(rawHandlerContext);
847 (void)ctx->parser.emitError(
848 ctx->loc,
849 llvm::formatv("error while processing include file `{0}`: {1}",
850 ctx->filename, diag.getMessage()));
851 },
852 &handlerContext);
853
854 // Parse the tablegen file.
855 llvm::RecordKeeper tdRecords;
856 if (llvm::TableGenParseFile(tdSrcMgr, tdRecords))
857 return failure();
858
859 // Process the parsed records.
860 processTdIncludeRecords(tdRecords, decls);
861
862 // After we are done processing, move all of the tablegen source buffers to
863 // the main parser source mgr. This allows for directly using source locations
864 // from the .td files without needing to remap them.
865 parserSrcMgr.takeSourceBuffersFrom(tdSrcMgr, fileLoc.End);
866 return success();
867}
868
869void Parser::processTdIncludeRecords(const llvm::RecordKeeper &tdRecords,
870 SmallVectorImpl<ast::Decl *> &decls) {
871 // Return the length kind of the given value.
872 auto getLengthKind = [](const auto &value) {
873 if (value.isOptional())
874 return ods::VariableLengthKind::Optional;
875 return value.isVariadic() ? ods::VariableLengthKind::Variadic
876 : ods::VariableLengthKind::Single;
877 };
878
879 // Insert a type constraint into the ODS context.
880 ods::Context &odsContext = ctx.getODSContext();
881 auto addTypeConstraint = [&](const tblgen::NamedTypeConstraint &cst)
882 -> const ods::TypeConstraint & {
883 return odsContext.insertTypeConstraint(
884 cst.constraint.getUniqueDefName(),
885 processDoc(cst.constraint.getSummary()), cst.constraint.getCppType());
886 };
887 auto convertLocToRange = [&](llvm::SMLoc loc) -> llvm::SMRange {
888 return {loc, llvm::SMLoc::getFromPointer(loc.getPointer() + 1)};
889 };
890
891 // Process the parsed tablegen records to build ODS information.
892 /// Operations.
893 for (const llvm::Record *def : tdRecords.getAllDerivedDefinitions("Op")) {
894 tblgen::Operator op(def);
895
896 // Check to see if this operation is known to support type inferrence.
897 bool supportsResultTypeInferrence =
898 op.getTrait("::mlir::InferTypeOpInterface::Trait");
899
900 auto [odsOp, inserted] = odsContext.insertOperation(
901 op.getOperationName(), processDoc(op.getSummary()),
902 processAndFormatDoc(op.getDescription()), op.getQualCppClassName(),
903 supportsResultTypeInferrence, op.getLoc().front());
904
905 // Ignore operations that have already been added.
906 if (!inserted)
907 continue;
908
909 for (const tblgen::NamedAttribute &attr : op.getAttributes()) {
910 odsOp->appendAttribute(attr.name, attr.attr.isOptional(),
911 odsContext.insertAttributeConstraint(
912 attr.attr.getUniqueDefName(),
913 processDoc(attr.attr.getSummary()),
914 attr.attr.getStorageType()));
915 }
916 for (const tblgen::NamedTypeConstraint &operand : op.getOperands()) {
917 odsOp->appendOperand(operand.name, getLengthKind(operand),
918 addTypeConstraint(operand));
919 }
920 for (const tblgen::NamedTypeConstraint &result : op.getResults()) {
921 odsOp->appendResult(result.name, getLengthKind(result),
922 addTypeConstraint(result));
923 }
924 }
925
926 auto shouldBeSkipped = [this](const llvm::Record *def) {
927 return def->isAnonymous() || curDeclScope->lookup(def->getName()) ||
928 def->isSubClassOf("DeclareInterfaceMethods");
929 };
930
931 /// Attr constraints.
932 for (const llvm::Record *def : tdRecords.getAllDerivedDefinitions("Attr")) {
933 if (shouldBeSkipped(def))
934 continue;
935
936 tblgen::Attribute constraint(def);
937 decls.push_back(createODSNativePDLLConstraintDecl<ast::AttrConstraintDecl>(
938 constraint, convertLocToRange(def->getLoc().front()), attrTy,
939 constraint.getStorageType()));
940 }
941 /// Type constraints.
942 for (const llvm::Record *def : tdRecords.getAllDerivedDefinitions("Type")) {
943 if (shouldBeSkipped(def))
944 continue;
945
946 tblgen::TypeConstraint constraint(def);
947 decls.push_back(createODSNativePDLLConstraintDecl<ast::TypeConstraintDecl>(
948 constraint, convertLocToRange(def->getLoc().front()), typeTy,
949 constraint.getCppType()));
950 }
951 /// OpInterfaces.
952 ast::Type opTy = ast::OperationType::get(ctx);
953 for (const llvm::Record *def :
954 tdRecords.getAllDerivedDefinitions("OpInterface")) {
955 if (shouldBeSkipped(def))
956 continue;
957
958 SMRange loc = convertLocToRange(def->getLoc().front());
959
960 std::string cppClassName =
961 llvm::formatv("{0}::{1}", def->getValueAsString("cppNamespace"),
962 def->getValueAsString("cppInterfaceName"))
963 .str();
964 std::string codeBlock =
965 llvm::formatv("return ::mlir::success(llvm::isa<{0}>(self));",
966 cppClassName)
967 .str();
968
969 std::string desc =
970 processAndFormatDoc(def->getValueAsString("description"));
971 decls.push_back(createODSNativePDLLConstraintDecl<ast::OpConstraintDecl>(
972 def->getName(), codeBlock, loc, opTy, cppClassName, desc));
973 }
974}
975
976template <typename ConstraintT>
977ast::Decl *Parser::createODSNativePDLLConstraintDecl(
978 StringRef name, StringRef codeBlock, SMRange loc, ast::Type type,
979 StringRef nativeType, StringRef docString) {
980 // Build the single input parameter.
981 ast::DeclScope *argScope = pushDeclScope();
982 auto *paramVar = ast::VariableDecl::create(
983 ctx, ast::Name::create(ctx, "self", loc), type,
984 /*initExpr=*/nullptr, ast::ConstraintRef(ConstraintT::create(ctx, loc)));
985 argScope->add(paramVar);
986 popDeclScope();
987
988 // Build the native constraint.
989 auto *constraintDecl = ast::UserConstraintDecl::createNative(
990 ctx, ast::Name::create(ctx, name, loc), paramVar,
991 /*results=*/{}, codeBlock, ast::TupleType::get(ctx), nativeType);
992 constraintDecl->setDocComment(ctx, docString);
993 curDeclScope->add(constraintDecl);
994 return constraintDecl;
995}
996
997template <typename ConstraintT>
998ast::Decl *
999Parser::createODSNativePDLLConstraintDecl(const tblgen::Constraint &constraint,
1000 SMRange loc, ast::Type type,
1001 StringRef nativeType) {
1002 // Format the condition template.
1003 tblgen::FmtContext fmtContext;
1004 fmtContext.withSelf("self");
1005 std::string codeBlock = tblgen::tgfmt(
1006 "return ::mlir::success(" + constraint.getConditionTemplate() + ");",
1007 &fmtContext);
1008
1009 // If documentation was enabled, build the doc string for the generated
1010 // constraint. It would be nice to do this lazily, but TableGen information is
1011 // destroyed after we finish parsing the file.
1012 std::string docString;
1013 if (enableDocumentation) {
1014 StringRef desc = constraint.getDescription();
1015 docString = processAndFormatDoc(
1016 constraint.getSummary() +
1017 (desc.empty() ? "" : ("\n\n" + constraint.getDescription())));
1018 }
1019
1020 return createODSNativePDLLConstraintDecl<ConstraintT>(
1021 constraint.getUniqueDefName(), codeBlock, loc, type, nativeType,
1022 docString);
1023}
1024
1025//===----------------------------------------------------------------------===//
1026// Decls
1027//===----------------------------------------------------------------------===//
1028
1029FailureOr<ast::Decl *> Parser::parseTopLevelDecl() {
1030 FailureOr<ast::Decl *> decl;
1031 switch (curToken.getKind()) {
1033 decl = parseUserConstraintDecl();
1034 break;
1035 case Token::kw_Pattern:
1036 decl = parsePatternDecl();
1037 break;
1038 case Token::kw_Rewrite:
1039 decl = parseUserRewriteDecl();
1040 break;
1041 default:
1042 return emitError("expected top-level declaration, such as a `Pattern`");
1043 }
1044 if (failed(decl))
1045 return failure();
1046
1047 // If the decl has a name, add it to the current scope.
1048 if (const ast::Name *name = (*decl)->getName()) {
1049 if (failed(checkDefineNamedDecl(*name)))
1050 return failure();
1051 curDeclScope->add(*decl);
1052 }
1053 return decl;
1054}
1055
1056FailureOr<ast::NamedAttributeDecl *>
1057Parser::parseNamedAttributeDecl(std::optional<StringRef> parentOpName) {
1058 // Check for name code completion.
1059 if (curToken.is(Token::code_complete))
1060 return codeCompleteAttributeName(parentOpName);
1061
1062 std::string attrNameStr;
1063 if (curToken.isString())
1064 attrNameStr = curToken.getStringValue();
1065 else if (curToken.is(Token::identifier) || curToken.isKeyword())
1066 attrNameStr = curToken.getSpelling().str();
1067 else
1068 return emitError("expected identifier or string attribute name");
1069 const auto &name = ast::Name::create(ctx, attrNameStr, curToken.getLoc());
1070 consumeToken();
1071
1072 // Check for a value of the attribute.
1073 ast::Expr *attrValue = nullptr;
1074 if (consumeIf(Token::equal)) {
1075 FailureOr<ast::Expr *> attrExpr = parseExpr();
1076 if (failed(attrExpr))
1077 return failure();
1078 attrValue = *attrExpr;
1079 } else {
1080 // If there isn't a concrete value, create an expression representing a
1081 // UnitAttr.
1082 attrValue = ast::AttributeExpr::create(ctx, name.getLoc(), "unit");
1083 }
1084
1085 return ast::NamedAttributeDecl::create(ctx, name, attrValue);
1086}
1087
1088FailureOr<ast::CompoundStmt *> Parser::parseLambdaBody(
1089 function_ref<LogicalResult(ast::Stmt *&)> processStatementFn,
1090 bool expectTerminalSemicolon) {
1091 consumeToken(Token::equal_arrow);
1092
1093 // Parse the single statement of the lambda body.
1094 SMLoc bodyStartLoc = curToken.getStartLoc();
1095 pushDeclScope();
1096 FailureOr<ast::Stmt *> singleStatement = parseStmt(expectTerminalSemicolon);
1097 bool failedToParse =
1098 failed(singleStatement) || failed(processStatementFn(*singleStatement));
1099 popDeclScope();
1100 if (failedToParse)
1101 return failure();
1102
1103 SMRange bodyLoc(bodyStartLoc, curToken.getStartLoc());
1104 return ast::CompoundStmt::create(ctx, bodyLoc, *singleStatement);
1105}
1106
1107FailureOr<ast::VariableDecl *> Parser::parseArgumentDecl() {
1108 // Ensure that the argument is named.
1109 if (curToken.isNot(Token::identifier) && !curToken.isDependentKeyword())
1110 return emitError("expected identifier argument name");
1111
1112 // Parse the argument similarly to a normal variable.
1113 StringRef name = curToken.getSpelling();
1114 SMRange nameLoc = curToken.getLoc();
1115 consumeToken();
1116
1117 if (failed(
1118 parseToken(Token::colon, "expected `:` before argument constraint")))
1119 return failure();
1120
1121 FailureOr<ast::ConstraintRef> cst = parseArgOrResultConstraint();
1122 if (failed(cst))
1123 return failure();
1124
1125 return createArgOrResultVariableDecl(name, nameLoc, *cst);
1126}
1127
1128FailureOr<ast::VariableDecl *> Parser::parseResultDecl(unsigned resultNum) {
1129 // Check to see if this result is named.
1130 if (curToken.is(Token::identifier) || curToken.isDependentKeyword()) {
1131 // Check to see if this name actually refers to a Constraint.
1132 if (!curDeclScope->lookup<ast::ConstraintDecl>(curToken.getSpelling())) {
1133 // If it wasn't a constraint, parse the result similarly to a variable. If
1134 // there is already an existing decl, we will emit an error when defining
1135 // this variable later.
1136 StringRef name = curToken.getSpelling();
1137 SMRange nameLoc = curToken.getLoc();
1138 consumeToken();
1139
1140 if (failed(parseToken(Token::colon,
1141 "expected `:` before result constraint")))
1142 return failure();
1143
1144 FailureOr<ast::ConstraintRef> cst = parseArgOrResultConstraint();
1145 if (failed(cst))
1146 return failure();
1147
1148 return createArgOrResultVariableDecl(name, nameLoc, *cst);
1149 }
1150 }
1151
1152 // If it isn't named, we parse the constraint directly and create an unnamed
1153 // result variable.
1154 FailureOr<ast::ConstraintRef> cst = parseArgOrResultConstraint();
1155 if (failed(cst))
1156 return failure();
1157
1158 return createArgOrResultVariableDecl("", cst->referenceLoc, *cst);
1159}
1160
1161FailureOr<ast::UserConstraintDecl *>
1162Parser::parseUserConstraintDecl(bool isInline) {
1163 // Constraints and rewrites have very similar formats, dispatch to a shared
1164 // interface for parsing.
1165 return parseUserConstraintOrRewriteDecl<ast::UserConstraintDecl>(
1166 [&](auto &&...args) {
1167 return this->parseUserPDLLConstraintDecl(args...);
1168 },
1169 ParserContext::Constraint, "constraint", isInline);
1170}
1171
1172FailureOr<ast::UserConstraintDecl *> Parser::parseInlineUserConstraintDecl() {
1173 FailureOr<ast::UserConstraintDecl *> decl =
1174 parseUserConstraintDecl(/*isInline=*/true);
1175 if (failed(decl) || failed(checkDefineNamedDecl((*decl)->getName())))
1176 return failure();
1177
1178 curDeclScope->add(*decl);
1179 return decl;
1180}
1181
1182FailureOr<ast::UserConstraintDecl *> Parser::parseUserPDLLConstraintDecl(
1183 const ast::Name &name, bool isInline,
1184 ArrayRef<ast::VariableDecl *> arguments, ast::DeclScope *argumentScope,
1185 ArrayRef<ast::VariableDecl *> results, ast::Type resultType) {
1186 // Push the argument scope back onto the list, so that the body can
1187 // reference arguments.
1188 pushDeclScope(argumentScope);
1189
1190 // Parse the body of the constraint. The body is either defined as a compound
1191 // block, i.e. `{ ... }`, or a lambda body, i.e. `=> <expr>`.
1192 ast::CompoundStmt *body;
1193 if (curToken.is(Token::equal_arrow)) {
1194 FailureOr<ast::CompoundStmt *> bodyResult = parseLambdaBody(
1195 [&](ast::Stmt *&stmt) -> LogicalResult {
1196 ast::Expr *stmtExpr = dyn_cast<ast::Expr>(stmt);
1197 if (!stmtExpr) {
1198 return emitError(stmt->getLoc(),
1199 "expected `Constraint` lambda body to contain a "
1200 "single expression");
1201 }
1202 stmt = ast::ReturnStmt::create(ctx, stmt->getLoc(), stmtExpr);
1203 return success();
1204 },
1205 /*expectTerminalSemicolon=*/!isInline);
1206 if (failed(bodyResult))
1207 return failure();
1208 body = *bodyResult;
1209 } else {
1210 FailureOr<ast::CompoundStmt *> bodyResult = parseCompoundStmt();
1211 if (failed(bodyResult))
1212 return failure();
1213 body = *bodyResult;
1214
1215 // Verify the structure of the body.
1216 auto bodyIt = body->begin(), bodyE = body->end();
1217 for (; bodyIt != bodyE; ++bodyIt)
1218 if (isa<ast::ReturnStmt>(*bodyIt))
1219 break;
1220 if (failed(validateUserConstraintOrRewriteReturn(
1221 "Constraint", body, bodyIt, bodyE, results, resultType)))
1222 return failure();
1223 }
1224 popDeclScope();
1225
1226 return createUserPDLLConstraintOrRewriteDecl<ast::UserConstraintDecl>(
1227 name, arguments, results, resultType, body);
1228}
1229
1230FailureOr<ast::UserRewriteDecl *> Parser::parseUserRewriteDecl(bool isInline) {
1231 // Constraints and rewrites have very similar formats, dispatch to a shared
1232 // interface for parsing.
1233 return parseUserConstraintOrRewriteDecl<ast::UserRewriteDecl>(
1234 [&](auto &&...args) { return this->parseUserPDLLRewriteDecl(args...); },
1235 ParserContext::Rewrite, "rewrite", isInline);
1236}
1237
1238FailureOr<ast::UserRewriteDecl *> Parser::parseInlineUserRewriteDecl() {
1239 FailureOr<ast::UserRewriteDecl *> decl =
1240 parseUserRewriteDecl(/*isInline=*/true);
1241 if (failed(decl) || failed(checkDefineNamedDecl((*decl)->getName())))
1242 return failure();
1243
1244 curDeclScope->add(*decl);
1245 return decl;
1246}
1247
1248FailureOr<ast::UserRewriteDecl *> Parser::parseUserPDLLRewriteDecl(
1249 const ast::Name &name, bool isInline,
1250 ArrayRef<ast::VariableDecl *> arguments, ast::DeclScope *argumentScope,
1251 ArrayRef<ast::VariableDecl *> results, ast::Type resultType) {
1252 // Push the argument scope back onto the list, so that the body can
1253 // reference arguments.
1254 curDeclScope = argumentScope;
1255 ast::CompoundStmt *body;
1256 if (curToken.is(Token::equal_arrow)) {
1257 FailureOr<ast::CompoundStmt *> bodyResult = parseLambdaBody(
1258 [&](ast::Stmt *&statement) -> LogicalResult {
1259 if (isa<ast::OpRewriteStmt>(statement))
1260 return success();
1261
1262 ast::Expr *statementExpr = dyn_cast<ast::Expr>(statement);
1263 if (!statementExpr) {
1264 return emitError(
1265 statement->getLoc(),
1266 "expected `Rewrite` lambda body to contain a single expression "
1267 "or an operation rewrite statement; such as `erase`, "
1268 "`replace`, or `rewrite`");
1269 }
1270 statement =
1271 ast::ReturnStmt::create(ctx, statement->getLoc(), statementExpr);
1272 return success();
1273 },
1274 /*expectTerminalSemicolon=*/!isInline);
1275 if (failed(bodyResult))
1276 return failure();
1277 body = *bodyResult;
1278 } else {
1279 FailureOr<ast::CompoundStmt *> bodyResult = parseCompoundStmt();
1280 if (failed(bodyResult))
1281 return failure();
1282 body = *bodyResult;
1283 }
1284 popDeclScope();
1285
1286 // Verify the structure of the body.
1287 auto bodyIt = body->begin(), bodyE = body->end();
1288 for (; bodyIt != bodyE; ++bodyIt)
1289 if (isa<ast::ReturnStmt>(*bodyIt))
1290 break;
1291 if (failed(validateUserConstraintOrRewriteReturn("Rewrite", body, bodyIt,
1292 bodyE, results, resultType)))
1293 return failure();
1294 return createUserPDLLConstraintOrRewriteDecl<ast::UserRewriteDecl>(
1295 name, arguments, results, resultType, body);
1296}
1297
1298template <typename T, typename ParseUserPDLLDeclFnT>
1299FailureOr<T *> Parser::parseUserConstraintOrRewriteDecl(
1300 ParseUserPDLLDeclFnT &&parseUserPDLLFn, ParserContext declContext,
1301 StringRef anonymousNamePrefix, bool isInline) {
1302 SMRange loc = curToken.getLoc();
1303 consumeToken();
1304 llvm::SaveAndRestore saveCtx(parserContext, declContext);
1305
1306 // Parse the name of the decl.
1307 const ast::Name *name = nullptr;
1308 if (curToken.isNot(Token::identifier)) {
1309 // Only inline decls can be un-named. Inline decls are similar to "lambdas"
1310 // in C++, so being unnamed is fine.
1311 if (!isInline)
1312 return emitError("expected identifier name");
1313
1314 // Create a unique anonymous name to use, as the name for this decl is not
1315 // important.
1316 std::string anonName =
1317 llvm::formatv("<anonymous_{0}_{1}>", anonymousNamePrefix,
1318 anonymousDeclNameCounter++)
1319 .str();
1320 name = &ast::Name::create(ctx, anonName, loc);
1321 } else {
1322 // If a name was provided, we can use it directly.
1323 name = &ast::Name::create(ctx, curToken.getSpelling(), curToken.getLoc());
1324 consumeToken(Token::identifier);
1325 }
1326
1327 // Parse the functional signature of the decl.
1328 SmallVector<ast::VariableDecl *> arguments, results;
1329 ast::DeclScope *argumentScope;
1330 ast::Type resultType;
1331 if (failed(parseUserConstraintOrRewriteSignature(arguments, results,
1332 argumentScope, resultType)))
1333 return failure();
1334
1335 // Check to see which type of constraint this is. If the constraint contains a
1336 // compound body, this is a PDLL decl.
1338 return parseUserPDLLFn(*name, isInline, arguments, argumentScope, results,
1339 resultType);
1340
1341 // Otherwise, this is a native decl.
1342 return parseUserNativeConstraintOrRewriteDecl<T>(*name, isInline, arguments,
1343 results, resultType);
1344}
1345
1346template <typename T>
1347FailureOr<T *> Parser::parseUserNativeConstraintOrRewriteDecl(
1348 const ast::Name &name, bool isInline,
1349 ArrayRef<ast::VariableDecl *> arguments,
1350 ArrayRef<ast::VariableDecl *> results, ast::Type resultType) {
1351 // If followed by a string, the native code body has also been specified.
1352 std::string codeStrStorage;
1353 std::optional<StringRef> optCodeStr;
1354 if (curToken.isString()) {
1355 codeStrStorage = curToken.getStringValue();
1356 optCodeStr = codeStrStorage;
1357 consumeToken();
1358 } else if (isInline) {
1359 return emitError(name.getLoc(),
1360 "external declarations must be declared in global scope");
1361 } else if (curToken.is(Token::error)) {
1362 return failure();
1363 }
1364 if (failed(parseToken(Token::semicolon,
1365 "expected `;` after native declaration")))
1366 return failure();
1367 return T::createNative(ctx, name, arguments, results, optCodeStr, resultType);
1368}
1369
1370LogicalResult Parser::parseUserConstraintOrRewriteSignature(
1371 SmallVectorImpl<ast::VariableDecl *> &arguments,
1372 SmallVectorImpl<ast::VariableDecl *> &results,
1373 ast::DeclScope *&argumentScope, ast::Type &resultType) {
1374 // Parse the argument list of the decl.
1375 if (failed(parseToken(Token::l_paren, "expected `(` to start argument list")))
1376 return failure();
1377
1378 argumentScope = pushDeclScope();
1379 if (curToken.isNot(Token::r_paren)) {
1380 do {
1381 FailureOr<ast::VariableDecl *> argument = parseArgumentDecl();
1382 if (failed(argument))
1383 return failure();
1384 arguments.emplace_back(*argument);
1385 } while (consumeIf(Token::comma));
1386 }
1387 popDeclScope();
1388 if (failed(parseToken(Token::r_paren, "expected `)` to end argument list")))
1389 return failure();
1390
1391 // Parse the results of the decl.
1392 pushDeclScope();
1393 if (consumeIf(Token::arrow)) {
1394 auto parseResultFn = [&]() -> LogicalResult {
1395 FailureOr<ast::VariableDecl *> result = parseResultDecl(results.size());
1396 if (failed(result))
1397 return failure();
1398 results.emplace_back(*result);
1399 return success();
1400 };
1401
1402 // Check for a list of results.
1403 if (consumeIf(Token::l_paren)) {
1404 do {
1405 if (failed(parseResultFn()))
1406 return failure();
1407 } while (consumeIf(Token::comma));
1408 if (failed(parseToken(Token::r_paren, "expected `)` to end result list")))
1409 return failure();
1410
1411 // Otherwise, there is only one result.
1412 } else if (failed(parseResultFn())) {
1413 return failure();
1414 }
1415 }
1416 popDeclScope();
1417
1418 // Compute the result type of the decl.
1419 resultType = createUserConstraintRewriteResultType(results);
1420
1421 // Verify that results are only named if there are more than one.
1422 if (results.size() == 1 && !results.front()->getName().getName().empty()) {
1423 return emitError(
1424 results.front()->getLoc(),
1425 "cannot create a single-element tuple with an element label");
1426 }
1427 return success();
1428}
1429
1430LogicalResult Parser::validateUserConstraintOrRewriteReturn(
1431 StringRef declType, ast::CompoundStmt *body,
1432 ArrayRef<ast::Stmt *>::iterator bodyIt,
1433 ArrayRef<ast::Stmt *>::iterator bodyE,
1434 ArrayRef<ast::VariableDecl *> results, ast::Type &resultType) {
1435 // Handle if a `return` was provided.
1436 if (bodyIt != bodyE) {
1437 // Emit an error if we have trailing statements after the return.
1438 if (std::next(bodyIt) != bodyE) {
1439 return emitError(
1440 (*std::next(bodyIt))->getLoc(),
1441 llvm::formatv("`return` terminated the `{0}` body, but found "
1442 "trailing statements afterwards",
1443 declType));
1444 }
1445
1446 // Otherwise if a return wasn't provided, check that no results are
1447 // expected.
1448 } else if (!results.empty()) {
1449 return emitError(
1450 {body->getLoc().End, body->getLoc().End},
1451 llvm::formatv("missing return in a `{0}` expected to return `{1}`",
1452 declType, resultType));
1453 }
1454 return success();
1455}
1456
1457FailureOr<ast::CompoundStmt *> Parser::parsePatternLambdaBody() {
1458 return parseLambdaBody([&](ast::Stmt *&statement) -> LogicalResult {
1459 if (isa<ast::OpRewriteStmt>(statement))
1460 return success();
1461 return emitError(
1462 statement->getLoc(),
1463 "expected Pattern lambda body to contain a single operation "
1464 "rewrite statement, such as `erase`, `replace`, or `rewrite`");
1465 });
1466}
1467
1468FailureOr<ast::Decl *> Parser::parsePatternDecl() {
1469 SMRange loc = curToken.getLoc();
1470 consumeToken(Token::kw_Pattern);
1471 llvm::SaveAndRestore saveCtx(parserContext, ParserContext::PatternMatch);
1472
1473 // Check for an optional identifier for the pattern name.
1474 const ast::Name *name = nullptr;
1475 if (curToken.is(Token::identifier)) {
1476 name = &ast::Name::create(ctx, curToken.getSpelling(), curToken.getLoc());
1477 consumeToken(Token::identifier);
1478 }
1479
1480 // Parse any pattern metadata.
1481 ParsedPatternMetadata metadata;
1482 if (consumeIf(Token::kw_with) && failed(parsePatternDeclMetadata(metadata)))
1483 return failure();
1484
1485 // Parse the pattern body.
1486 ast::CompoundStmt *body;
1487
1488 // Handle a lambda body.
1489 if (curToken.is(Token::equal_arrow)) {
1490 FailureOr<ast::CompoundStmt *> bodyResult = parsePatternLambdaBody();
1491 if (failed(bodyResult))
1492 return failure();
1493 body = *bodyResult;
1494 } else {
1495 if (curToken.isNot(Token::l_brace))
1496 return emitError("expected `{` or `=>` to start pattern body");
1497 FailureOr<ast::CompoundStmt *> bodyResult = parseCompoundStmt();
1498 if (failed(bodyResult))
1499 return failure();
1500 body = *bodyResult;
1501
1502 // Verify the body of the pattern.
1503 auto bodyIt = body->begin(), bodyE = body->end();
1504 for (; bodyIt != bodyE; ++bodyIt) {
1505 if (isa<ast::ReturnStmt>(*bodyIt)) {
1506 return emitError((*bodyIt)->getLoc(),
1507 "`return` statements are only permitted within a "
1508 "`Constraint` or `Rewrite` body");
1509 }
1510 // Break when we've found the rewrite statement.
1511 if (isa<ast::OpRewriteStmt>(*bodyIt))
1512 break;
1513 }
1514 if (bodyIt == bodyE) {
1515 return emitError(loc,
1516 "expected Pattern body to terminate with an operation "
1517 "rewrite statement, such as `erase`");
1518 }
1519 if (std::next(bodyIt) != bodyE) {
1520 return emitError((*std::next(bodyIt))->getLoc(),
1521 "Pattern body was terminated by an operation "
1522 "rewrite statement, but found trailing statements");
1523 }
1524 }
1525
1526 return createPatternDecl(loc, name, metadata, body);
1527}
1528
1529LogicalResult
1530Parser::parsePatternDeclMetadata(ParsedPatternMetadata &metadata) {
1531 std::optional<SMRange> benefitLoc;
1532 std::optional<SMRange> hasBoundedRecursionLoc;
1533
1534 do {
1535 // Handle metadata code completion.
1536 if (curToken.is(Token::code_complete))
1537 return codeCompletePatternMetadata();
1538
1539 if (curToken.isNot(Token::identifier))
1540 return emitError("expected pattern metadata identifier");
1541 StringRef metadataStr = curToken.getSpelling();
1542 SMRange metadataLoc = curToken.getLoc();
1543 consumeToken(Token::identifier);
1544
1545 // Parse the benefit metadata: benefit(<integer-value>)
1546 if (metadataStr == "benefit") {
1547 if (benefitLoc) {
1548 return emitErrorAndNote(metadataLoc,
1549 "pattern benefit has already been specified",
1550 *benefitLoc, "see previous definition here");
1551 }
1552 if (failed(parseToken(Token::l_paren,
1553 "expected `(` before pattern benefit")))
1554 return failure();
1555
1556 uint16_t benefitValue = 0;
1557 if (curToken.isNot(Token::integer))
1558 return emitError("expected integral pattern benefit");
1559 if (curToken.getSpelling().getAsInteger(/*Radix=*/10, benefitValue))
1560 return emitError(
1561 "expected pattern benefit to fit within a 16-bit integer");
1562 consumeToken(Token::integer);
1563
1564 metadata.benefit = benefitValue;
1565 benefitLoc = metadataLoc;
1566
1567 if (failed(
1568 parseToken(Token::r_paren, "expected `)` after pattern benefit")))
1569 return failure();
1570 continue;
1571 }
1572
1573 // Parse the bounded recursion metadata: recursion
1574 if (metadataStr == "recursion") {
1575 if (hasBoundedRecursionLoc) {
1576 return emitErrorAndNote(
1577 metadataLoc,
1578 "pattern recursion metadata has already been specified",
1579 *hasBoundedRecursionLoc, "see previous definition here");
1580 }
1581 metadata.hasBoundedRecursion = true;
1582 hasBoundedRecursionLoc = metadataLoc;
1583 continue;
1584 }
1585
1586 return emitError(metadataLoc, "unknown pattern metadata");
1587 } while (consumeIf(Token::comma));
1588
1589 return success();
1590}
1591
1592FailureOr<ast::Expr *> Parser::parseTypeConstraintExpr() {
1593 consumeToken(Token::less);
1594
1595 FailureOr<ast::Expr *> typeExpr = parseExpr();
1596 if (failed(typeExpr) ||
1597 failed(parseToken(Token::greater,
1598 "expected `>` after variable type constraint")))
1599 return failure();
1600 return typeExpr;
1601}
1602
1603LogicalResult Parser::checkDefineNamedDecl(const ast::Name &name) {
1604 assert(curDeclScope && "defining decl outside of a decl scope");
1605 if (ast::Decl *lastDecl = curDeclScope->lookup(name.getName())) {
1606 return emitErrorAndNote(
1607 name.getLoc(), "`" + name.getName() + "` has already been defined",
1608 lastDecl->getName()->getLoc(), "see previous definition here");
1609 }
1610 return success();
1611}
1612
1613FailureOr<ast::VariableDecl *>
1614Parser::defineVariableDecl(StringRef name, SMRange nameLoc, ast::Type type,
1615 ast::Expr *initExpr,
1616 ArrayRef<ast::ConstraintRef> constraints) {
1617 assert(curDeclScope && "defining variable outside of decl scope");
1618 const ast::Name &nameDecl = ast::Name::create(ctx, name, nameLoc);
1619
1620 // If the name of the variable indicates a special variable, we don't add it
1621 // to the scope. This variable is local to the definition point.
1622 if (name.empty() || name == "_") {
1623 return ast::VariableDecl::create(ctx, nameDecl, type, initExpr,
1624 constraints);
1625 }
1626 if (failed(checkDefineNamedDecl(nameDecl)))
1627 return failure();
1628
1629 auto *varDecl =
1630 ast::VariableDecl::create(ctx, nameDecl, type, initExpr, constraints);
1631 curDeclScope->add(varDecl);
1632 return varDecl;
1633}
1634
1635FailureOr<ast::VariableDecl *>
1636Parser::defineVariableDecl(StringRef name, SMRange nameLoc, ast::Type type,
1637 ArrayRef<ast::ConstraintRef> constraints) {
1638 return defineVariableDecl(name, nameLoc, type, /*initExpr=*/nullptr,
1639 constraints);
1640}
1641
1642LogicalResult Parser::parseVariableDeclConstraintList(
1643 SmallVectorImpl<ast::ConstraintRef> &constraints) {
1644 std::optional<SMRange> typeConstraint;
1645 auto parseSingleConstraint = [&] {
1646 FailureOr<ast::ConstraintRef> constraint = parseConstraint(
1647 typeConstraint, constraints, /*allowInlineTypeConstraints=*/true);
1648 if (failed(constraint))
1649 return failure();
1650 constraints.push_back(*constraint);
1651 return success();
1652 };
1653
1654 // Check to see if this is a single constraint, or a list.
1655 if (!consumeIf(Token::l_square))
1656 return parseSingleConstraint();
1657
1658 do {
1659 if (failed(parseSingleConstraint()))
1660 return failure();
1661 } while (consumeIf(Token::comma));
1662 return parseToken(Token::r_square, "expected `]` after constraint list");
1663}
1664
1665FailureOr<ast::ConstraintRef>
1666Parser::parseConstraint(std::optional<SMRange> &typeConstraint,
1667 ArrayRef<ast::ConstraintRef> existingConstraints,
1668 bool allowInlineTypeConstraints) {
1669 auto parseTypeConstraint = [&](ast::Expr *&typeExpr) -> LogicalResult {
1670 if (!allowInlineTypeConstraints) {
1671 return emitError(
1672 curToken.getLoc(),
1673 "inline `Attr`, `Value`, and `ValueRange` type constraints are not "
1674 "permitted on arguments or results");
1675 }
1676 if (typeConstraint)
1677 return emitErrorAndNote(
1678 curToken.getLoc(),
1679 "the type of this variable has already been constrained",
1680 *typeConstraint, "see previous constraint location here");
1681 FailureOr<ast::Expr *> constraintExpr = parseTypeConstraintExpr();
1682 if (failed(constraintExpr))
1683 return failure();
1684 typeExpr = *constraintExpr;
1685 typeConstraint = typeExpr->getLoc();
1686 return success();
1687 };
1688
1689 SMRange loc = curToken.getLoc();
1690 switch (curToken.getKind()) {
1691 case Token::kw_Attr: {
1692 consumeToken(Token::kw_Attr);
1693
1694 // Check for a type constraint.
1695 ast::Expr *typeExpr = nullptr;
1696 if (curToken.is(Token::less) && failed(parseTypeConstraint(typeExpr)))
1697 return failure();
1698 return ast::ConstraintRef(
1699 ast::AttrConstraintDecl::create(ctx, loc, typeExpr), loc);
1700 }
1701 case Token::kw_Op: {
1702 consumeToken(Token::kw_Op);
1703
1704 // Parse an optional operation name. If the name isn't provided, this refers
1705 // to "any" operation.
1706 FailureOr<ast::OpNameDecl *> opName =
1707 parseWrappedOperationName(/*allowEmptyName=*/true);
1708 if (failed(opName))
1709 return failure();
1710
1711 return ast::ConstraintRef(ast::OpConstraintDecl::create(ctx, loc, *opName),
1712 loc);
1713 }
1714 case Token::kw_Type:
1715 consumeToken(Token::kw_Type);
1716 return ast::ConstraintRef(ast::TypeConstraintDecl::create(ctx, loc), loc);
1718 consumeToken(Token::kw_TypeRange);
1719 return ast::ConstraintRef(ast::TypeRangeConstraintDecl::create(ctx, loc),
1720 loc);
1721 case Token::kw_Value: {
1722 consumeToken(Token::kw_Value);
1723
1724 // Check for a type constraint.
1725 ast::Expr *typeExpr = nullptr;
1726 if (curToken.is(Token::less) && failed(parseTypeConstraint(typeExpr)))
1727 return failure();
1728
1729 return ast::ConstraintRef(
1730 ast::ValueConstraintDecl::create(ctx, loc, typeExpr), loc);
1731 }
1732 case Token::kw_ValueRange: {
1733 consumeToken(Token::kw_ValueRange);
1734
1735 // Check for a type constraint.
1736 ast::Expr *typeExpr = nullptr;
1737 if (curToken.is(Token::less) && failed(parseTypeConstraint(typeExpr)))
1738 return failure();
1739
1740 return ast::ConstraintRef(
1741 ast::ValueRangeConstraintDecl::create(ctx, loc, typeExpr), loc);
1742 }
1743
1744 case Token::kw_Constraint: {
1745 // Handle an inline constraint.
1746 FailureOr<ast::UserConstraintDecl *> decl = parseInlineUserConstraintDecl();
1747 if (failed(decl))
1748 return failure();
1749 return ast::ConstraintRef(*decl, loc);
1750 }
1751 case Token::identifier: {
1752 StringRef constraintName = curToken.getSpelling();
1753 consumeToken(Token::identifier);
1754
1755 // Lookup the referenced constraint.
1756 ast::Decl *cstDecl = curDeclScope->lookup<ast::Decl>(constraintName);
1757 if (!cstDecl) {
1758 return emitError(loc, "unknown reference to constraint `" +
1759 constraintName + "`");
1760 }
1761
1762 // Handle a reference to a proper constraint.
1763 if (auto *cst = dyn_cast<ast::ConstraintDecl>(cstDecl))
1764 return ast::ConstraintRef(cst, loc);
1765
1766 return emitErrorAndNote(
1767 loc, "invalid reference to non-constraint", cstDecl->getLoc(),
1768 "see the definition of `" + constraintName + "` here");
1769 }
1770 // Handle single entity constraint code completion.
1771 case Token::code_complete: {
1772 // Try to infer the current type for use by code completion.
1773 ast::Type inferredType;
1774 if (failed(validateVariableConstraints(existingConstraints, inferredType)))
1775 return failure();
1776
1777 return codeCompleteConstraintName(inferredType, allowInlineTypeConstraints);
1778 }
1779 default:
1780 break;
1781 }
1782 return emitError(loc, "expected identifier constraint");
1783}
1784
1785FailureOr<ast::ConstraintRef> Parser::parseArgOrResultConstraint() {
1786 std::optional<SMRange> typeConstraint;
1787 return parseConstraint(typeConstraint, /*existingConstraints=*/{},
1788 /*allowInlineTypeConstraints=*/false);
1789}
1790
1791//===----------------------------------------------------------------------===//
1792// Exprs
1793//===----------------------------------------------------------------------===//
1794
1795FailureOr<ast::Expr *> Parser::parseExpr() {
1796 if (curToken.is(Token::underscore))
1797 return parseUnderscoreExpr();
1798
1799 // Parse the LHS expression.
1800 FailureOr<ast::Expr *> lhsExpr;
1801 switch (curToken.getKind()) {
1802 case Token::kw_attr:
1803 lhsExpr = parseAttributeExpr();
1804 break;
1806 lhsExpr = parseInlineConstraintLambdaExpr();
1807 break;
1808 case Token::kw_not:
1809 lhsExpr = parseNegatedExpr();
1810 break;
1811 case Token::identifier:
1812 lhsExpr = parseIdentifierExpr();
1813 break;
1814 case Token::kw_op:
1815 lhsExpr = parseOperationExpr();
1816 break;
1817 case Token::kw_Rewrite:
1818 lhsExpr = parseInlineRewriteLambdaExpr();
1819 break;
1820 case Token::kw_type:
1821 lhsExpr = parseTypeExpr();
1822 break;
1823 case Token::l_paren:
1824 lhsExpr = parseTupleExpr();
1825 break;
1826 default:
1827 return emitError("expected expression");
1828 }
1829 if (failed(lhsExpr))
1830 return failure();
1831
1832 // Check for an operator expression.
1833 while (true) {
1834 switch (curToken.getKind()) {
1835 case Token::dot:
1836 lhsExpr = parseMemberAccessExpr(*lhsExpr);
1837 break;
1838 case Token::l_paren:
1839 lhsExpr = parseCallExpr(*lhsExpr);
1840 break;
1841 default:
1842 return lhsExpr;
1843 }
1844 if (failed(lhsExpr))
1845 return failure();
1846 }
1847}
1848
1849FailureOr<ast::Expr *> Parser::parseAttributeExpr() {
1850 SMRange loc = curToken.getLoc();
1851 consumeToken(Token::kw_attr);
1852
1853 // If we aren't followed by a `<`, the `attr` keyword is treated as a normal
1854 // identifier.
1855 if (!consumeIf(Token::less)) {
1856 resetToken(loc);
1857 return parseIdentifierExpr();
1858 }
1859
1860 if (!curToken.isString())
1861 return emitError("expected string literal containing MLIR attribute");
1862 std::string attrExpr = curToken.getStringValue();
1863 consumeToken();
1864
1865 loc.End = curToken.getEndLoc();
1866 if (failed(
1867 parseToken(Token::greater, "expected `>` after attribute literal")))
1868 return failure();
1869 return ast::AttributeExpr::create(ctx, loc, attrExpr);
1870}
1871
1872FailureOr<ast::Expr *> Parser::parseCallExpr(ast::Expr *parentExpr,
1873 bool isNegated) {
1874 consumeToken(Token::l_paren);
1875
1876 // Parse the arguments of the call.
1877 SmallVector<ast::Expr *> arguments;
1878 if (curToken.isNot(Token::r_paren)) {
1879 do {
1880 // Handle code completion for the call arguments.
1881 if (curToken.is(Token::code_complete)) {
1882 codeCompleteCallSignature(parentExpr, arguments.size());
1883 return failure();
1884 }
1885
1886 FailureOr<ast::Expr *> argument = parseExpr();
1887 if (failed(argument))
1888 return failure();
1889 arguments.push_back(*argument);
1890 } while (consumeIf(Token::comma));
1891 }
1892
1893 SMRange loc(parentExpr->getLoc().Start, curToken.getEndLoc());
1894 if (failed(parseToken(Token::r_paren, "expected `)` after argument list")))
1895 return failure();
1896
1897 return createCallExpr(loc, parentExpr, arguments, isNegated);
1898}
1899
1900FailureOr<ast::Expr *> Parser::parseDeclRefExpr(StringRef name, SMRange loc) {
1901 ast::Decl *decl = curDeclScope->lookup(name);
1902 if (!decl)
1903 return emitError(loc, "undefined reference to `" + name + "`");
1904
1905 return createDeclRefExpr(loc, decl);
1906}
1907
1908FailureOr<ast::Expr *> Parser::parseIdentifierExpr() {
1909 StringRef name = curToken.getSpelling();
1910 SMRange nameLoc = curToken.getLoc();
1911 consumeToken();
1912
1913 // Check to see if this is a decl ref expression that defines a variable
1914 // inline.
1915 if (consumeIf(Token::colon)) {
1916 SmallVector<ast::ConstraintRef> constraints;
1917 if (failed(parseVariableDeclConstraintList(constraints)))
1918 return failure();
1919 ast::Type type;
1920 if (failed(validateVariableConstraints(constraints, type)))
1921 return failure();
1922 return createInlineVariableExpr(type, name, nameLoc, constraints);
1923 }
1924
1925 return parseDeclRefExpr(name, nameLoc);
1926}
1927
1928FailureOr<ast::Expr *> Parser::parseInlineConstraintLambdaExpr() {
1929 FailureOr<ast::UserConstraintDecl *> decl = parseInlineUserConstraintDecl();
1930 if (failed(decl))
1931 return failure();
1932
1933 return ast::DeclRefExpr::create(ctx, (*decl)->getLoc(), *decl,
1935}
1936
1937FailureOr<ast::Expr *> Parser::parseInlineRewriteLambdaExpr() {
1938 FailureOr<ast::UserRewriteDecl *> decl = parseInlineUserRewriteDecl();
1939 if (failed(decl))
1940 return failure();
1941
1942 return ast::DeclRefExpr::create(ctx, (*decl)->getLoc(), *decl,
1944}
1945
1946FailureOr<ast::Expr *> Parser::parseMemberAccessExpr(ast::Expr *parentExpr) {
1947 SMRange dotLoc = curToken.getLoc();
1948 consumeToken(Token::dot);
1949
1950 // Check for code completion of the member name.
1951 if (curToken.is(Token::code_complete))
1952 return codeCompleteMemberAccess(parentExpr);
1953
1954 // Parse the member name.
1955 Token memberNameTok = curToken;
1956 if (memberNameTok.isNot(Token::identifier, Token::integer) &&
1957 !memberNameTok.isKeyword())
1958 return emitError(dotLoc, "expected identifier or numeric member name");
1959 StringRef memberName = memberNameTok.getSpelling();
1960 SMRange loc(parentExpr->getLoc().Start, curToken.getEndLoc());
1961 consumeToken();
1962
1963 return createMemberAccessExpr(parentExpr, memberName, loc);
1964}
1965
1966FailureOr<ast::Expr *> Parser::parseNegatedExpr() {
1967 consumeToken(Token::kw_not);
1968 // Only native constraints are supported after negation
1969 if (!curToken.is(Token::identifier))
1970 return emitError("expected native constraint");
1971 FailureOr<ast::Expr *> identifierExpr = parseIdentifierExpr();
1972 if (failed(identifierExpr))
1973 return failure();
1974 if (!curToken.is(Token::l_paren))
1975 return emitError("expected `(` after function name");
1976 return parseCallExpr(*identifierExpr, /*isNegated = */ true);
1977}
1978
1979FailureOr<ast::OpNameDecl *> Parser::parseOperationName(bool allowEmptyName) {
1980 SMRange loc = curToken.getLoc();
1981
1982 // Check for code completion for the dialect name.
1983 if (curToken.is(Token::code_complete))
1984 return codeCompleteDialectName();
1985
1986 // Handle the case of an no operation name.
1987 if (curToken.isNot(Token::identifier) && !curToken.isKeyword()) {
1988 if (allowEmptyName)
1989 return ast::OpNameDecl::create(ctx, SMRange());
1990 return emitError("expected dialect namespace");
1991 }
1992 StringRef name = curToken.getSpelling();
1993 consumeToken();
1994
1995 // Otherwise, this is a literal operation name.
1996 if (failed(parseToken(Token::dot, "expected `.` after dialect namespace")))
1997 return failure();
1998
1999 // Check for code completion for the operation name.
2000 if (curToken.is(Token::code_complete))
2001 return codeCompleteOperationName(name);
2002
2003 if (curToken.isNot(Token::identifier) && !curToken.isKeyword())
2004 return emitError("expected operation name after dialect namespace");
2005
2006 name = StringRef(name.data(), name.size() + 1);
2007 do {
2008 name = StringRef(name.data(), name.size() + curToken.getSpelling().size());
2009 loc.End = curToken.getEndLoc();
2010 consumeToken();
2011 } while (curToken.isAny(Token::identifier, Token::dot) ||
2012 curToken.isKeyword());
2013 return ast::OpNameDecl::create(ctx, ast::Name::create(ctx, name, loc));
2014}
2015
2016FailureOr<ast::OpNameDecl *>
2017Parser::parseWrappedOperationName(bool allowEmptyName) {
2018 if (!consumeIf(Token::less))
2019 return ast::OpNameDecl::create(ctx, SMRange());
2020
2021 FailureOr<ast::OpNameDecl *> opNameDecl = parseOperationName(allowEmptyName);
2022 if (failed(opNameDecl))
2023 return failure();
2024
2025 if (failed(parseToken(Token::greater, "expected `>` after operation name")))
2026 return failure();
2027 return opNameDecl;
2028}
2029
2030FailureOr<ast::Expr *>
2031Parser::parseOperationExpr(OpResultTypeContext inputResultTypeContext) {
2032 SMRange loc = curToken.getLoc();
2033 consumeToken(Token::kw_op);
2034
2035 // If it isn't followed by a `<`, the `op` keyword is treated as a normal
2036 // identifier.
2037 if (curToken.isNot(Token::less)) {
2038 resetToken(loc);
2039 return parseIdentifierExpr();
2040 }
2041
2042 // Parse the operation name. The name may be elided, in which case the
2043 // operation refers to "any" operation(i.e. a difference between `MyOp` and
2044 // `Operation*`). Operation names within a rewrite context must be named.
2045 bool allowEmptyName = parserContext != ParserContext::Rewrite;
2046 FailureOr<ast::OpNameDecl *> opNameDecl =
2047 parseWrappedOperationName(allowEmptyName);
2048 if (failed(opNameDecl))
2049 return failure();
2050 std::optional<StringRef> opName = (*opNameDecl)->getName();
2051
2052 // Functor used to create an implicit range variable, used for implicit "all"
2053 // operand or results variables.
2054 auto createImplicitRangeVar = [&](ast::ConstraintDecl *cst, ast::Type type) {
2055 FailureOr<ast::VariableDecl *> rangeVar =
2056 defineVariableDecl("_", loc, type, ast::ConstraintRef(cst, loc));
2057 assert(succeeded(rangeVar) && "expected range variable to be valid");
2058 return ast::DeclRefExpr::create(ctx, loc, *rangeVar, type);
2059 };
2060
2061 // Check for the optional list of operands.
2062 SmallVector<ast::Expr *> operands;
2063 if (!consumeIf(Token::l_paren)) {
2064 // If the operand list isn't specified and we are in a match context, define
2065 // an inplace unconstrained operand range corresponding to all of the
2066 // operands of the operation. This avoids treating zero operands the same
2067 // way as "unconstrained operands".
2068 if (parserContext != ParserContext::Rewrite) {
2069 operands.push_back(createImplicitRangeVar(
2070 ast::ValueRangeConstraintDecl::create(ctx, loc), valueRangeTy));
2071 }
2072 } else if (!consumeIf(Token::r_paren)) {
2073 // If the operand list was specified and non-empty, parse the operands.
2074 do {
2075 // Check for operand signature code completion.
2076 if (curToken.is(Token::code_complete)) {
2077 codeCompleteOperationOperandsSignature(opName, operands.size());
2078 return failure();
2079 }
2080
2081 FailureOr<ast::Expr *> operand = parseExpr();
2082 if (failed(operand))
2083 return failure();
2084 operands.push_back(*operand);
2085 } while (consumeIf(Token::comma));
2086
2087 if (failed(parseToken(Token::r_paren,
2088 "expected `)` after operation operand list")))
2089 return failure();
2090 }
2091
2092 // Check for the optional list of attributes.
2093 SmallVector<ast::NamedAttributeDecl *> attributes;
2094 if (consumeIf(Token::l_brace)) {
2095 do {
2096 FailureOr<ast::NamedAttributeDecl *> decl =
2097 parseNamedAttributeDecl(opName);
2098 if (failed(decl))
2099 return failure();
2100 attributes.emplace_back(*decl);
2101 } while (consumeIf(Token::comma));
2102
2103 if (failed(parseToken(Token::r_brace,
2104 "expected `}` after operation attribute list")))
2105 return failure();
2106 }
2107
2108 // Handle the result types of the operation.
2109 SmallVector<ast::Expr *> resultTypes;
2110 OpResultTypeContext resultTypeContext = inputResultTypeContext;
2111
2112 // Check for an explicit list of result types.
2113 if (consumeIf(Token::arrow)) {
2114 if (failed(parseToken(Token::l_paren,
2115 "expected `(` before operation result type list")))
2116 return failure();
2117
2118 // If result types are provided, initially assume that the operation does
2119 // not rely on type inferrence. We don't assert that it isn't, because we
2120 // may be inferring the value of some type/type range variables, but given
2121 // that these variables may be defined in calls we can't always discern when
2122 // this is the case.
2123 resultTypeContext = OpResultTypeContext::Explicit;
2124
2125 // Handle the case of an empty result list.
2126 if (!consumeIf(Token::r_paren)) {
2127 do {
2128 // Check for result signature code completion.
2129 if (curToken.is(Token::code_complete)) {
2130 codeCompleteOperationResultsSignature(opName, resultTypes.size());
2131 return failure();
2132 }
2133
2134 FailureOr<ast::Expr *> resultTypeExpr = parseExpr();
2135 if (failed(resultTypeExpr))
2136 return failure();
2137 resultTypes.push_back(*resultTypeExpr);
2138 } while (consumeIf(Token::comma));
2139
2140 if (failed(parseToken(Token::r_paren,
2141 "expected `)` after operation result type list")))
2142 return failure();
2143 }
2144 } else if (parserContext != ParserContext::Rewrite) {
2145 // If the result list isn't specified and we are in a match context, define
2146 // an inplace unconstrained result range corresponding to all of the results
2147 // of the operation. This avoids treating zero results the same way as
2148 // "unconstrained results".
2149 resultTypes.push_back(createImplicitRangeVar(
2150 ast::TypeRangeConstraintDecl::create(ctx, loc), typeRangeTy));
2151 } else if (resultTypeContext == OpResultTypeContext::Explicit) {
2152 // If the result list isn't specified and we are in a rewrite, try to infer
2153 // them at runtime instead.
2154 resultTypeContext = OpResultTypeContext::Interface;
2155 }
2156
2157 return createOperationExpr(loc, *opNameDecl, resultTypeContext, operands,
2158 attributes, resultTypes);
2159}
2160
2161FailureOr<ast::Expr *> Parser::parseTupleExpr() {
2162 SMRange loc = curToken.getLoc();
2163 consumeToken(Token::l_paren);
2164
2166 SmallVector<StringRef> elementNames;
2167 SmallVector<ast::Expr *> elements;
2168 if (curToken.isNot(Token::r_paren)) {
2169 do {
2170 // Check for the optional element name assignment before the value.
2171 StringRef elementName;
2172 if (curToken.is(Token::identifier) || curToken.isDependentKeyword()) {
2173 Token elementNameTok = curToken;
2174 consumeToken();
2175
2176 // The element name is only present if followed by an `=`.
2177 if (consumeIf(Token::equal)) {
2178 elementName = elementNameTok.getSpelling();
2179
2180 // Check to see if this name is already used.
2181 auto elementNameIt =
2182 usedNames.try_emplace(elementName, elementNameTok.getLoc());
2183 if (!elementNameIt.second) {
2184 return emitErrorAndNote(
2185 elementNameTok.getLoc(),
2186 llvm::formatv("duplicate tuple element label `{0}`",
2187 elementName),
2188 elementNameIt.first->getSecond(),
2189 "see previous label use here");
2190 }
2191 } else {
2192 // Otherwise, we treat this as part of an expression so reset the
2193 // lexer.
2194 resetToken(elementNameTok.getLoc());
2195 }
2196 }
2197 elementNames.push_back(elementName);
2198
2199 // Parse the tuple element value.
2200 FailureOr<ast::Expr *> element = parseExpr();
2201 if (failed(element))
2202 return failure();
2203 elements.push_back(*element);
2204 } while (consumeIf(Token::comma));
2205 }
2206 loc.End = curToken.getEndLoc();
2207 if (failed(
2208 parseToken(Token::r_paren, "expected `)` after tuple element list")))
2209 return failure();
2210 return createTupleExpr(loc, elements, elementNames);
2211}
2212
2213FailureOr<ast::Expr *> Parser::parseTypeExpr() {
2214 SMRange loc = curToken.getLoc();
2215 consumeToken(Token::kw_type);
2216
2217 // If we aren't followed by a `<`, the `type` keyword is treated as a normal
2218 // identifier.
2219 if (!consumeIf(Token::less)) {
2220 resetToken(loc);
2221 return parseIdentifierExpr();
2222 }
2223
2224 if (!curToken.isString())
2225 return emitError("expected string literal containing MLIR type");
2226 std::string attrExpr = curToken.getStringValue();
2227 consumeToken();
2228
2229 loc.End = curToken.getEndLoc();
2230 if (failed(parseToken(Token::greater, "expected `>` after type literal")))
2231 return failure();
2232 return ast::TypeExpr::create(ctx, loc, attrExpr);
2233}
2234
2235FailureOr<ast::Expr *> Parser::parseUnderscoreExpr() {
2236 StringRef name = curToken.getSpelling();
2237 SMRange nameLoc = curToken.getLoc();
2238 consumeToken(Token::underscore);
2239
2240 // Underscore expressions require a constraint list.
2241 if (failed(parseToken(Token::colon, "expected `:` after `_` variable")))
2242 return failure();
2243
2244 // Parse the constraints for the expression.
2245 SmallVector<ast::ConstraintRef> constraints;
2246 if (failed(parseVariableDeclConstraintList(constraints)))
2247 return failure();
2248
2249 ast::Type type;
2250 if (failed(validateVariableConstraints(constraints, type)))
2251 return failure();
2252 return createInlineVariableExpr(type, name, nameLoc, constraints);
2253}
2254
2255//===----------------------------------------------------------------------===//
2256// Stmts
2257//===----------------------------------------------------------------------===//
2258
2259FailureOr<ast::Stmt *> Parser::parseStmt(bool expectTerminalSemicolon) {
2260 FailureOr<ast::Stmt *> stmt;
2261 switch (curToken.getKind()) {
2262 case Token::kw_erase:
2263 stmt = parseEraseStmt();
2264 break;
2265 case Token::kw_let:
2266 stmt = parseLetStmt();
2267 break;
2268 case Token::kw_replace:
2269 stmt = parseReplaceStmt();
2270 break;
2271 case Token::kw_return:
2272 stmt = parseReturnStmt();
2273 break;
2274 case Token::kw_rewrite:
2275 stmt = parseRewriteStmt();
2276 break;
2277 default:
2278 stmt = parseExpr();
2279 break;
2280 }
2281 if (failed(stmt) ||
2282 (expectTerminalSemicolon &&
2283 failed(parseToken(Token::semicolon, "expected `;` after statement"))))
2284 return failure();
2285 return stmt;
2286}
2287
2288FailureOr<ast::CompoundStmt *> Parser::parseCompoundStmt() {
2289 SMLoc startLoc = curToken.getStartLoc();
2290 consumeToken(Token::l_brace);
2291
2292 // Push a new block scope and parse any nested statements.
2293 pushDeclScope();
2294 SmallVector<ast::Stmt *> statements;
2295 while (curToken.isNot(Token::r_brace)) {
2296 FailureOr<ast::Stmt *> statement = parseStmt();
2297 if (failed(statement))
2298 return popDeclScope(), failure();
2299 statements.push_back(*statement);
2300 }
2301 popDeclScope();
2302
2303 // Consume the end brace.
2304 SMRange location(startLoc, curToken.getEndLoc());
2305 consumeToken(Token::r_brace);
2306
2307 return ast::CompoundStmt::create(ctx, location, statements);
2308}
2309
2310FailureOr<ast::EraseStmt *> Parser::parseEraseStmt() {
2311 if (parserContext == ParserContext::Constraint)
2312 return emitError("`erase` cannot be used within a Constraint");
2313 SMRange loc = curToken.getLoc();
2314 consumeToken(Token::kw_erase);
2315
2316 // Parse the root operation expression.
2317 FailureOr<ast::Expr *> rootOp = parseExpr();
2318 if (failed(rootOp))
2319 return failure();
2320
2321 return createEraseStmt(loc, *rootOp);
2322}
2323
2324FailureOr<ast::LetStmt *> Parser::parseLetStmt() {
2325 SMRange loc = curToken.getLoc();
2326 consumeToken(Token::kw_let);
2327
2328 // Parse the name of the new variable.
2329 SMRange varLoc = curToken.getLoc();
2330 if (curToken.isNot(Token::identifier) && !curToken.isDependentKeyword()) {
2331 // `_` is a reserved variable name.
2332 if (curToken.is(Token::underscore)) {
2333 return emitError(varLoc,
2334 "`_` may only be used to define \"inline\" variables");
2335 }
2336 return emitError(varLoc,
2337 "expected identifier after `let` to name a new variable");
2338 }
2339 StringRef varName = curToken.getSpelling();
2340 consumeToken();
2341
2342 // Parse the optional set of constraints.
2343 SmallVector<ast::ConstraintRef> constraints;
2344 if (consumeIf(Token::colon) &&
2345 failed(parseVariableDeclConstraintList(constraints)))
2346 return failure();
2347
2348 // Parse the optional initializer expression.
2349 ast::Expr *initializer = nullptr;
2350 if (consumeIf(Token::equal)) {
2351 FailureOr<ast::Expr *> initOrFailure = parseExpr();
2352 if (failed(initOrFailure))
2353 return failure();
2354 initializer = *initOrFailure;
2355
2356 // Check that the constraints are compatible with having an initializer,
2357 // e.g. type constraints cannot be used with initializers.
2358 for (ast::ConstraintRef constraint : constraints) {
2359 LogicalResult result =
2361 .Case<ast::AttrConstraintDecl, ast::ValueConstraintDecl,
2362 ast::ValueRangeConstraintDecl>([&](const auto *cst) {
2363 if (cst->getTypeExpr()) {
2364 return this->emitError(
2365 constraint.referenceLoc,
2366 "type constraints are not permitted on variables with "
2367 "initializers");
2368 }
2369 return success();
2370 })
2371 .Default(success());
2372 if (failed(result))
2373 return failure();
2374 }
2375 }
2376
2377 FailureOr<ast::VariableDecl *> varDecl =
2378 createVariableDecl(varName, varLoc, initializer, constraints);
2379 if (failed(varDecl))
2380 return failure();
2381 return ast::LetStmt::create(ctx, loc, *varDecl);
2382}
2383
2384FailureOr<ast::ReplaceStmt *> Parser::parseReplaceStmt() {
2385 if (parserContext == ParserContext::Constraint)
2386 return emitError("`replace` cannot be used within a Constraint");
2387 SMRange loc = curToken.getLoc();
2388 consumeToken(Token::kw_replace);
2389
2390 // Parse the root operation expression.
2391 FailureOr<ast::Expr *> rootOp = parseExpr();
2392 if (failed(rootOp))
2393 return failure();
2394
2395 if (failed(
2396 parseToken(Token::kw_with, "expected `with` after root operation")))
2397 return failure();
2398
2399 // The replacement portion of this statement is within a rewrite context.
2400 llvm::SaveAndRestore saveCtx(parserContext, ParserContext::Rewrite);
2401
2402 // Parse the replacement values.
2403 SmallVector<ast::Expr *> replValues;
2404 if (consumeIf(Token::l_paren)) {
2405 if (consumeIf(Token::r_paren)) {
2406 return emitError(
2407 loc, "expected at least one replacement value, consider using "
2408 "`erase` if no replacement values are desired");
2409 }
2410
2411 do {
2412 FailureOr<ast::Expr *> replExpr = parseExpr();
2413 if (failed(replExpr))
2414 return failure();
2415 replValues.emplace_back(*replExpr);
2416 } while (consumeIf(Token::comma));
2417
2418 if (failed(parseToken(Token::r_paren,
2419 "expected `)` after replacement values")))
2420 return failure();
2421 } else {
2422 // Handle replacement with an operation uniquely, as the replacement
2423 // operation supports type inferrence from the root operation.
2424 FailureOr<ast::Expr *> replExpr;
2425 if (curToken.is(Token::kw_op))
2426 replExpr = parseOperationExpr(OpResultTypeContext::Replacement);
2427 else
2428 replExpr = parseExpr();
2429 if (failed(replExpr))
2430 return failure();
2431 replValues.emplace_back(*replExpr);
2432 }
2433
2434 return createReplaceStmt(loc, *rootOp, replValues);
2435}
2436
2437FailureOr<ast::ReturnStmt *> Parser::parseReturnStmt() {
2438 SMRange loc = curToken.getLoc();
2439 consumeToken(Token::kw_return);
2440
2441 // Parse the result value.
2442 FailureOr<ast::Expr *> resultExpr = parseExpr();
2443 if (failed(resultExpr))
2444 return failure();
2445
2446 return ast::ReturnStmt::create(ctx, loc, *resultExpr);
2447}
2448
2449FailureOr<ast::RewriteStmt *> Parser::parseRewriteStmt() {
2450 if (parserContext == ParserContext::Constraint)
2451 return emitError("`rewrite` cannot be used within a Constraint");
2452 SMRange loc = curToken.getLoc();
2453 consumeToken(Token::kw_rewrite);
2454
2455 // Parse the root operation.
2456 FailureOr<ast::Expr *> rootOp = parseExpr();
2457 if (failed(rootOp))
2458 return failure();
2459
2460 if (failed(parseToken(Token::kw_with, "expected `with` before rewrite body")))
2461 return failure();
2462
2463 if (curToken.isNot(Token::l_brace))
2464 return emitError("expected `{` to start rewrite body");
2465
2466 // The rewrite body of this statement is within a rewrite context.
2467 llvm::SaveAndRestore saveCtx(parserContext, ParserContext::Rewrite);
2468
2469 FailureOr<ast::CompoundStmt *> rewriteBody = parseCompoundStmt();
2470 if (failed(rewriteBody))
2471 return failure();
2472
2473 // Verify the rewrite body.
2474 for (const ast::Stmt *stmt : (*rewriteBody)->getChildren()) {
2475 if (isa<ast::ReturnStmt>(stmt)) {
2476 return emitError(stmt->getLoc(),
2477 "`return` statements are only permitted within a "
2478 "`Constraint` or `Rewrite` body");
2479 }
2480 }
2481
2482 return createRewriteStmt(loc, *rootOp, *rewriteBody);
2483}
2484
2485//===----------------------------------------------------------------------===//
2486// Creation+Analysis
2487//===----------------------------------------------------------------------===//
2488
2489//===----------------------------------------------------------------------===//
2490// Decls
2491//===----------------------------------------------------------------------===//
2492
2493ast::CallableDecl *Parser::tryExtractCallableDecl(ast::Node *node) {
2494 // Unwrap reference expressions.
2495 if (auto *init = dyn_cast<ast::DeclRefExpr>(node))
2496 node = init->getDecl();
2497 return dyn_cast<ast::CallableDecl>(node);
2498}
2499
2500FailureOr<ast::PatternDecl *>
2501Parser::createPatternDecl(SMRange loc, const ast::Name *name,
2502 const ParsedPatternMetadata &metadata,
2503 ast::CompoundStmt *body) {
2504 return ast::PatternDecl::create(ctx, loc, name, metadata.benefit,
2505 metadata.hasBoundedRecursion, body);
2506}
2507
2508ast::Type Parser::createUserConstraintRewriteResultType(
2509 ArrayRef<ast::VariableDecl *> results) {
2510 // Single result decls use the type of the single result.
2511 if (results.size() == 1)
2512 return results[0]->getType();
2513
2514 // Multiple results use a tuple type, with the types and names grabbed from
2515 // the result variable decls.
2516 auto resultTypes = llvm::map_range(
2517 results, [&](const auto *result) { return result->getType(); });
2518 auto resultNames = llvm::map_range(
2519 results, [&](const auto *result) { return result->getName().getName(); });
2520 return ast::TupleType::get(ctx, llvm::to_vector(resultTypes),
2521 llvm::to_vector(resultNames));
2522}
2523
2524template <typename T>
2525FailureOr<T *> Parser::createUserPDLLConstraintOrRewriteDecl(
2526 const ast::Name &name, ArrayRef<ast::VariableDecl *> arguments,
2527 ArrayRef<ast::VariableDecl *> results, ast::Type resultType,
2528 ast::CompoundStmt *body) {
2529 if (!body->getChildren().empty()) {
2530 if (auto *retStmt = dyn_cast<ast::ReturnStmt>(body->getChildren().back())) {
2531 ast::Expr *resultExpr = retStmt->getResultExpr();
2532
2533 // Process the result of the decl. If no explicit signature results
2534 // were provided, check for return type inference. Otherwise, check that
2535 // the return expression can be converted to the expected type.
2536 if (results.empty())
2537 resultType = resultExpr->getType();
2538 else if (failed(convertExpressionTo(resultExpr, resultType)))
2539 return failure();
2540 else
2541 retStmt->setResultExpr(resultExpr);
2542 }
2543 }
2544 return T::createPDLL(ctx, name, arguments, results, body, resultType);
2545}
2546
2547FailureOr<ast::VariableDecl *>
2548Parser::createVariableDecl(StringRef name, SMRange loc, ast::Expr *initializer,
2549 ArrayRef<ast::ConstraintRef> constraints) {
2550 // The type of the variable, which is expected to be inferred by either a
2551 // constraint or an initializer expression.
2552 ast::Type type;
2553 if (failed(validateVariableConstraints(constraints, type)))
2554 return failure();
2555
2556 if (initializer) {
2557 // Update the variable type based on the initializer, or try to convert the
2558 // initializer to the existing type.
2559 if (!type)
2560 type = initializer->getType();
2561 else if (ast::Type mergedType = type.refineWith(initializer->getType()))
2562 type = mergedType;
2563 else if (failed(convertExpressionTo(initializer, type)))
2564 return failure();
2565
2566 // Otherwise, if there is no initializer check that the type has already
2567 // been resolved from the constraint list.
2568 } else if (!type) {
2569 return emitErrorAndNote(
2570 loc, "unable to infer type for variable `" + name + "`", loc,
2571 "the type of a variable must be inferable from the constraint "
2572 "list or the initializer");
2573 }
2574
2575 // Constraint types cannot be used when defining variables.
2576 if (isa<ast::ConstraintType, ast::RewriteType>(type)) {
2577 return emitError(
2578 loc, llvm::formatv("unable to define variable of `{0}` type", type));
2579 }
2580
2581 // Try to define a variable with the given name.
2582 FailureOr<ast::VariableDecl *> varDecl =
2583 defineVariableDecl(name, loc, type, initializer, constraints);
2584 if (failed(varDecl))
2585 return failure();
2586
2587 return *varDecl;
2588}
2589
2590FailureOr<ast::VariableDecl *>
2591Parser::createArgOrResultVariableDecl(StringRef name, SMRange loc,
2592 const ast::ConstraintRef &constraint) {
2593 ast::Type argType;
2594 if (failed(validateVariableConstraint(constraint, argType)))
2595 return failure();
2596 return defineVariableDecl(name, loc, argType, constraint);
2597}
2598
2599LogicalResult
2600Parser::validateVariableConstraints(ArrayRef<ast::ConstraintRef> constraints,
2601 ast::Type &inferredType) {
2602 for (const ast::ConstraintRef &ref : constraints)
2603 if (failed(validateVariableConstraint(ref, inferredType)))
2604 return failure();
2605 return success();
2606}
2607
2608LogicalResult Parser::validateVariableConstraint(const ast::ConstraintRef &ref,
2609 ast::Type &inferredType) {
2610 ast::Type constraintType;
2611 if (const auto *cst = dyn_cast<ast::AttrConstraintDecl>(ref.constraint)) {
2612 if (const ast::Expr *typeExpr = cst->getTypeExpr()) {
2613 if (failed(validateTypeConstraintExpr(typeExpr)))
2614 return failure();
2615 }
2616 constraintType = ast::AttributeType::get(ctx);
2617 } else if (const auto *cst =
2618 dyn_cast<ast::OpConstraintDecl>(ref.constraint)) {
2619 constraintType = ast::OperationType::get(
2620 ctx, cst->getName(), lookupODSOperation(cst->getName()));
2621 } else if (isa<ast::TypeConstraintDecl>(ref.constraint)) {
2622 constraintType = typeTy;
2623 } else if (isa<ast::TypeRangeConstraintDecl>(ref.constraint)) {
2624 constraintType = typeRangeTy;
2625 } else if (const auto *cst =
2626 dyn_cast<ast::ValueConstraintDecl>(ref.constraint)) {
2627 if (const ast::Expr *typeExpr = cst->getTypeExpr()) {
2628 if (failed(validateTypeConstraintExpr(typeExpr)))
2629 return failure();
2630 }
2631 constraintType = valueTy;
2632 } else if (const auto *cst =
2633 dyn_cast<ast::ValueRangeConstraintDecl>(ref.constraint)) {
2634 if (const ast::Expr *typeExpr = cst->getTypeExpr()) {
2635 if (failed(validateTypeRangeConstraintExpr(typeExpr)))
2636 return failure();
2637 }
2638 constraintType = valueRangeTy;
2639 } else if (const auto *cst =
2640 dyn_cast<ast::UserConstraintDecl>(ref.constraint)) {
2641 ArrayRef<ast::VariableDecl *> inputs = cst->getInputs();
2642 if (inputs.size() != 1) {
2643 return emitErrorAndNote(ref.referenceLoc,
2644 "`Constraint`s applied via a variable constraint "
2645 "list must take a single input, but got " +
2646 Twine(inputs.size()),
2647 cst->getLoc(),
2648 "see definition of constraint here");
2649 }
2650 constraintType = inputs.front()->getType();
2651 } else {
2652 llvm_unreachable("unknown constraint type");
2653 }
2654
2655 // Check that the constraint type is compatible with the current inferred
2656 // type.
2657 if (!inferredType) {
2658 inferredType = constraintType;
2659 } else if (ast::Type mergedTy = inferredType.refineWith(constraintType)) {
2660 inferredType = mergedTy;
2661 } else {
2662 return emitError(ref.referenceLoc,
2663 llvm::formatv("constraint type `{0}` is incompatible "
2664 "with the previously inferred type `{1}`",
2665 constraintType, inferredType));
2666 }
2667 return success();
2668}
2669
2670LogicalResult Parser::validateTypeConstraintExpr(const ast::Expr *typeExpr) {
2671 ast::Type typeExprType = typeExpr->getType();
2672 if (typeExprType != typeTy) {
2673 return emitError(typeExpr->getLoc(),
2674 "expected expression of `Type` in type constraint");
2675 }
2676 return success();
2677}
2678
2679LogicalResult
2680Parser::validateTypeRangeConstraintExpr(const ast::Expr *typeExpr) {
2681 ast::Type typeExprType = typeExpr->getType();
2682 if (typeExprType != typeRangeTy) {
2683 return emitError(typeExpr->getLoc(),
2684 "expected expression of `TypeRange` in type constraint");
2685 }
2686 return success();
2687}
2688
2689//===----------------------------------------------------------------------===//
2690// Exprs
2691//===----------------------------------------------------------------------===//
2692
2693FailureOr<ast::CallExpr *>
2694Parser::createCallExpr(SMRange loc, ast::Expr *parentExpr,
2695 MutableArrayRef<ast::Expr *> arguments, bool isNegated) {
2696 ast::Type parentType = parentExpr->getType();
2697
2698 ast::CallableDecl *callableDecl = tryExtractCallableDecl(parentExpr);
2699 if (!callableDecl) {
2700 return emitError(loc,
2701 llvm::formatv("expected a reference to a callable "
2702 "`Constraint` or `Rewrite`, but got: `{0}`",
2703 parentType));
2704 }
2705 if (parserContext == ParserContext::Rewrite) {
2706 if (isa<ast::UserConstraintDecl>(callableDecl))
2707 return emitError(
2708 loc, "unable to invoke `Constraint` within a rewrite section");
2709 if (isNegated)
2710 return emitError(loc, "unable to negate a Rewrite");
2711 } else {
2712 if (isa<ast::UserRewriteDecl>(callableDecl))
2713 return emitError(loc,
2714 "unable to invoke `Rewrite` within a match section");
2715 if (isNegated && cast<ast::UserConstraintDecl>(callableDecl)->getBody())
2716 return emitError(loc, "unable to negate non native constraints");
2717 }
2718
2719 // Verify the arguments of the call.
2720 /// Handle size mismatch.
2721 ArrayRef<ast::VariableDecl *> callArgs = callableDecl->getInputs();
2722 if (callArgs.size() != arguments.size()) {
2723 return emitErrorAndNote(
2724 loc,
2725 llvm::formatv("invalid number of arguments for {0} call; expected "
2726 "{1}, but got {2}",
2727 callableDecl->getCallableType(), callArgs.size(),
2728 arguments.size()),
2729 callableDecl->getLoc(),
2730 llvm::formatv("see the definition of {0} here",
2731 callableDecl->getName()->getName()));
2732 }
2733
2734 /// Handle argument type mismatch.
2735 auto attachDiagFn = [&](ast::Diagnostic &diag) {
2736 diag.attachNote(llvm::formatv("see the definition of `{0}` here",
2737 callableDecl->getName()->getName()),
2738 callableDecl->getLoc());
2739 };
2740 for (auto it : llvm::zip(callArgs, arguments)) {
2741 if (failed(convertExpressionTo(std::get<1>(it), std::get<0>(it)->getType(),
2742 attachDiagFn)))
2743 return failure();
2744 }
2745
2746 return ast::CallExpr::create(ctx, loc, parentExpr, arguments,
2747 callableDecl->getResultType(), isNegated);
2748}
2749
2750FailureOr<ast::DeclRefExpr *> Parser::createDeclRefExpr(SMRange loc,
2751 ast::Decl *decl) {
2752 // Check the type of decl being referenced.
2753 ast::Type declType;
2754 if (isa<ast::ConstraintDecl>(decl))
2755 declType = ast::ConstraintType::get(ctx);
2756 else if (isa<ast::UserRewriteDecl>(decl))
2757 declType = ast::RewriteType::get(ctx);
2758 else if (auto *varDecl = dyn_cast<ast::VariableDecl>(decl))
2759 declType = varDecl->getType();
2760 else
2761 return emitError(loc, "invalid reference to `" +
2762 decl->getName()->getName() + "`");
2763
2764 return ast::DeclRefExpr::create(ctx, loc, decl, declType);
2765}
2766
2767FailureOr<ast::DeclRefExpr *>
2768Parser::createInlineVariableExpr(ast::Type type, StringRef name, SMRange loc,
2769 ArrayRef<ast::ConstraintRef> constraints) {
2770 FailureOr<ast::VariableDecl *> decl =
2771 defineVariableDecl(name, loc, type, constraints);
2772 if (failed(decl))
2773 return failure();
2774 return ast::DeclRefExpr::create(ctx, loc, *decl, type);
2775}
2776
2777FailureOr<ast::MemberAccessExpr *>
2778Parser::createMemberAccessExpr(ast::Expr *parentExpr, StringRef name,
2779 SMRange loc) {
2780 // Validate the member name for the given parent expression.
2781 FailureOr<ast::Type> memberType = validateMemberAccess(parentExpr, name, loc);
2782 if (failed(memberType))
2783 return failure();
2784
2785 return ast::MemberAccessExpr::create(ctx, loc, parentExpr, name, *memberType);
2786}
2787
2788FailureOr<ast::Type> Parser::validateMemberAccess(ast::Expr *parentExpr,
2789 StringRef name, SMRange loc) {
2790 ast::Type parentType = parentExpr->getType();
2791 if (ast::OperationType opType = dyn_cast<ast::OperationType>(parentType)) {
2793 return valueRangeTy;
2794
2795 // Verify member access based on the operation type.
2796 if (const ods::Operation *odsOp = opType.getODSOperation()) {
2797 auto results = odsOp->getResults();
2798
2799 // Handle indexed results.
2800 unsigned index = 0;
2801 if (llvm::isDigit(name[0]) && !name.getAsInteger(/*Radix=*/10, index) &&
2802 index < results.size()) {
2803 return results[index].isVariadic() ? valueRangeTy : valueTy;
2804 }
2805
2806 // Handle named results.
2807 const auto *it = llvm::find_if(results, [&](const auto &result) {
2808 return result.getName() == name;
2809 });
2810 if (it != results.end())
2811 return it->isVariadic() ? valueRangeTy : valueTy;
2812 } else if (llvm::isDigit(name[0])) {
2813 int32_t index;
2814 if (name.getAsInteger(/*Radix=*/10, index))
2815 return emitError(loc, "result index is too large");
2816
2817 // Allow numeric indexing of the results of unregistered operations. It
2818 // returns a single value because the result signature is unknown.
2819 return valueTy;
2820 }
2821 } else if (auto tupleType = dyn_cast<ast::TupleType>(parentType)) {
2822 // Handle indexed results.
2823 unsigned index = 0;
2824 if (llvm::isDigit(name[0]) && !name.getAsInteger(/*Radix=*/10, index) &&
2825 index < tupleType.size()) {
2826 return tupleType.getElementTypes()[index];
2827 }
2828
2829 // Handle named results.
2830 auto elementNames = tupleType.getElementNames();
2831 const auto *it = llvm::find(elementNames, name);
2832 if (it != elementNames.end())
2833 return tupleType.getElementTypes()[it - elementNames.begin()];
2834 }
2835 return emitError(
2836 loc,
2837 llvm::formatv("invalid member access `{0}` on expression of type `{1}`",
2838 name, parentType));
2839}
2840
2841FailureOr<ast::OperationExpr *> Parser::createOperationExpr(
2842 SMRange loc, const ast::OpNameDecl *name,
2843 OpResultTypeContext resultTypeContext,
2844 SmallVectorImpl<ast::Expr *> &operands,
2845 MutableArrayRef<ast::NamedAttributeDecl *> attributes,
2846 SmallVectorImpl<ast::Expr *> &results) {
2847 std::optional<StringRef> opNameRef = name->getName();
2848 const ods::Operation *odsOp = lookupODSOperation(opNameRef);
2849
2850 // Verify the inputs operands.
2851 if (failed(validateOperationOperands(loc, opNameRef, odsOp, operands)))
2852 return failure();
2853
2854 // Verify the attribute list.
2855 for (ast::NamedAttributeDecl *attr : attributes) {
2856 // Check for an attribute type, or a type awaiting resolution.
2857 ast::Type attrType = attr->getValue()->getType();
2858 if (!isa<ast::AttributeType>(attrType)) {
2859 return emitError(
2860 attr->getValue()->getLoc(),
2861 llvm::formatv("expected `Attr` expression, but got `{0}`", attrType));
2862 }
2863 }
2864
2865 assert(
2866 (resultTypeContext == OpResultTypeContext::Explicit || results.empty()) &&
2867 "unexpected inferrence when results were explicitly specified");
2868
2869 // If we aren't relying on type inferrence, or explicit results were provided,
2870 // validate them.
2871 if (resultTypeContext == OpResultTypeContext::Explicit) {
2872 if (failed(validateOperationResults(loc, opNameRef, odsOp, results)))
2873 return failure();
2874
2875 // Validate the use of interface based type inferrence for this operation.
2876 } else if (resultTypeContext == OpResultTypeContext::Interface) {
2877 assert(opNameRef &&
2878 "expected valid operation name when inferring operation results");
2879 checkOperationResultTypeInferrence(loc, *opNameRef, odsOp);
2880 }
2881
2882 return ast::OperationExpr::create(ctx, loc, odsOp, name, operands, results,
2883 attributes);
2884}
2885
2886LogicalResult
2887Parser::validateOperationOperands(SMRange loc, std::optional<StringRef> name,
2888 const ods::Operation *odsOp,
2889 SmallVectorImpl<ast::Expr *> &operands) {
2890 return validateOperationOperandsOrResults(
2891 "operand", loc, odsOp ? odsOp->getLoc() : std::optional<SMRange>(), name,
2892 operands,
2893 odsOp ? odsOp->getOperands() : ArrayRef<pdll::ods::OperandOrResult>(),
2894 valueTy, valueRangeTy);
2895}
2896
2897LogicalResult
2898Parser::validateOperationResults(SMRange loc, std::optional<StringRef> name,
2899 const ods::Operation *odsOp,
2900 SmallVectorImpl<ast::Expr *> &results) {
2901 return validateOperationOperandsOrResults(
2902 "result", loc, odsOp ? odsOp->getLoc() : std::optional<SMRange>(), name,
2903 results,
2904 odsOp ? odsOp->getResults() : ArrayRef<pdll::ods::OperandOrResult>(),
2905 typeTy, typeRangeTy);
2906}
2907
2908void Parser::checkOperationResultTypeInferrence(SMRange loc, StringRef opName,
2909 const ods::Operation *odsOp) {
2910 // If the operation might not have inferrence support, emit a warning to the
2911 // user. We don't emit an error because the interface might be added to the
2912 // operation at runtime. It's rare, but it could still happen. We emit a
2913 // warning here instead.
2914
2915 // Handle inferrence warnings for unknown operations.
2916 if (!odsOp) {
2918 loc, llvm::formatv(
2919 "operation result types are marked to be inferred, but "
2920 "`{0}` is unknown. Ensure that `{0}` supports zero "
2921 "results or implements `InferTypeOpInterface`. Include "
2922 "the ODS definition of this operation to remove this warning.",
2923 opName));
2924 return;
2925 }
2926
2927 // Handle inferrence warnings for known operations that expected at least one
2928 // result, but don't have inference support. An elided results list can mean
2929 // "zero-results", and we don't want to warn when that is the expected
2930 // behavior.
2931 bool requiresInferrence =
2932 llvm::any_of(odsOp->getResults(), [](const ods::OperandOrResult &result) {
2933 return !result.isVariableLength();
2934 });
2935 if (requiresInferrence && !odsOp->hasResultTypeInferrence()) {
2936 ast::InFlightDiagnostic diag = ctx.getDiagEngine().emitWarning(
2937 loc,
2938 llvm::formatv("operation result types are marked to be inferred, but "
2939 "`{0}` does not provide an implementation of "
2940 "`InferTypeOpInterface`. Ensure that `{0}` attaches "
2941 "`InferTypeOpInterface` at runtime, or add support to "
2942 "the ODS definition to remove this warning.",
2943 opName));
2944 diag->attachNote(llvm::formatv("see the definition of `{0}` here", opName),
2945 odsOp->getLoc());
2946 return;
2947 }
2948}
2949
2950LogicalResult Parser::validateOperationOperandsOrResults(
2951 StringRef groupName, SMRange loc, std::optional<SMRange> odsOpLoc,
2952 std::optional<StringRef> name, SmallVectorImpl<ast::Expr *> &values,
2953 ArrayRef<ods::OperandOrResult> odsValues, ast::Type singleTy,
2954 ast::RangeType rangeTy) {
2955 // All operation types accept a single range parameter.
2956 if (values.size() == 1) {
2957 if (failed(convertExpressionTo(values[0], rangeTy)))
2958 return failure();
2959 return success();
2960 }
2961
2962 /// If the operation has ODS information, we can more accurately verify the
2963 /// values.
2964 if (odsOpLoc) {
2965 auto emitSizeMismatchError = [&] {
2966 return emitErrorAndNote(
2967 loc,
2968 llvm::formatv("invalid number of {0} groups for `{1}`; expected "
2969 "{2}, but got {3}",
2970 groupName, *name, odsValues.size(), values.size()),
2971 *odsOpLoc, llvm::formatv("see the definition of `{0}` here", *name));
2972 };
2973
2974 // Handle the case where no values were provided.
2975 if (values.empty()) {
2976 // If we don't expect any on the ODS side, we are done.
2977 if (odsValues.empty())
2978 return success();
2979
2980 // If we do, check if we actually need to provide values (i.e. if any of
2981 // the values are actually required).
2982 unsigned numVariadic = 0;
2983 for (const auto &odsValue : odsValues) {
2984 if (!odsValue.isVariableLength())
2985 return emitSizeMismatchError();
2986 ++numVariadic;
2987 }
2988
2989 // If we are in a non-rewrite context, we don't need to do anything more.
2990 // Zero-values is a valid constraint on the operation.
2991 if (parserContext != ParserContext::Rewrite)
2992 return success();
2993
2994 // Otherwise, when in a rewrite we may need to provide values to match the
2995 // ODS signature of the operation to create.
2996
2997 // If we only have one variadic value, just use an empty list.
2998 if (numVariadic == 1)
2999 return success();
3000
3001 // Otherwise, create dummy values for each of the entries so that we
3002 // adhere to the ODS signature.
3003 for (unsigned i = 0, e = odsValues.size(); i < e; ++i) {
3004 values.push_back(
3005 ast::RangeExpr::create(ctx, loc, /*elements=*/{}, rangeTy));
3006 }
3007 return success();
3008 }
3009
3010 // Verify that the number of values provided matches the number of value
3011 // groups ODS expects.
3012 if (odsValues.size() != values.size())
3013 return emitSizeMismatchError();
3014
3015 auto diagFn = [&](ast::Diagnostic &diag) {
3016 diag.attachNote(llvm::formatv("see the definition of `{0}` here", *name),
3017 *odsOpLoc);
3018 };
3019 for (unsigned i = 0, e = values.size(); i < e; ++i) {
3020 ast::Type expectedType = odsValues[i].isVariadic() ? rangeTy : singleTy;
3021 if (failed(convertExpressionTo(values[i], expectedType, diagFn)))
3022 return failure();
3023 }
3024 return success();
3025 }
3026
3027 // Otherwise, accept the value groups as they have been defined and just
3028 // ensure they are one of the expected types.
3029 for (ast::Expr *&valueExpr : values) {
3030 ast::Type valueExprType = valueExpr->getType();
3031
3032 // Check if this is one of the expected types.
3033 if (valueExprType == rangeTy || valueExprType == singleTy)
3034 continue;
3035
3036 // If the operand is an Operation, allow converting to a Value or
3037 // ValueRange. This situations arises quite often with nested operation
3038 // expressions: `op<my_dialect.foo>(op<my_dialect.bar>)`
3039 if (singleTy == valueTy) {
3040 if (isa<ast::OperationType>(valueExprType)) {
3041 valueExpr = convertOpToValue(valueExpr);
3042 continue;
3043 }
3044 }
3045
3046 // Otherwise, try to convert the expression to a range.
3047 if (succeeded(convertExpressionTo(valueExpr, rangeTy)))
3048 continue;
3049
3050 return emitError(
3051 valueExpr->getLoc(),
3052 llvm::formatv(
3053 "expected `{0}` or `{1}` convertible expression, but got `{2}`",
3054 singleTy, rangeTy, valueExprType));
3055 }
3056 return success();
3057}
3058
3059FailureOr<ast::TupleExpr *>
3060Parser::createTupleExpr(SMRange loc, ArrayRef<ast::Expr *> elements,
3061 ArrayRef<StringRef> elementNames) {
3062 for (const ast::Expr *element : elements) {
3063 ast::Type eleTy = element->getType();
3064 if (isa<ast::ConstraintType, ast::RewriteType, ast::TupleType>(eleTy)) {
3065 return emitError(
3066 element->getLoc(),
3067 llvm::formatv("unable to build a tuple with `{0}` element", eleTy));
3068 }
3069 }
3070 return ast::TupleExpr::create(ctx, loc, elements, elementNames);
3071}
3072
3073//===----------------------------------------------------------------------===//
3074// Stmts
3075//===----------------------------------------------------------------------===//
3076
3077FailureOr<ast::EraseStmt *> Parser::createEraseStmt(SMRange loc,
3078 ast::Expr *rootOp) {
3079 // Check that root is an Operation.
3080 ast::Type rootType = rootOp->getType();
3081 if (!isa<ast::OperationType>(rootType))
3082 return emitError(rootOp->getLoc(), "expected `Op` expression");
3083
3084 return ast::EraseStmt::create(ctx, loc, rootOp);
3085}
3086
3087FailureOr<ast::ReplaceStmt *>
3088Parser::createReplaceStmt(SMRange loc, ast::Expr *rootOp,
3089 MutableArrayRef<ast::Expr *> replValues) {
3090 // Check that root is an Operation.
3091 ast::Type rootType = rootOp->getType();
3092 if (!isa<ast::OperationType>(rootType)) {
3093 return emitError(
3094 rootOp->getLoc(),
3095 llvm::formatv("expected `Op` expression, but got `{0}`", rootType));
3096 }
3097
3098 // If there are multiple replacement values, we implicitly convert any Op
3099 // expressions to the value form.
3100 bool shouldConvertOpToValues = replValues.size() > 1;
3101 for (ast::Expr *&replExpr : replValues) {
3102 ast::Type replType = replExpr->getType();
3103
3104 // Check that replExpr is an Operation, Value, or ValueRange.
3105 if (isa<ast::OperationType>(replType)) {
3106 if (shouldConvertOpToValues)
3107 replExpr = convertOpToValue(replExpr);
3108 continue;
3109 }
3110
3111 if (replType != valueTy && replType != valueRangeTy) {
3112 return emitError(replExpr->getLoc(),
3113 llvm::formatv("expected `Op`, `Value` or `ValueRange` "
3114 "expression, but got `{0}`",
3115 replType));
3116 }
3117 }
3118
3119 return ast::ReplaceStmt::create(ctx, loc, rootOp, replValues);
3120}
3121
3122FailureOr<ast::RewriteStmt *>
3123Parser::createRewriteStmt(SMRange loc, ast::Expr *rootOp,
3124 ast::CompoundStmt *rewriteBody) {
3125 // Check that root is an Operation.
3126 ast::Type rootType = rootOp->getType();
3127 if (!isa<ast::OperationType>(rootType)) {
3128 return emitError(
3129 rootOp->getLoc(),
3130 llvm::formatv("expected `Op` expression, but got `{0}`", rootType));
3131 }
3132
3133 return ast::RewriteStmt::create(ctx, loc, rootOp, rewriteBody);
3134}
3135
3136//===----------------------------------------------------------------------===//
3137// Code Completion
3138//===----------------------------------------------------------------------===//
3139
3140LogicalResult Parser::codeCompleteMemberAccess(ast::Expr *parentExpr) {
3141 ast::Type parentType = parentExpr->getType();
3142 if (ast::OperationType opType = dyn_cast<ast::OperationType>(parentType))
3143 codeCompleteContext->codeCompleteOperationMemberAccess(opType);
3144 else if (ast::TupleType tupleType = dyn_cast<ast::TupleType>(parentType))
3145 codeCompleteContext->codeCompleteTupleMemberAccess(tupleType);
3146 return failure();
3147}
3148
3149LogicalResult
3150Parser::codeCompleteAttributeName(std::optional<StringRef> opName) {
3151 if (opName)
3152 codeCompleteContext->codeCompleteOperationAttributeName(*opName);
3153 return failure();
3154}
3155
3156LogicalResult
3157Parser::codeCompleteConstraintName(ast::Type inferredType,
3158 bool allowInlineTypeConstraints) {
3159 codeCompleteContext->codeCompleteConstraintName(
3160 inferredType, allowInlineTypeConstraints, curDeclScope);
3161 return failure();
3162}
3163
3164LogicalResult Parser::codeCompleteDialectName() {
3165 codeCompleteContext->codeCompleteDialectName();
3166 return failure();
3167}
3168
3169LogicalResult Parser::codeCompleteOperationName(StringRef dialectName) {
3170 codeCompleteContext->codeCompleteOperationName(dialectName);
3171 return failure();
3172}
3173
3174LogicalResult Parser::codeCompletePatternMetadata() {
3175 codeCompleteContext->codeCompletePatternMetadata();
3176 return failure();
3177}
3178
3179LogicalResult Parser::codeCompleteIncludeFilename(StringRef curPath) {
3180 codeCompleteContext->codeCompleteIncludeFilename(curPath);
3181 return failure();
3182}
3183
3184void Parser::codeCompleteCallSignature(ast::Node *parent,
3185 unsigned currentNumArgs) {
3186 ast::CallableDecl *callableDecl = tryExtractCallableDecl(parent);
3187 if (!callableDecl)
3188 return;
3189
3190 codeCompleteContext->codeCompleteCallSignature(callableDecl, currentNumArgs);
3191}
3192
3193void Parser::codeCompleteOperationOperandsSignature(
3194 std::optional<StringRef> opName, unsigned currentNumOperands) {
3195 codeCompleteContext->codeCompleteOperationOperandsSignature(
3196 opName, currentNumOperands);
3197}
3198
3199void Parser::codeCompleteOperationResultsSignature(
3200 std::optional<StringRef> opName, unsigned currentNumResults) {
3201 codeCompleteContext->codeCompleteOperationResultsSignature(opName,
3202 currentNumResults);
3203}
3204
3205//===----------------------------------------------------------------------===//
3206// Parser
3207//===----------------------------------------------------------------------===//
3208
3209FailureOr<ast::Module *>
3210mlir::pdll::parsePDLLAST(ast::Context &ctx, llvm::SourceMgr &sourceMgr,
3211 bool enableDocumentation,
3212 CodeCompleteContext *codeCompleteContext) {
3213 Parser parser(ctx, sourceMgr, enableDocumentation, codeCompleteContext);
3214 return parser.parseModule();
3215}
return success()
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be inserted(the insertion happens right before the *insertion point). Since `begin` can itself be invalidated due to the memref *rewriting done from this method
static std::string diag(const llvm::Value &value)
Token lexToken()
Definition Lexer.cpp:80
const llvm::SourceMgr & getSourceMgr()
Definition Lexer.h:28
bool isKeyword() const
Return true if this is one of the keyword token kinds (e.g. kw_if).
Definition Token.cpp:183
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:77
bool isAny(Kind k1, Kind k2) const
Definition Token.h:40
Kind getKind() const
Definition Token.h:37
SMLoc getEndLoc() const
Definition Token.cpp:26
bool isNot(Kind k) const
Definition Token.h:50
StringRef getSpelling() const
Definition Token.h:34
This class provides an abstract interface into the parser for hooking in code completion events.
virtual void codeCompleteConstraintName(ast::Type currentType, bool allowInlineTypeConstraints, const ast::DeclScope *scope)
Signal code completion for a constraint name with an optional decl scope.
virtual void codeCompleteOperationAttributeName(StringRef opName)
Signal code completion for a member access into the given operation type.
virtual void codeCompleteOperationOperandsSignature(std::optional< StringRef > opName, unsigned currentNumOperands)
Signal code completion for the signature of an operation's operands.
virtual void codeCompleteOperationName(StringRef dialectName)
Signal code completion for an operation name in the given dialect.
virtual void codeCompleteOperationResultsSignature(std::optional< StringRef > opName, unsigned currentNumResults)
Signal code completion for the signature of an operation's results.
virtual void codeCompleteDialectName()
Signal code completion for a dialect name.
virtual void codeCompleteOperationMemberAccess(ast::OperationType opType)
Signal code completion for a member access into the given operation type.
virtual void codeCompleteTupleMemberAccess(ast::TupleType tupleType)
Signal code completion for a member access into the given tuple type.
virtual void codeCompletePatternMetadata()
Signal code completion for Pattern metadata.
virtual void codeCompleteCallSignature(const ast::CallableDecl *callable, unsigned currentNumArgs)
Signal code completion for the signature of a callable.
virtual void codeCompleteIncludeFilename(StringRef curPath)
Signal code completion for an include filename.
@ code_complete_string
Token signifying a code completion location within a string.
Definition Lexer.h:41
@ directive
Tokens.
Definition Lexer.h:93
@ eof
Markers.
Definition Lexer.h:36
@ code_complete
Token signifying a code completion location.
Definition Lexer.h:39
@ arrow
Punctuation.
Definition Lexer.h:74
@ less
Paired punctuation.
Definition Lexer.h:82
@ kw_Attr
General keywords.
Definition Lexer.h:54
static StringRef getMemberName()
Return the member name used for the "all-results" access.
Definition Nodes.h:487
static AllResultsMemberAccessExpr * create(Context &ctx, SMRange loc, const Expr *parentExpr, Type type)
Definition Nodes.h:489
static AttrConstraintDecl * create(Context &ctx, SMRange loc, Expr *typeExpr=nullptr)
Definition Nodes.cpp:385
static AttributeExpr * create(Context &ctx, SMRange loc, StringRef value)
Definition Nodes.cpp:259
static AttributeType get(Context &context)
Return an instance of the Attribute type.
Definition Types.cpp:56
static CallExpr * create(Context &ctx, SMRange loc, Expr *callable, ArrayRef< Expr * > arguments, Type resultType, bool isNegated=false)
Definition Nodes.cpp:269
Type getResultType() const
Return the result type of this decl.
Definition Nodes.h:1212
StringRef getCallableType() const
Return the callable type of this decl.
Definition Nodes.h:1197
ArrayRef< VariableDecl * > getInputs() const
Return the inputs of this decl.
Definition Nodes.h:1205
ArrayRef< Stmt * >::iterator end() const
Definition Nodes.h:192
MutableArrayRef< Stmt * > getChildren()
Return the children of this compound statement.
Definition Nodes.h:185
ArrayRef< Stmt * >::iterator begin() const
Definition Nodes.h:191
static CompoundStmt * create(Context &ctx, SMRange location, ArrayRef< Stmt * > children)
Definition Nodes.cpp:192
static ConstraintType get(Context &context)
Return an instance of the Constraint type.
Definition Types.cpp:64
This class represents the main context of the PDLL AST.
Definition Context.h:25
DiagnosticEngine & getDiagEngine()
Return the diagnostic engine of this context.
Definition Context.h:42
ods::Context & getODSContext()
Return the ODS context used by the AST.
Definition Context.h:38
static DeclRefExpr * create(Context &ctx, SMRange loc, Decl *decl, Type type)
Definition Nodes.cpp:285
This class represents a scope for named AST decls.
Definition Nodes.h:64
Decl * lookup(StringRef name)
Lookup a decl with the given name starting from this scope.
Definition Nodes.cpp:182
void add(Decl *decl)
Add a new decl to the scope.
Definition Nodes.cpp:175
DeclScope * getParentScope()
Return the parent scope of this scope, or nullptr if there is no parent.
Definition Nodes.h:70
void setDocComment(Context &ctx, StringRef comment)
Set the documentation comment for this decl.
Definition Nodes.cpp:377
const Name * getName() const
Return the name of the decl, or nullptr if it doesn't have one.
Definition Nodes.h:672
InFlightDiagnostic emitWarning(SMRange loc, const Twine &msg)
Definition Diagnostic.h:149
InFlightDiagnostic emitError(SMRange loc, const Twine &msg)
Emit an error to the diagnostic engine.
Definition Diagnostic.h:145
This class provides a simple implementation of a PDLL diagnostic.
Definition Diagnostic.h:29
Diagnostic & attachNote(const Twine &msg, std::optional< SMRange > noteLoc=std::nullopt)
Attach a note to this diagnostic.
Definition Diagnostic.h:46
static EraseStmt * create(Context &ctx, SMRange loc, Expr *rootOp)
Definition Nodes.cpp:218
This class represents a base AST Expression node.
Definition Nodes.h:348
Type getType() const
Return the type of this expression.
Definition Nodes.h:351
This class represents a diagnostic that is inflight and set to be reported.
Definition Diagnostic.h:83
static LetStmt * create(Context &ctx, SMRange loc, VariableDecl *varDecl)
Definition Nodes.cpp:206
static MemberAccessExpr * create(Context &ctx, SMRange loc, const Expr *parentExpr, StringRef memberName, Type type)
Definition Nodes.cpp:295
static Module * create(Context &ctx, SMLoc loc, ArrayRef< Decl * > children)
Definition Nodes.cpp:566
static NamedAttributeDecl * create(Context &ctx, const Name &name, Expr *value)
Definition Nodes.cpp:492
SMRange getLoc() const
Return the location of this node.
Definition Nodes.h:131
static OpConstraintDecl * create(Context &ctx, SMRange loc, const OpNameDecl *nameDecl=nullptr)
Definition Nodes.cpp:395
std::optional< StringRef > getName() const
Return the name of this operation, or std::nullopt if the name is unknown.
Definition Nodes.h:1028
static OpNameDecl * create(Context &ctx, const Name &name)
Definition Nodes.cpp:502
static OperationExpr * create(Context &ctx, SMRange loc, const ods::Operation *odsOp, const OpNameDecl *nameDecl, ArrayRef< Expr * > operands, ArrayRef< Expr * > resultTypes, ArrayRef< NamedAttributeDecl * > attributes)
Definition Nodes.cpp:307
This class represents a PDLL type that corresponds to an mlir::Operation.
Definition Types.h:245
const ods::Operation * getODSOperation() const
Return the ODS operation that this type refers to, or nullptr if the ODS operation is unknown.
Definition Types.cpp:86
static OperationType get(Context &context, std::optional< StringRef > name=std::nullopt, const ods::Operation *odsOp=nullptr)
Return an instance of the Operation type with an optional operation name.
Definition Types.cpp:72
static PatternDecl * create(Context &ctx, SMRange location, const Name *name, std::optional< uint16_t > benefit, bool hasBoundedRecursion, const CompoundStmt *body)
Definition Nodes.cpp:513
static RangeExpr * create(Context &ctx, SMRange loc, ArrayRef< Expr * > elements, RangeType type)
Definition Nodes.cpp:335
static ReplaceStmt * create(Context &ctx, SMRange loc, Expr *rootOp, ArrayRef< Expr * > replExprs)
Definition Nodes.cpp:226
static ReturnStmt * create(Context &ctx, SMRange loc, Expr *resultExpr)
Definition Nodes.cpp:250
static RewriteStmt * create(Context &ctx, SMRange loc, Expr *rootOp, CompoundStmt *rewriteBody)
Definition Nodes.cpp:240
static RewriteType get(Context &context)
Return an instance of the Rewrite type.
Definition Types.cpp:135
static TupleExpr * create(Context &ctx, SMRange loc, ArrayRef< Expr * > elements, ArrayRef< StringRef > elementNames)
Definition Nodes.cpp:349
This class represents a PDLL tuple type, i.e.
Definition Types.h:333
size_t size() const
Return the number of elements within this tuple.
Definition Types.h:349
ArrayRef< Type > getElementTypes() const
Return the element types of this tuple.
Definition Types.cpp:154
static TupleType get(Context &context, ArrayRef< Type > elementTypes, ArrayRef< StringRef > elementNames)
Return an instance of the Tuple type.
Definition Types.cpp:143
static TypeConstraintDecl * create(Context &ctx, SMRange loc)
Definition Nodes.cpp:412
static TypeExpr * create(Context &ctx, SMRange loc, StringRef value)
Definition Nodes.cpp:368
static TypeRangeConstraintDecl * create(Context &ctx, SMRange loc)
Definition Nodes.cpp:421
static TypeRangeType get(Context &context)
Return an instance of the TypeRange type.
Definition Types.cpp:112
static TypeType get(Context &context)
Return an instance of the Type type.
Definition Types.cpp:166
Type refineWith(Type other) const
Try to refine this type with the one provided.
Definition Types.cpp:32
static UserConstraintDecl * createNative(Context &ctx, const Name &name, ArrayRef< VariableDecl * > inputs, ArrayRef< VariableDecl * > results, std::optional< StringRef > codeBlock, Type resultType, ArrayRef< StringRef > nativeInputTypes={})
Create a native constraint with the given optional code block.
Definition Nodes.h:892
static ValueConstraintDecl * create(Context &ctx, SMRange loc, Expr *typeExpr)
Definition Nodes.cpp:431
static ValueRangeConstraintDecl * create(Context &ctx, SMRange loc, Expr *typeExpr=nullptr)
Definition Nodes.cpp:442
static ValueRangeType get(Context &context)
Return an instance of the ValueRange type.
Definition Types.cpp:126
static ValueType get(Context &context)
Return an instance of the Value type.
Definition Types.cpp:174
static VariableDecl * create(Context &ctx, const Name &name, Type type, Expr *initExpr, ArrayRef< ConstraintRef > constraints)
Definition Nodes.cpp:549
std::pair< Operation *, bool > insertOperation(StringRef name, StringRef summary, StringRef desc, StringRef nativeClassName, bool supportsResultTypeInferrence, SMLoc loc)
Insert a new operation with the context.
Definition Context.cpp:63
const TypeConstraint & insertTypeConstraint(StringRef name, StringRef summary, StringRef cppClass)
Insert a new type constraint with the context.
Definition Context.cpp:41
const AttributeConstraint & insertAttributeConstraint(StringRef name, StringRef summary, StringRef cppClass)
Insert a new attribute constraint with the context.
Definition Context.cpp:27
const Operation * lookupOperation(StringRef name) const
Lookup an operation registered with the given name, or null if no operation with that name is registe...
Definition Context.cpp:72
This class provides an ODS representation of a specific operation.
Definition Operation.h:125
ArrayRef< OperandOrResult > getOperands() const
Returns the operands of this operation.
Definition Operation.h:165
SMRange getLoc() const
Return the source location of this operation.
Definition Operation.h:128
bool hasResultTypeInferrence() const
Return if the operation is known to support result type inferrence.
Definition Operation.h:171
ArrayRef< OperandOrResult > getResults() const
Returns the results of this operation.
Definition Operation.h:168
StringRef getSummary() const
std::string getUniqueDefName() const
Returns a unique name for the TablGen def of this constraint.
StringRef getDescription() const
std::string getConditionTemplate() const
FmtContext & withSelf(Twine subst)
Definition Format.cpp:41
FailureOr< ast::Module * > parsePDLLAST(ast::Context &ctx, llvm::SourceMgr &sourceMgr, bool enableDocumentation=false, CodeCompleteContext *codeCompleteContext=nullptr)
Parse an AST module from the main file of the given source manager.
Definition Parser.cpp:3210
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:732
auto tgfmt(StringRef fmt, const FmtContext *ctx, Ts &&...vals) -> FmtObject< decltype(std::make_tuple(llvm::support::detail::FormatFunctor< Ts >(std::forward< Ts >(vals))...))>
Formats text by substituting placeholders in format string with replacement parameters.
Definition Format.h:255
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition Utils.cpp:310
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
llvm::TypeSwitch< T, ResultT > TypeSwitch
Definition LLVM.h:139
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:120
llvm::function_ref< Fn > function_ref
Definition LLVM.h:147
const ConstraintDecl * constraint
Definition Nodes.h:722
StringRef getName() const
Return the raw string name.
Definition Nodes.h:41
SMRange getLoc() const
Get the location of this name.
Definition Nodes.h:44
static const Name & create(Context &ctx, StringRef name, SMRange location)
Definition Nodes.cpp:33