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