//===--- ParseSIL.cpp - SIL File Parsing logic ----------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "SILParserFunctionBuilder.h" #include "SILParserState.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/NameLookup.h" #include "swift/AST/NameLookupRequests.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/SILGenRequests.h" #include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/Defer.h" #include "swift/Demangling/Demangle.h" #include "swift/Parse/Lexer.h" #include "swift/Parse/ParseSILSupport.h" #include "swift/Parse/Parser.h" #include "swift/SIL/AbstractionPattern.h" #include "swift/SIL/InstructionUtils.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILDebugScope.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/SILUndef.h" #include "swift/SIL/TypeLowering.h" #include "swift/Subsystems.h" #include "swift/Syntax/SyntaxKind.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/SaveAndRestore.h" using namespace swift; using namespace swift::syntax; //===----------------------------------------------------------------------===// // SILParserState implementation //===----------------------------------------------------------------------===// SILParserState::~SILParserState() { if (!ForwardRefFns.empty()) { for (auto Entry : ForwardRefFns) { if (Entry.second.Loc.isValid()) { M.getASTContext().Diags.diagnose(Entry.second.Loc, diag::sil_use_of_undefined_value, Entry.first.str()); } } } // Turn any debug-info-only function declarations into zombies. for (auto *Fn : PotentialZombieFns) if (Fn->isExternalDeclaration()) { Fn->setInlined(); M.eraseFunction(Fn); } } std::unique_ptr ParseSILModuleRequest::evaluate(Evaluator &evaluator, ASTLoweringDescriptor desc) const { auto *SF = desc.getSourceFileToParse(); assert(SF); auto bufferID = SF->getBufferID(); assert(bufferID); auto silMod = SILModule::createEmptyModule(desc.context, desc.conv, desc.opts); SILParserState parserState(*silMod.get()); Parser parser(*bufferID, *SF, &parserState); PrettyStackTraceParser StackTrace(parser); auto hadError = parser.parseTopLevelSIL(); if (hadError) { // The rest of the SIL pipeline expects well-formed SIL, so if we encounter // a parsing error, just return an empty SIL module. // // Because the SIL parser's notion of failing with an error is distinct from // the ASTContext's notion of having emitted a diagnostic, it's possible for // the parser to fail silently without emitting a diagnostic. This assertion // ensures that +asserts builds will fail fast. If you crash here, please go // back and add a diagnostic after identifying where the SIL parser failed. assert(SF->getASTContext().hadError() && "Failed to parse SIL but did not emit any errors!"); return SILModule::createEmptyModule(desc.context, desc.conv, desc.opts); } return silMod; } //===----------------------------------------------------------------------===// // SILParser //===----------------------------------------------------------------------===// namespace { struct ParsedSubstitution { SourceLoc loc; Type replacement; }; struct ParsedSpecAttr { ArrayRef requirements; bool exported; SILSpecializeAttr::SpecializationKind kind; SILFunction *target = nullptr; Identifier spiGroupID; ModuleDecl *spiModule; }; class SILParser { friend SILParserState; public: Parser &P; SILModule &SILMod; SILParserState &TUState; SILFunction *F = nullptr; GenericEnvironment *ContextGenericEnv = nullptr; GenericParamList *ContextGenericParams = nullptr; private: /// HadError - Have we seen an error parsing this function? bool HadError = false; /// Data structures used to perform name lookup of basic blocks. llvm::DenseMap BlocksByName; llvm::DenseMap> UndefinedBlocks; /// Data structures used to perform name lookup for local values. llvm::StringMap LocalValues; llvm::StringMap ForwardRefLocalValues; /// A callback to be invoked every time a type was deserialized. std::function ParsedTypeCallback; Type performTypeResolution(TypeRepr *TyR, bool IsSILType, GenericEnvironment *GenericEnv, GenericParamList *GenericParams); void convertRequirements(ArrayRef From, SmallVectorImpl &To); ProtocolConformanceRef parseProtocolConformanceHelper( ProtocolDecl *&proto, GenericEnvironment *GenericEnv, GenericParamList *WitnessParams); public: SILParser(Parser &P) : P(P), SILMod(static_cast(P.SIL)->M), TUState(*static_cast(P.SIL)), ParsedTypeCallback([](Type ty) {}) {} ~SILParser(); /// diagnoseProblems - After a function is fully parse, emit any diagnostics /// for errors and return true if there were any. bool diagnoseProblems(); /// getGlobalNameForReference - Given a reference to a global name, look it /// up and return an appropriate SIL function. SILFunction *getGlobalNameForReference(Identifier Name, CanSILFunctionType Ty, SourceLoc Loc, bool IgnoreFwdRef = false); /// getGlobalNameForDefinition - Given a definition of a global name, look /// it up and return an appropriate SIL function. SILFunction *getGlobalNameForDefinition(Identifier Name, CanSILFunctionType Ty, SourceLoc Loc); /// getBBForDefinition - Return the SILBasicBlock for a definition of the /// specified block. SILBasicBlock *getBBForDefinition(Identifier Name, SourceLoc Loc); /// getBBForReference - return the SILBasicBlock of the specified name. The /// source location is used to diagnose a failure if the block ends up never /// being defined. SILBasicBlock *getBBForReference(Identifier Name, SourceLoc Loc); struct UnresolvedValueName { StringRef Name; SourceLoc NameLoc; bool isUndef() const { return Name == "undef"; } }; /// getLocalValue - Get a reference to a local value with the specified name /// and type. SILValue getLocalValue(UnresolvedValueName Name, SILType Type, SILLocation L, SILBuilder &B); /// setLocalValue - When an instruction or block argument is defined, this /// method is used to register it and update our symbol table. void setLocalValue(ValueBase *Value, StringRef Name, SourceLoc NameLoc); SILDebugLocation getDebugLoc(SILBuilder & B, SILLocation Loc) { return SILDebugLocation(Loc, F->getDebugScope()); } /// @{ Primitive parsing. /// \verbatim /// sil-identifier ::= [A-Za-z_0-9]+ /// \endverbatim bool parseSILIdentifier(Identifier &Result, SourceLoc &Loc, const Diagnostic &D); template bool parseSILIdentifier(Identifier &Result, Diag ID, ArgTypes... Args) { SourceLoc L; return parseSILIdentifier(Result, L, Diagnostic(ID, Args...)); } template bool parseSILIdentifierSwitch(T &Result, ArrayRef Strings, Diag ID, ArgTypes... Args) { Identifier TmpResult; SourceLoc L; if (parseSILIdentifier(TmpResult, L, Diagnostic(ID, Args...))) { return true; } auto Iter = std::find(Strings.begin(), Strings.end(), TmpResult.str()); if (Iter == Strings.end()) { P.diagnose(P.Tok, Diagnostic(ID, Args...)); return true; } Result = T(*Iter); return false; } template bool parseSILIdentifier(Identifier &Result, SourceLoc &L, Diag ID, ArgTypes... Args) { return parseSILIdentifier(Result, L, Diagnostic(ID, Args...)); } bool parseVerbatim(StringRef identifier); template bool parseInteger(T &Result, const Diagnostic &D) { if (!P.Tok.is(tok::integer_literal)) { P.diagnose(P.Tok, D); return true; } bool error = parseIntegerLiteral(P.Tok.getText(), 0, Result); P.consumeToken(tok::integer_literal); return error; } template bool parseIntegerLiteral(StringRef text, unsigned radix, T &result) { text = prepareIntegerLiteralForParsing(text); return text.getAsInteger(radix, result); } StringRef prepareIntegerLiteralForParsing(StringRef text) { // tok::integer_literal can contain characters that the library // parsing routines don't expect. if (text.contains('_')) text = P.copyAndStripUnderscores(text); return text; } /// @} /// @{ Type parsing. bool parseASTType(CanType &result, GenericEnvironment *genericEnv=nullptr, GenericParamList *genericParams=nullptr); bool parseASTType(CanType &result, SourceLoc &TypeLoc, GenericEnvironment *genericEnv=nullptr, GenericParamList *genericParams=nullptr) { TypeLoc = P.Tok.getLoc(); return parseASTType(result, genericEnv, genericParams); } bool parseSILOwnership(ValueOwnershipKind &OwnershipKind) { // We parse here @ . if (!P.consumeIf(tok::at_sign)) { // If we fail, we must have @any ownership. We check elsewhere in the // parser that this matches what the function signature wants. OwnershipKind = OwnershipKind::None; return false; } StringRef AllOwnershipKinds[3] = {"unowned", "owned", "guaranteed"}; return parseSILIdentifierSwitch(OwnershipKind, AllOwnershipKinds, diag::expected_sil_value_ownership_kind); } void bindSILGenericParams(TypeRepr *TyR); bool parseSILType(SILType &Result, GenericEnvironment *&parsedGenericEnv, GenericParamList *&parsedGenericParams, bool IsFuncDecl=false, GenericEnvironment *parentGenericEnv=nullptr, GenericParamList *parentGenericParams=nullptr); bool parseSILType(SILType &Result) { GenericEnvironment *IgnoredEnv = nullptr; GenericParamList *IgnoredParams = nullptr; return parseSILType(Result, IgnoredEnv, IgnoredParams); } bool parseSILType(SILType &Result, SourceLoc &TypeLoc) { TypeLoc = P.Tok.getLoc(); return parseSILType(Result); } bool parseSILType(SILType &Result, SourceLoc &TypeLoc, GenericEnvironment *&parsedGenericEnv, GenericParamList *&parsedGenericParams, GenericEnvironment *parentGenericEnv = nullptr, GenericParamList *parentGenericParams = nullptr) { TypeLoc = P.Tok.getLoc(); return parseSILType(Result, parsedGenericEnv, parsedGenericParams, false, parentGenericEnv, parentGenericParams); } /// @} bool parseSILDottedPath(ValueDecl *&Decl, SmallVectorImpl &values); bool parseSILDottedPath(ValueDecl *&Decl) { SmallVector values; return parseSILDottedPath(Decl, values); } bool parseSILDottedPathWithoutPound(ValueDecl *&Decl, SmallVectorImpl &values); bool parseSILDottedPathWithoutPound(ValueDecl *&Decl) { SmallVector values; return parseSILDottedPathWithoutPound(Decl, values); } /// At the time of calling this function, we may not have the type of the /// Decl yet. So we return a SILDeclRef on the first lookup result and also /// return all the lookup results. After parsing the expected type, the /// caller of this function can choose the one that has the expected type. bool parseSILDeclRef(SILDeclRef &Result, SmallVectorImpl &values); bool parseSILDeclRef(SILDeclRef &Result) { SmallVector values; return parseSILDeclRef(Result, values); } bool parseSILDeclRef(SILDeclRef &Member, bool FnTypeRequired); bool parseGlobalName(Identifier &Name); bool parseValueName(UnresolvedValueName &Name); bool parseValueRef(SILValue &Result, SILType Ty, SILLocation Loc, SILBuilder &B); bool parseTypedValueRef(SILValue &Result, SourceLoc &Loc, SILBuilder &B); bool parseTypedValueRef(SILValue &Result, SILBuilder &B) { SourceLoc Tmp; return parseTypedValueRef(Result, Tmp, B); } bool parseSILOpcode(SILInstructionKind &Opcode, SourceLoc &OpcodeLoc, StringRef &OpcodeName); bool parseSILDebugVar(SILDebugVariable &Var); /// Parses the basic block arguments as part of branch instruction. bool parseSILBBArgsAtBranch(SmallVector &Args, SILBuilder &B); bool parseSILLocation(SILLocation &L); bool parseScopeRef(SILDebugScope *&DS); bool parseSILDebugLocation(SILLocation &L, SILBuilder &B, bool parsedComma = false); bool parseSpecificSILInstruction(SILBuilder &B, SILInstructionKind Opcode, SourceLoc OpcodeLoc, StringRef OpcodeName, SILInstruction *&ResultVal); bool parseSILInstruction(SILBuilder &B); bool parseCallInstruction(SILLocation InstLoc, SILInstructionKind Opcode, SILBuilder &B, SILInstruction *&ResultVal); bool parseSILFunctionRef(SILLocation InstLoc, SILFunction *&ResultFn); bool parseSILBasicBlock(SILBuilder &B); bool parseKeyPathPatternComponent(KeyPathPatternComponent &component, SmallVectorImpl &operandTypes, SourceLoc componentLoc, Identifier componentKind, SILLocation InstLoc, GenericEnvironment *patternEnv, GenericParamList *patternParams); bool isStartOfSILInstruction(); bool parseSubstitutions(SmallVectorImpl &parsed, GenericEnvironment *GenericEnv=nullptr, GenericParamList *GenericParams=nullptr); ProtocolConformanceRef parseProtocolConformance( ProtocolDecl *&proto, GenericEnvironment *&genericEnv, GenericParamList *&genericParams); ProtocolConformanceRef parseProtocolConformance() { ProtocolDecl *dummy = nullptr; GenericEnvironment *genericEnv = nullptr; GenericParamList *genericParams = nullptr; return parseProtocolConformance(dummy, genericEnv, genericParams); } Optional parseSILCoverageExpr(llvm::coverage::CounterExpressionBuilder &Builder); template struct ParsedEnum { Optional Value; StringRef Name; SourceLoc Loc; bool isSet() const { return Value.hasValue(); } T operator*() const { return *Value; } }; template void setEnum(ParsedEnum &existing, T value, StringRef name, SourceLoc loc) { if (existing.Value) { if (*existing.Value == value) { P.diagnose(loc, diag::duplicate_attribute, /*modifier*/ 1); } else { P.diagnose(loc, diag::mutually_exclusive_attrs, name, existing.Name, /*modifier*/ 1); } P.diagnose(existing.Loc, diag::previous_attribute, /*modifier*/ 1); } existing.Value = value; existing.Name = name; existing.Loc = loc; } template void maybeSetEnum(bool allowed, ParsedEnum &existing, T value, StringRef name, SourceLoc loc) { if (allowed) setEnum(existing, value, name, loc); else P.diagnose(loc, diag::unknown_attribute, name); } }; } // end anonymous namespace bool SILParser::parseSILIdentifier(Identifier &Result, SourceLoc &Loc, const Diagnostic &D) { switch (P.Tok.getKind()) { case tok::identifier: case tok::dollarident: Result = P.Context.getIdentifier(P.Tok.getText()); break; case tok::string_literal: { // Drop the double quotes. StringRef rawString = P.Tok.getText().drop_front().drop_back(); Result = P.Context.getIdentifier(rawString); break; } case tok::oper_binary_unspaced: // fixme? case tok::oper_binary_spaced: case tok::kw_init: // A binary operator or `init` can be part of a SILDeclRef. Result = P.Context.getIdentifier(P.Tok.getText()); break; default: // If it's some other keyword, grab an identifier for it. if (P.Tok.isKeyword()) { Result = P.Context.getIdentifier(P.Tok.getText()); break; } P.diagnose(P.Tok, D); return true; } Loc = P.Tok.getLoc(); P.consumeToken(); return false; } bool SILParser::parseVerbatim(StringRef name) { Identifier tok; SourceLoc loc; if (parseSILIdentifier(tok, loc, diag::expected_tok_in_sil_instr, name)) { return true; } if (tok.str() != name) { P.diagnose(loc, diag::expected_tok_in_sil_instr, name); return true; } return false; } SILParser::~SILParser() { for (auto &Entry : ForwardRefLocalValues) { if (ValueBase *dummyVal = LocalValues[Entry.first()]) { dummyVal->replaceAllUsesWith(SILUndef::get(dummyVal->getType(), SILMod)); SILInstruction::destroy(cast(dummyVal)); SILMod.deallocateInst(cast(dummyVal)); } } } /// diagnoseProblems - After a function is fully parse, emit any diagnostics /// for errors and return true if there were any. bool SILParser::diagnoseProblems() { // Check for any uses of basic blocks that were not defined. if (!UndefinedBlocks.empty()) { // FIXME: These are going to come out in nondeterministic order. for (auto Entry : UndefinedBlocks) P.diagnose(Entry.second.Loc, diag::sil_undefined_basicblock_use, Entry.second.Item); HadError = true; } if (!ForwardRefLocalValues.empty()) { // FIXME: These are going to come out in nondeterministic order. for (auto &Entry : ForwardRefLocalValues) P.diagnose(Entry.second, diag::sil_use_of_undefined_value, Entry.first()); HadError = true; } return HadError; } /// getGlobalNameForDefinition - Given a definition of a global name, look /// it up and return an appropriate SIL function. SILFunction *SILParser::getGlobalNameForDefinition(Identifier name, CanSILFunctionType ty, SourceLoc sourceLoc) { SILParserFunctionBuilder builder(SILMod); auto silLoc = RegularLocation(sourceLoc); // Check to see if a function of this name has been forward referenced. If so // complete the forward reference. auto iter = TUState.ForwardRefFns.find(name); if (iter != TUState.ForwardRefFns.end()) { SILFunction *fn = iter->second.Item; // Verify that the types match up. if (fn->getLoweredFunctionType() != ty) { P.diagnose(sourceLoc, diag::sil_value_use_type_mismatch, name.str(), fn->getLoweredFunctionType(), ty); P.diagnose(iter->second.Loc, diag::sil_prior_reference); fn = builder.createFunctionForForwardReference("" /*name*/, ty, silLoc); } assert(fn->isExternalDeclaration() && "Forward defns cannot have bodies!"); TUState.ForwardRefFns.erase(iter); // Move the function to this position in the module. // // FIXME: Should we move this functionality into SILParserFunctionBuilder? SILMod.getFunctionList().remove(fn); SILMod.getFunctionList().push_back(fn); return fn; } // If we don't have a forward reference, make sure the function hasn't been // defined already. if (SILMod.lookUpFunction(name.str()) != nullptr) { P.diagnose(sourceLoc, diag::sil_value_redefinition, name.str()); return builder.createFunctionForForwardReference("" /*name*/, ty, silLoc); } // Otherwise, this definition is the first use of this name. return builder.createFunctionForForwardReference(name.str(), ty, silLoc); } /// getGlobalNameForReference - Given a reference to a global name, look it /// up and return an appropriate SIL function. SILFunction *SILParser::getGlobalNameForReference(Identifier name, CanSILFunctionType funcTy, SourceLoc sourceLoc, bool ignoreFwdRef) { SILParserFunctionBuilder builder(SILMod); auto silLoc = RegularLocation(sourceLoc); // Check to see if we have a function by this name already. if (SILFunction *fn = SILMod.lookUpFunction(name.str())) { // If so, check for matching types. if (fn->getLoweredFunctionType() == funcTy) { return fn; } P.diagnose(sourceLoc, diag::sil_value_use_type_mismatch, name.str(), fn->getLoweredFunctionType(), funcTy); return builder.createFunctionForForwardReference("" /*name*/, funcTy, silLoc); } // If we didn't find a function, create a new one - it must be a forward // reference. auto *fn = builder.createFunctionForForwardReference(name.str(), funcTy, silLoc); TUState.ForwardRefFns[name] = {fn, ignoreFwdRef ? SourceLoc() : sourceLoc}; return fn; } /// getBBForDefinition - Return the SILBasicBlock for a definition of the /// specified block. SILBasicBlock *SILParser::getBBForDefinition(Identifier Name, SourceLoc Loc) { // If there was no name specified for this block, just create a new one. if (Name.empty()) return F->createBasicBlock(); SILBasicBlock *&BB = BlocksByName[Name]; // If the block has never been named yet, just create it. if (BB == nullptr) return BB = F->createBasicBlock(); // If it already exists, it was either a forward reference or a redefinition. // If it is a forward reference, it should be in our undefined set. if (!UndefinedBlocks.erase(BB)) { // If we have a redefinition, return a new BB to avoid inserting // instructions after the terminator. P.diagnose(Loc, diag::sil_basicblock_redefinition, Name); HadError = true; return F->createBasicBlock(); } // FIXME: Splice the block to the end of the function so they come out in the // right order. return BB; } /// getBBForReference - return the SILBasicBlock of the specified name. The /// source location is used to diagnose a failure if the block ends up never /// being defined. SILBasicBlock *SILParser::getBBForReference(Identifier Name, SourceLoc Loc) { // If the block has already been created, use it. SILBasicBlock *&BB = BlocksByName[Name]; if (BB != nullptr) return BB; // Otherwise, create it and remember that this is a forward reference so // that we can diagnose use without definition problems. BB = F->createBasicBlock(); UndefinedBlocks[BB] = {Name, Loc}; return BB; } /// sil-global-name: /// '@' identifier bool SILParser::parseGlobalName(Identifier &Name) { return P.parseToken(tok::at_sign, diag::expected_sil_value_name) || parseSILIdentifier(Name, diag::expected_sil_value_name); } /// getLocalValue - Get a reference to a local value with the specified name /// and type. SILValue SILParser::getLocalValue(UnresolvedValueName Name, SILType Type, SILLocation Loc, SILBuilder &B) { if (Name.isUndef()) return SILUndef::get(Type, B.getFunction()); // Check to see if this is already defined. ValueBase *&Entry = LocalValues[Name.Name]; if (Entry) { // If this value is already defined, check it to make sure types match. SILType EntryTy = Entry->getType(); if (EntryTy != Type) { HadError = true; P.diagnose(Name.NameLoc, diag::sil_value_use_type_mismatch, Name.Name, EntryTy.getASTType(), Type.getASTType()); // Make sure to return something of the requested type. return SILUndef::get(Type, B.getFunction()); } return SILValue(Entry); } // Otherwise, this is a forward reference. Create a dummy node to represent // it until we see a real definition. ForwardRefLocalValues[Name.Name] = Name.NameLoc; Entry = new (SILMod) GlobalAddrInst(getDebugLoc(B, Loc), Type); return Entry; } /// setLocalValue - When an instruction or block argument is defined, this /// method is used to register it and update our symbol table. void SILParser::setLocalValue(ValueBase *Value, StringRef Name, SourceLoc NameLoc) { ValueBase *&Entry = LocalValues[Name]; // If this value was already defined, it is either a redefinition, or a // specification for a forward referenced value. if (Entry) { if (!ForwardRefLocalValues.erase(Name)) { P.diagnose(NameLoc, diag::sil_value_redefinition, Name); HadError = true; return; } // If the forward reference was of the wrong type, diagnose this now. if (Entry->getType() != Value->getType()) { P.diagnose(NameLoc, diag::sil_value_def_type_mismatch, Name, Entry->getType().getASTType(), Value->getType().getASTType()); HadError = true; } else { // Forward references only live here if they have a single result. Entry->replaceAllUsesWith(Value); SILInstruction::destroy(cast(Entry)); SILMod.deallocateInst(cast(Entry)); } Entry = Value; return; } // Otherwise, just store it in our map. Entry = Value; } //===----------------------------------------------------------------------===// // SIL Parsing Logic //===----------------------------------------------------------------------===// /// parseSILLinkage - Parse a linkage specifier if present. /// sil-linkage: /// /*empty*/ // default depends on whether this is a definition /// 'public' /// 'hidden' /// 'shared' /// 'private' /// 'public_external' /// 'hidden_external' /// 'private_external' static bool parseSILLinkage(Optional &Result, Parser &P) { // Begin by initializing result to our base value of None. Result = None; // Unfortunate collision with access control keywords. if (P.Tok.is(tok::kw_public)) { Result = SILLinkage::Public; P.consumeToken(); return false; } // Unfortunate collision with access control keywords. if (P.Tok.is(tok::kw_private)) { Result = SILLinkage::Private; P.consumeToken(); return false; } // If we do not have an identifier, bail. All SILLinkages that we are parsing // are identifiers. if (P.Tok.isNot(tok::identifier)) return false; // Then use a string switch to try and parse the identifier. Result = llvm::StringSwitch>(P.Tok.getText()) .Case("non_abi", SILLinkage::PublicNonABI) .Case("hidden", SILLinkage::Hidden) .Case("shared", SILLinkage::Shared) .Case("public_external", SILLinkage::PublicExternal) .Case("hidden_external", SILLinkage::HiddenExternal) .Case("shared_external", SILLinkage::SharedExternal) .Case("private_external", SILLinkage::PrivateExternal) .Default(None); // If we succeed, consume the token. if (Result) { P.consumeToken(tok::identifier); } return false; } /// Given whether it's known to be a definition, resolve an optional /// SIL linkage to a real one. static SILLinkage resolveSILLinkage(Optional linkage, bool isDefinition) { if (linkage.hasValue()) { return linkage.getValue(); } else if (isDefinition) { return SILLinkage::DefaultForDefinition; } else { return SILLinkage::DefaultForDeclaration; } } static bool parseSILOptional(StringRef &Result, SourceLoc &Loc, SILParser &SP) { if (SP.P.consumeIf(tok::l_square)) { Identifier Id; SP.parseSILIdentifier(Id, Loc, diag::expected_in_attribute_list); SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list); Result = Id.str(); return true; } return false; } static bool parseSILOptional(StringRef &Result, SILParser &SP) { SourceLoc Loc; return parseSILOptional(Result, Loc, SP); } /// Parse an option attribute ('[' Expected ']')? static bool parseSILOptional(bool &Result, SILParser &SP, StringRef Expected) { StringRef Optional; if (parseSILOptional(Optional, SP)) { if (Optional != Expected) return true; Result = true; } return false; } /// Remap RequirementReps to Requirements. void SILParser::convertRequirements(ArrayRef From, SmallVectorImpl &To) { if (From.empty()) { To.clear(); return; } // Use parser lexical scopes to resolve references // to the generic parameters. auto ResolveToInterfaceType = [&](TypeRepr *TyR) -> Type { return performTypeResolution(TyR, /*IsSILType=*/false, ContextGenericEnv, ContextGenericParams) ->mapTypeOutOfContext(); }; for (auto &Req : From) { if (Req.getKind() == RequirementReprKind::SameType) { auto FirstType = ResolveToInterfaceType(Req.getFirstTypeRepr()); auto SecondType = ResolveToInterfaceType(Req.getSecondTypeRepr()); Requirement ConvertedRequirement(RequirementKind::SameType, FirstType, SecondType); To.push_back(ConvertedRequirement); continue; } if (Req.getKind() == RequirementReprKind::TypeConstraint) { auto Subject = ResolveToInterfaceType(Req.getSubjectRepr()); auto Constraint = ResolveToInterfaceType(Req.getConstraintRepr()); Requirement ConvertedRequirement(RequirementKind::Conformance, Subject, Constraint); To.push_back(ConvertedRequirement); continue; } if (Req.getKind() == RequirementReprKind::LayoutConstraint) { auto Subject = ResolveToInterfaceType(Req.getSubjectRepr()); Requirement ConvertedRequirement(RequirementKind::Layout, Subject, Req.getLayoutConstraint()); To.push_back(ConvertedRequirement); continue; } llvm_unreachable("Unsupported requirement kind"); } } static bool parseDeclSILOptional(bool *isTransparent, IsSerialized_t *isSerialized, bool *isCanonical, bool *hasOwnershipSSA, IsThunk_t *isThunk, IsDynamicallyReplaceable_t *isDynamic, IsExactSelfClass_t *isExactSelfClass, SILFunction **dynamicallyReplacedFunction, Identifier *objCReplacementFor, SILFunction::Purpose *specialPurpose, Inline_t *inlineStrategy, OptimizationMode *optimizationMode, bool *isLet, bool *isWeakImported, AvailabilityContext *availability, bool *isWithoutActuallyEscapingThunk, SmallVectorImpl *Semantics, SmallVectorImpl *SpecAttrs, ValueDecl **ClangDecl, EffectsKind *MRK, SILParser &SP, SILModule &M) { while (SP.P.consumeIf(tok::l_square)) { if (isLet && SP.P.Tok.is(tok::kw_let)) { *isLet = true; SP.P.consumeToken(tok::kw_let); SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list); continue; } else if (SP.P.Tok.isNot(tok::identifier)) { SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list); return true; } else if (isTransparent && SP.P.Tok.getText() == "transparent") *isTransparent = true; else if (isSerialized && SP.P.Tok.getText() == "serialized") *isSerialized = IsSerialized; else if (isDynamic && SP.P.Tok.getText() == "dynamically_replacable") *isDynamic = IsDynamic; else if (isExactSelfClass && SP.P.Tok.getText() == "exact_self_class") *isExactSelfClass = IsExactSelfClass; else if (isSerialized && SP.P.Tok.getText() == "serializable") *isSerialized = IsSerializable; else if (isCanonical && SP.P.Tok.getText() == "canonical") *isCanonical = true; else if (hasOwnershipSSA && SP.P.Tok.getText() == "ossa") *hasOwnershipSSA = true; else if (isThunk && SP.P.Tok.getText() == "thunk") *isThunk = IsThunk; else if (isThunk && SP.P.Tok.getText() == "signature_optimized_thunk") *isThunk = IsSignatureOptimizedThunk; else if (isThunk && SP.P.Tok.getText() == "reabstraction_thunk") *isThunk = IsReabstractionThunk; else if (isWithoutActuallyEscapingThunk && SP.P.Tok.getText() == "without_actually_escaping") *isWithoutActuallyEscapingThunk = true; else if (specialPurpose && SP.P.Tok.getText() == "global_init") *specialPurpose = SILFunction::Purpose::GlobalInit; else if (specialPurpose && SP.P.Tok.getText() == "lazy_getter") *specialPurpose = SILFunction::Purpose::LazyPropertyGetter; else if (specialPurpose && SP.P.Tok.getText() == "global_init_once_fn") *specialPurpose = SILFunction::Purpose::GlobalInitOnceFunction; else if (isWeakImported && SP.P.Tok.getText() == "weak_imported") { if (M.getASTContext().LangOpts.Target.isOSBinFormatCOFF()) SP.P.diagnose(SP.P.Tok, diag::attr_unsupported_on_target, SP.P.Tok.getText(), M.getASTContext().LangOpts.Target.str()); else *isWeakImported = true; } else if (availability && SP.P.Tok.getText() == "available") { SP.P.consumeToken(tok::identifier); SourceRange range; llvm::VersionTuple version; if (SP.P.parseVersionTuple(version, range, diag::sil_availability_expected_version)) return true; *availability = AvailabilityContext(VersionRange::allGTE(version)); SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list); continue; } else if (inlineStrategy && SP.P.Tok.getText() == "noinline") *inlineStrategy = NoInline; else if (optimizationMode && SP.P.Tok.getText() == "Onone") *optimizationMode = OptimizationMode::NoOptimization; else if (optimizationMode && SP.P.Tok.getText() == "Ospeed") *optimizationMode = OptimizationMode::ForSpeed; else if (optimizationMode && SP.P.Tok.getText() == "Osize") *optimizationMode = OptimizationMode::ForSize; else if (inlineStrategy && SP.P.Tok.getText() == "always_inline") *inlineStrategy = AlwaysInline; else if (MRK && SP.P.Tok.getText() == "readnone") *MRK = EffectsKind::ReadNone; else if (MRK && SP.P.Tok.getText() == "readonly") *MRK = EffectsKind::ReadOnly; else if (MRK && SP.P.Tok.getText() == "readwrite") *MRK = EffectsKind::ReadWrite; else if (MRK && SP.P.Tok.getText() == "releasenone") *MRK = EffectsKind::ReleaseNone; else if (dynamicallyReplacedFunction && SP.P.Tok.getText() == "dynamic_replacement_for") { SP.P.consumeToken(tok::identifier); if (SP.P.Tok.getKind() != tok::string_literal) { SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list); return true; } // Drop the double quotes. StringRef replacedFunc = SP.P.Tok.getText().drop_front().drop_back(); SILFunction *Func = M.lookUpFunction(replacedFunc.str()); if (!Func) { Identifier Id = SP.P.Context.getIdentifier(replacedFunc); SP.P.diagnose(SP.P.Tok, diag::sil_dynamically_replaced_func_not_found, Id); return true; } *dynamicallyReplacedFunction = Func; SP.P.consumeToken(tok::string_literal); SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list); continue; } else if (objCReplacementFor && SP.P.Tok.getText() == "objc_replacement_for") { SP.P.consumeToken(tok::identifier); if (SP.P.Tok.getKind() != tok::string_literal) { SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list); return true; } // Drop the double quotes. StringRef replacedFunc = SP.P.Tok.getText().drop_front().drop_back(); *objCReplacementFor = SP.P.Context.getIdentifier(replacedFunc); SP.P.consumeToken(tok::string_literal); SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list); continue; } else if (Semantics && SP.P.Tok.getText() == "_semantics") { SP.P.consumeToken(tok::identifier); if (SP.P.Tok.getKind() != tok::string_literal) { SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list); return true; } // Drop the double quotes. StringRef rawString = SP.P.Tok.getText().drop_front().drop_back(); Semantics->push_back(rawString.str()); SP.P.consumeToken(tok::string_literal); SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list); continue; } else if (SpecAttrs && SP.P.Tok.getText() == "_specialize") { SourceLoc AtLoc = SP.P.Tok.getLoc(); SourceLoc Loc(AtLoc); // Parse a _specialized attribute, building a parsed substitution list // and pushing a new ParsedSpecAttr on the SpecAttrs list. Conformances // cannot be generated until the function declaration is fully parsed so // that the function's generic signature can be consulted. ParsedSpecAttr SpecAttr; SpecAttr.requirements = {}; SpecAttr.exported = false; SpecAttr.kind = SILSpecializeAttr::SpecializationKind::Full; SpecializeAttr *Attr; StringRef targetFunctionName; ModuleDecl *module = nullptr; if (!SP.P.parseSpecializeAttribute( tok::r_square, AtLoc, Loc, Attr, [&targetFunctionName](Parser &P) -> bool { if (P.Tok.getKind() != tok::string_literal) { P.diagnose(P.Tok, diag::expected_in_attribute_list); return true; } // Drop the double quotes. targetFunctionName = P.Tok.getText().drop_front().drop_back(); P.consumeToken(tok::string_literal); return true; }, [&module](Parser &P) -> bool { if (P.Tok.getKind() != tok::identifier) { P.diagnose(P.Tok, diag::expected_in_attribute_list); return true; } auto ident = P.Context.getIdentifier(P.Tok.getText()); module = P.Context.getModuleByIdentifier(ident); assert(module); P.consumeToken(); return true; })) return true; SILFunction *targetFunction = nullptr; if (!targetFunctionName.empty()) { targetFunction = M.lookUpFunction(targetFunctionName.str()); if (!targetFunction) { Identifier Id = SP.P.Context.getIdentifier(targetFunctionName); SP.P.diagnose(SP.P.Tok, diag::sil_specialize_target_func_not_found, Id); return true; } } // Convert SpecializeAttr into ParsedSpecAttr. SpecAttr.requirements = Attr->getTrailingWhereClause()->getRequirements(); SpecAttr.kind = Attr->getSpecializationKind() == swift::SpecializeAttr::SpecializationKind::Full ? SILSpecializeAttr::SpecializationKind::Full : SILSpecializeAttr::SpecializationKind::Partial; SpecAttr.exported = Attr->isExported(); SpecAttr.target = targetFunction; SpecAttrs->emplace_back(SpecAttr); if (!Attr->getSPIGroups().empty()) { SpecAttr.spiGroupID = Attr->getSPIGroups()[0]; } continue; } else if (ClangDecl && SP.P.Tok.getText() == "clang") { SP.P.consumeToken(tok::identifier); if (SP.parseSILDottedPathWithoutPound(*ClangDecl)) return true; SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list); continue; } else { SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list); return true; } SP.P.consumeToken(tok::identifier); SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list); } return false; } Type SILParser::performTypeResolution(TypeRepr *TyR, bool IsSILType, GenericEnvironment *GenericEnv, GenericParamList *GenericParams) { if (GenericEnv == nullptr) GenericEnv = ContextGenericEnv; return swift::performTypeResolution(TyR, P.Context, /*isSILMode=*/true, IsSILType, GenericEnv, GenericParams, &P.SF); } /// Find the top-level ValueDecl or Module given a name. static llvm::PointerUnion lookupTopDecl(Parser &P, DeclBaseName Name, bool typeLookup) { // Use UnqualifiedLookup to look through all of the imports. UnqualifiedLookupOptions options; if (typeLookup) options |= UnqualifiedLookupFlags::TypeLookup; auto &ctx = P.SF.getASTContext(); auto descriptor = UnqualifiedLookupDescriptor(DeclNameRef(Name), &P.SF); auto lookup = evaluateOrDefault(ctx.evaluator, UnqualifiedLookupRequest{descriptor}, {}); assert(lookup.size() == 1); return lookup.back().getValueDecl(); } /// Find the ValueDecl given an interface type and a member name. static ValueDecl *lookupMember(Parser &P, Type Ty, DeclBaseName Name, SourceLoc Loc, SmallVectorImpl &Lookup, bool ExpectMultipleResults) { Type CheckTy = Ty; if (auto MetaTy = CheckTy->getAs()) CheckTy = MetaTy->getInstanceType(); if (auto nominal = CheckTy->getAnyNominal()) { if (Name == DeclBaseName::createDestructor() && isa(nominal)) { auto *classDecl = cast(nominal); Lookup.push_back(classDecl->getDestructor()); } else { auto found = nominal->lookupDirect(Name); Lookup.append(found.begin(), found.end()); } } else if (auto moduleTy = CheckTy->getAs()) { moduleTy->getModule()->lookupValue(Name, NLKind::QualifiedLookup, Lookup); } else { P.diagnose(Loc, diag::sil_member_lookup_bad_type, Name, Ty); return nullptr; } if (Lookup.empty() || (!ExpectMultipleResults && Lookup.size() != 1)) { P.diagnose(Loc, diag::sil_named_member_decl_not_found, Name, Ty); return nullptr; } return Lookup[0]; } bool SILParser::parseASTType(CanType &result, GenericEnvironment *genericEnv, GenericParamList *genericParams) { ParserResult parsedType = P.parseType(); if (parsedType.isNull()) return true; bool wantInterfaceType = true; if (genericEnv == nullptr) { genericEnv = ContextGenericEnv; wantInterfaceType = false; } if (genericParams == nullptr) genericParams = ContextGenericParams; bindSILGenericParams(parsedType.get()); const auto resolvedType = performTypeResolution(parsedType.get(), /*isSILType=*/false, genericEnv, genericParams); if (resolvedType->hasError()) return true; if (wantInterfaceType) result = resolvedType->mapTypeOutOfContext()->getCanonicalType(); else result = resolvedType->getCanonicalType(); // Invoke the callback on the parsed type. ParsedTypeCallback(resolvedType); return false; } void SILParser::bindSILGenericParams(TypeRepr *TyR) { // Resolve the generic environments for parsed generic function and box types. class HandleSILGenericParamsWalker : public ASTWalker { SourceFile *SF; public: HandleSILGenericParamsWalker(SourceFile *SF) : SF(SF) {} bool walkToTypeReprPre(TypeRepr *T) override { if (auto fnType = dyn_cast(T)) { if (auto *genericParams = fnType->getGenericParams()) { auto *env = handleSILGenericParams(genericParams, SF); fnType->setGenericEnvironment(env); } if (auto *genericParams = fnType->getPatternGenericParams()) { auto *env = handleSILGenericParams(genericParams, SF); fnType->setPatternGenericEnvironment(env); } } if (auto boxType = dyn_cast(T)) { if (auto *genericParams = boxType->getGenericParams()) { auto *env = handleSILGenericParams(genericParams, SF); boxType->setGenericEnvironment(env); } } return true; } }; TyR->walk(HandleSILGenericParamsWalker(&P.SF)); } /// sil-type: /// '$' '*'? attribute-list (generic-params)? type /// bool SILParser::parseSILType(SILType &Result, GenericEnvironment *&ParsedGenericEnv, GenericParamList *&ParsedGenericParams, bool IsFuncDecl, GenericEnvironment *OuterGenericEnv, GenericParamList *OuterGenericParams) { ParsedGenericEnv = nullptr; ParsedGenericParams = nullptr; if (OuterGenericEnv == nullptr) OuterGenericEnv = ContextGenericEnv; if (OuterGenericParams == nullptr) OuterGenericParams = ContextGenericParams; if (P.parseToken(tok::sil_dollar, diag::expected_sil_type)) return true; // If we have a '*', then this is an address type. SILValueCategory category = SILValueCategory::Object; if (P.Tok.isAnyOperator() && P.Tok.getText().startswith("*")) { category = SILValueCategory::Address; P.consumeStartingCharacterOfCurrentToken(); } // Parse attributes. ParamDecl::Specifier specifier; SourceLoc specifierLoc; TypeAttributes attrs; P.parseTypeAttributeList(specifier, specifierLoc, attrs); // Global functions are implicitly @convention(thin) if not specified otherwise. if (IsFuncDecl && !attrs.has(TAK_convention)) { // Use a random location. attrs.setAttr(TAK_convention, P.PreviousLoc); attrs.ConventionArguments = TypeAttributes::Convention::makeSwiftConvention("thin"); } ParserResult TyR = P.parseType(diag::expected_sil_type, /*isSILFuncDecl*/ IsFuncDecl); if (TyR.isNull()) return true; bindSILGenericParams(TyR.get()); // Apply attributes to the type. auto *attrRepr = P.applyAttributeToType(TyR.get(), attrs, specifier, specifierLoc); const auto Ty = performTypeResolution(attrRepr, /*IsSILType=*/true, OuterGenericEnv, OuterGenericParams); if (Ty->hasError()) return true; // Save the top-level function generic environment if there was one. if (auto fnType = dyn_cast(TyR.get())) { if (auto *genericEnv = fnType->getGenericEnvironment()) ParsedGenericEnv = genericEnv; if (auto *genericParams = fnType->getGenericParams()) ParsedGenericParams = genericParams; } Result = SILType::getPrimitiveType(Ty->getCanonicalType(), category); // Invoke the callback on the parsed type. ParsedTypeCallback(Ty); return false; } bool SILParser::parseSILDottedPath(ValueDecl *&Decl, SmallVectorImpl &values) { if (P.parseToken(tok::pound, diag::expected_sil_constant)) return true; return parseSILDottedPathWithoutPound(Decl, values); } bool SILParser::parseSILDottedPathWithoutPound(ValueDecl *&Decl, SmallVectorImpl &values) { // Handle sil-dotted-path. Identifier Id; SmallVector FullName; SmallVector Locs; do { Locs.push_back(P.Tok.getLoc()); switch (P.Tok.getKind()) { case tok::kw_subscript: P.consumeToken(); FullName.push_back(DeclBaseName::createSubscript()); break; case tok::kw_init: P.consumeToken(); FullName.push_back(DeclBaseName::createConstructor()); break; case tok::kw_deinit: P.consumeToken(); FullName.push_back(DeclBaseName::createDestructor()); break; default: if (parseSILIdentifier(Id, diag::expected_sil_constant)) return true; FullName.push_back(Id); break; } } while (P.consumeIf(tok::period)); // Look up ValueDecl from a dotted path. If there are multiple components, // the first one must be a type declaration. ValueDecl *VD; llvm::PointerUnion Res = lookupTopDecl( P, FullName[0], /*typeLookup=*/FullName.size() > 1); // It is possible that the last member lookup can return multiple lookup // results. One example is the overloaded member functions. if (Res.is()) { assert(FullName.size() > 1 && "A single module is not a full path to SILDeclRef"); auto Mod = Res.get(); values.clear(); VD = lookupMember(P, ModuleType::get(Mod), FullName[1], Locs[1], values, FullName.size() == 2/*ExpectMultipleResults*/); for (unsigned I = 2, E = FullName.size(); I < E; ++I) { values.clear(); VD = lookupMember(P, VD->getInterfaceType(), FullName[I], Locs[I], values, I == FullName.size() - 1/*ExpectMultipleResults*/); } } else { VD = Res.get(); for (unsigned I = 1, E = FullName.size(); I < E; ++I) { values.clear(); VD = lookupMember(P, VD->getInterfaceType(), FullName[I], Locs[I], values, I == FullName.size() - 1/*ExpectMultipleResults*/); } } Decl = VD; return false; } static Optional getAccessorKind(StringRef ident) { return llvm::StringSwitch>(ident) .Case("getter", AccessorKind::Get) .Case("setter", AccessorKind::Set) .Case("addressor", AccessorKind::Address) .Case("mutableAddressor", AccessorKind::MutableAddress) .Case("read", AccessorKind::Read) .Case("modify", AccessorKind::Modify) .Default(None); } /// sil-decl-ref ::= '#' sil-identifier ('.' sil-identifier)* sil-decl-subref? /// sil-decl-subref ::= '!' sil-decl-subref-part ('.' sil-decl-lang)? /// ('.' sil-decl-autodiff)? /// sil-decl-subref ::= '!' sil-decl-lang /// sil-decl-subref ::= '!' sil-decl-autodiff /// sil-decl-subref-part ::= 'getter' /// sil-decl-subref-part ::= 'setter' /// sil-decl-subref-part ::= 'allocator' /// sil-decl-subref-part ::= 'initializer' /// sil-decl-subref-part ::= 'enumelt' /// sil-decl-subref-part ::= 'destroyer' /// sil-decl-subref-part ::= 'globalaccessor' /// sil-decl-lang ::= 'foreign' /// sil-decl-autodiff ::= sil-decl-autodiff-kind '.' sil-decl-autodiff-indices /// sil-decl-autodiff-kind ::= 'jvp' /// sil-decl-autodiff-kind ::= 'vjp' /// sil-decl-autodiff-indices ::= [SU]+ bool SILParser::parseSILDeclRef(SILDeclRef &Result, SmallVectorImpl &values) { ValueDecl *VD; if (parseSILDottedPath(VD, values)) return true; // Initialize SILDeclRef components. SILDeclRef::Kind Kind = SILDeclRef::Kind::Func; bool IsObjC = false; AutoDiffDerivativeFunctionIdentifier *DerivativeId = nullptr; if (!P.consumeIf(tok::sil_exclamation)) { // Construct SILDeclRef. Result = SILDeclRef(VD, Kind, IsObjC, DerivativeId); return false; } // Handle SILDeclRef components. ParseState tracks the last parsed component. // // When ParseState is 0, accept kind (`func|getter|setter|...`) and set // ParseState to 1. // // Always accept `foreign` and derivative function identifier. unsigned ParseState = 0; Identifier Id; do { if (P.Tok.is(tok::identifier)) { auto IdLoc = P.Tok.getLoc(); if (parseSILIdentifier(Id, diag::expected_sil_constant)) return true; Optional accessorKind; if (!ParseState && Id.str() == "func") { Kind = SILDeclRef::Kind::Func; ParseState = 1; } else if (!ParseState && (accessorKind = getAccessorKind(Id.str())).hasValue()) { // Drill down to the corresponding accessor for each declaration, // compacting away decls that lack it. size_t destI = 0; for (size_t srcI = 0, e = values.size(); srcI != e; ++srcI) { if (auto storage = dyn_cast(values[srcI])) if (auto accessor = storage->getOpaqueAccessor(*accessorKind)) values[destI++] = accessor; } values.resize(destI); // Complain if none of the decls had a corresponding accessor. if (destI == 0) { P.diagnose(IdLoc, diag::referenced_value_no_accessor, 0); return true; } Kind = SILDeclRef::Kind::Func; VD = values[0]; ParseState = 1; } else if (!ParseState && Id.str() == "allocator") { Kind = SILDeclRef::Kind::Allocator; ParseState = 1; } else if (!ParseState && Id.str() == "initializer") { Kind = SILDeclRef::Kind::Initializer; ParseState = 1; } else if (!ParseState && Id.str() == "enumelt") { Kind = SILDeclRef::Kind::EnumElement; ParseState = 1; } else if (!ParseState && Id.str() == "destroyer") { Kind = SILDeclRef::Kind::Destroyer; ParseState = 1; } else if (!ParseState && Id.str() == "deallocator") { Kind = SILDeclRef::Kind::Deallocator; ParseState = 1; } else if (!ParseState && Id.str() == "globalaccessor") { Kind = SILDeclRef::Kind::GlobalAccessor; ParseState = 1; } else if (!ParseState && Id.str() == "ivardestroyer") { Kind = SILDeclRef::Kind::IVarDestroyer; ParseState = 1; } else if (!ParseState && Id.str() == "ivarinitializer") { Kind = SILDeclRef::Kind::IVarInitializer; ParseState = 1; } else if (!ParseState && Id.str() == "defaultarg") { Kind = SILDeclRef::Kind::IVarInitializer; ParseState = 1; } else if (!ParseState && Id.str() == "propertyinit") { Kind = SILDeclRef::Kind::StoredPropertyInitializer; ParseState = 1; } else if (!ParseState && Id.str() == "backinginit") { Kind = SILDeclRef::Kind::PropertyWrapperBackingInitializer; ParseState = 1; } else if (Id.str() == "foreign") { IsObjC = true; break; } else if (Id.str() == "jvp" || Id.str() == "vjp") { IndexSubset *parameterIndices = nullptr; GenericSignature derivativeGenSig; // Parse derivative function kind. AutoDiffDerivativeFunctionKind derivativeKind(Id.str()); if (!P.consumeIf(tok::period)) { P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "."); return true; } // Parse parameter indices. parameterIndices = IndexSubset::getFromString(SILMod.getASTContext(), P.Tok.getText()); if (!parameterIndices) { P.diagnose(P.Tok, diag::invalid_index_subset); return true; } P.consumeToken(); // Parse derivative generic signature (optional). if (P.Tok.is(tok::oper_binary_unspaced) && P.Tok.getText() == ".<") { P.consumeStartingCharacterOfCurrentToken(tok::period); // Create a new scope to avoid type redefinition errors. auto *genericParams = P.maybeParseGenericParams().getPtrOrNull(); assert(genericParams); auto *derivativeGenEnv = handleSILGenericParams(genericParams, &P.SF); derivativeGenSig = derivativeGenEnv->getGenericSignature(); } DerivativeId = AutoDiffDerivativeFunctionIdentifier::get( derivativeKind, parameterIndices, derivativeGenSig, SILMod.getASTContext()); break; } else { break; } } else break; } while (P.consumeIf(tok::period)); // Construct SILDeclRef. Result = SILDeclRef(VD, Kind, IsObjC, DerivativeId); return false; } /// parseValueName - Parse a value name without a type available yet. /// /// sil-value-name: /// sil-local-name /// 'undef' /// bool SILParser::parseValueName(UnresolvedValueName &Result) { Result.Name = P.Tok.getText(); if (P.Tok.is(tok::kw_undef)) { Result.NameLoc = P.consumeToken(tok::kw_undef); return false; } // Parse the local-name. if (P.parseToken(tok::sil_local_name, Result.NameLoc, diag::expected_sil_value_name)) return true; return false; } /// parseValueRef - Parse a value, given a contextual type. /// /// sil-value-ref: /// sil-local-name /// bool SILParser::parseValueRef(SILValue &Result, SILType Ty, SILLocation Loc, SILBuilder &B) { UnresolvedValueName Name; if (parseValueName(Name)) return true; Result = getLocalValue(Name, Ty, Loc, B); return false; } /// parseTypedValueRef - Parse a type/value reference pair. /// /// sil-typed-valueref: /// sil-value-ref ':' sil-type /// bool SILParser::parseTypedValueRef(SILValue &Result, SourceLoc &Loc, SILBuilder &B) { Loc = P.Tok.getLoc(); UnresolvedValueName Name; SILType Ty; if (parseValueName(Name) || P.parseToken(tok::colon, diag::expected_sil_colon_value_ref) || parseSILType(Ty)) return true; Result = getLocalValue(Name, Ty, RegularLocation(Loc), B); return false; } /// Look up whether the given string corresponds to a SIL opcode. static Optional getOpcodeByName(StringRef OpcodeName) { return llvm::StringSwitch>(OpcodeName) #define FULL_INST(Id, TextualName, Parent, MemBehavior, MayRelease) \ .Case(#TextualName, SILInstructionKind::Id) #include "swift/SIL/SILNodes.def" .Default(None); } /// getInstructionKind - This method maps the string form of a SIL instruction /// opcode to an enum. bool SILParser::parseSILOpcode(SILInstructionKind &Opcode, SourceLoc &OpcodeLoc, StringRef &OpcodeName) { OpcodeLoc = P.Tok.getLoc(); OpcodeName = P.Tok.getText(); // Parse this textually to avoid Swift keywords (like 'return') from // interfering with opcode recognition. auto MaybeOpcode = getOpcodeByName(OpcodeName); if (!MaybeOpcode) { P.diagnose(OpcodeLoc, diag::expected_sil_instr_opcode); return true; } Opcode = MaybeOpcode.getValue(); P.consumeToken(); return false; } static bool peekSILDebugLocation(Parser &P) { auto T = P.peekToken().getText(); return P.Tok.is(tok::comma) && (T == "loc" || T == "scope"); } bool SILParser::parseSILDebugVar(SILDebugVariable &Var) { while (P.Tok.is(tok::comma) && !peekSILDebugLocation(P)) { P.consumeToken(); StringRef Key = P.Tok.getText(); if (Key == "name") { P.consumeToken(); if (P.Tok.getKind() != tok::string_literal) { P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "string"); return true; } // Drop the double quotes. StringRef Val = P.Tok.getText().drop_front().drop_back(); Var.Name = Val; } else if (Key == "argno") { P.consumeToken(); if (P.Tok.getKind() != tok::integer_literal) { P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "integer"); return true; } uint16_t ArgNo; if (parseIntegerLiteral(P.Tok.getText(), 0, ArgNo)) return true; Var.ArgNo = ArgNo; } else if (Key == "let") { Var.Constant = true; } else if (Key == "var") { Var.Constant = false; } else if (Key == "loc") { Var.Constant = false; } else { P.diagnose(P.Tok, diag::sil_dbg_unknown_key, Key); return true; } P.consumeToken(); } return false; } bool SILParser::parseSILBBArgsAtBranch(SmallVector &Args, SILBuilder &B) { if (P.Tok.is(tok::l_paren)) { SourceLoc LParenLoc = P.consumeToken(tok::l_paren); SourceLoc RParenLoc; bool HasError = false; if (P.parseList(tok::r_paren, LParenLoc, RParenLoc, /*AllowSepAfterLast=*/false, diag::sil_basicblock_arg_rparen, SyntaxKind::Unknown, [&]() -> ParserStatus { SILValue Arg; SourceLoc ArgLoc; if (parseTypedValueRef(Arg, ArgLoc, B)) { HasError = true; return makeParserError(); } Args.push_back(Arg); return makeParserSuccess(); }).isErrorOrHasCompletion() || HasError) return true; } return false; } /// Parse the substitution list for an apply instruction or /// specialized protocol conformance. bool SILParser::parseSubstitutions(SmallVectorImpl &parsed, GenericEnvironment *GenericEnv, GenericParamList *GenericParams) { // Check for an opening '<' bracket. if (!P.startsWithLess(P.Tok)) return false; if (GenericEnv == nullptr) GenericEnv = ContextGenericEnv; if (GenericParams == nullptr) GenericParams = ContextGenericParams; P.consumeStartingLess(); // Parse a list of Substitutions. do { SourceLoc Loc = P.Tok.getLoc(); // Parse substitution as AST type. ParserResult TyR = P.parseType(); if (TyR.isNull()) return true; const auto Ty = performTypeResolution(TyR.get(), /*IsSILType=*/false, GenericEnv, GenericParams); if (Ty->hasError()) return true; parsed.push_back({Loc, Ty}); } while (P.consumeIf(tok::comma)); // Consume the closing '>'. if (!P.startsWithGreater(P.Tok)) { P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, ">"); return true; } P.consumeStartingGreater(); return false; } /// Collect conformances by looking up the conformance from replacement /// type and protocol decl. static bool getConformancesForSubstitution(Parser &P, ExistentialLayout::ProtocolTypeArrayRef protocols, Type subReplacement, SourceLoc loc, SmallVectorImpl &conformances) { auto M = P.SF.getParentModule(); for (auto protoTy : protocols) { auto conformance = M->lookupConformance(subReplacement, protoTy->getDecl()); if (conformance.isInvalid()) { P.diagnose(loc, diag::sil_substitution_mismatch, subReplacement, protoTy); return true; } conformances.push_back(conformance); } return false; } /// Reconstruct an AST substitution map from parsed substitutions. SubstitutionMap getApplySubstitutionsFromParsed( SILParser &SP, GenericEnvironment *env, ArrayRef parses) { if (parses.empty()) { assert(!env); return SubstitutionMap(); } assert(env); auto loc = parses[0].loc; // Ensure that we have the right number of type arguments. auto genericSig = env->getGenericSignature(); if (parses.size() != genericSig->getGenericParams().size()) { bool hasTooFew = parses.size() < genericSig->getGenericParams().size(); SP.P.diagnose(loc, hasTooFew ? diag::sil_missing_substitutions : diag::sil_too_many_substitutions); return SubstitutionMap(); } bool failed = false; auto subMap = SubstitutionMap::get( genericSig, [&](SubstitutableType *type) -> Type { auto genericParam = dyn_cast(type); if (!genericParam) return nullptr; auto index = genericSig->getGenericParamOrdinal(genericParam); assert(index < genericSig->getGenericParams().size()); assert(index < parses.size()); // Provide the replacement type. return parses[index].replacement; }, [&](CanType dependentType, Type replacementType, ProtocolDecl *proto) -> ProtocolConformanceRef { auto M = SP.P.SF.getParentModule(); if (auto conformance = M->lookupConformance(replacementType, proto)) return conformance; SP.P.diagnose(loc, diag::sil_substitution_mismatch, replacementType, proto->getDeclaredInterfaceType()); failed = true; return ProtocolConformanceRef(proto); }); return failed ? SubstitutionMap() : subMap; } static ArrayRef collectExistentialConformances(Parser &P, CanType conformingType, SourceLoc loc, CanType protocolType) { auto layout = protocolType.getExistentialLayout(); if (layout.requiresClass()) { if (!conformingType->mayHaveSuperclass() && !conformingType->isObjCExistentialType()) { P.diagnose(loc, diag::sil_not_class, conformingType); } } // FIXME: Check superclass also. auto protocols = layout.getProtocols(); if (protocols.empty()) return {}; SmallVector conformances; getConformancesForSubstitution(P, protocols, conformingType, loc, conformances); return P.Context.AllocateCopy(conformances); } /// sil-loc ::= 'loc' string-literal ':' [0-9]+ ':' [0-9]+ bool SILParser::parseSILLocation(SILLocation &Loc) { SILLocation::DebugLoc L; if (parseVerbatim("loc")) return true; if (P.Tok.getKind() != tok::string_literal) { P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "string"); return true; } // Drop the double quotes. StringRef File = P.Tok.getText().drop_front().drop_back(); L.Filename = P.Context.getIdentifier(File).str().data(); P.consumeToken(tok::string_literal); if (P.parseToken(tok::colon, diag::expected_colon_in_sil_location)) return true; if (parseInteger(L.Line, diag::sil_invalid_line_in_sil_location)) return true; if (P.parseToken(tok::colon, diag::expected_colon_in_sil_location)) return true; if (parseInteger(L.Column, diag::sil_invalid_column_in_sil_location)) return true; Loc.setDebugInfoLoc(L); return false; } bool SILParser::parseScopeRef(SILDebugScope *&DS) { unsigned Slot; SourceLoc SlotLoc = P.Tok.getLoc(); if (parseInteger(Slot, diag::sil_invalid_scope_slot)) return true; DS = TUState.ScopeSlots[Slot]; if (!DS) { P.diagnose(SlotLoc, diag::sil_scope_undeclared, Slot); return true; } return false; } /// (',' sil-loc)? (',' sil-scope-ref)? bool SILParser::parseSILDebugLocation(SILLocation &L, SILBuilder &B, bool parsedComma) { // Parse the debug information, if any. if (P.Tok.is(tok::comma)) { P.consumeToken(); parsedComma = true; } if (!parsedComma) return false; bool requireScope = false; if (P.Tok.getText() == "loc") { if (parseSILLocation(L)) return true; if (P.Tok.is(tok::comma)) { P.consumeToken(); requireScope = true; } } if (P.Tok.getText() == "scope" || requireScope) { parseVerbatim("scope"); SILDebugScope *DS = nullptr; if (parseScopeRef(DS)) return true; if (DS) B.setCurrentDebugScope(DS); } return false; } static bool parseLoadOwnershipQualifier(LoadOwnershipQualifier &Result, SILParser &P) { StringRef Str; // If we do not parse '[' ... ']', we have unqualified. Set value and return. if (!parseSILOptional(Str, P)) { Result = LoadOwnershipQualifier::Unqualified; return false; } // Then try to parse one of our other qualifiers. We do not support parsing // unqualified here so we use that as our fail value. auto Tmp = llvm::StringSwitch(Str) .Case("take", LoadOwnershipQualifier::Take) .Case("copy", LoadOwnershipQualifier::Copy) .Case("trivial", LoadOwnershipQualifier::Trivial) .Default(LoadOwnershipQualifier::Unqualified); // Thus return true (following the conventions in this file) if we fail. if (Tmp == LoadOwnershipQualifier::Unqualified) return true; // Otherwise, assign Result and return false. Result = Tmp; return false; } static bool parseStoreOwnershipQualifier(StoreOwnershipQualifier &Result, SILParser &P) { StringRef Str; // If we do not parse '[' ... ']', we have unqualified. Set value and return. if (!parseSILOptional(Str, P)) { Result = StoreOwnershipQualifier::Unqualified; return false; } // Then try to parse one of our other qualifiers. We do not support parsing // unqualified here so we use that as our fail value. auto Tmp = llvm::StringSwitch(Str) .Case("init", StoreOwnershipQualifier::Init) .Case("assign", StoreOwnershipQualifier::Assign) .Case("trivial", StoreOwnershipQualifier::Trivial) .Default(StoreOwnershipQualifier::Unqualified); // Thus return true (following the conventions in this file) if we fail. if (Tmp == StoreOwnershipQualifier::Unqualified) return true; // Otherwise, assign Result and return false. Result = Tmp; return false; } static bool parseAssignOwnershipQualifier(AssignOwnershipQualifier &Result, SILParser &P) { StringRef Str; // If we do not parse '[' ... ']', we have unknown. Set value and return. if (!parseSILOptional(Str, P)) { Result = AssignOwnershipQualifier::Unknown; return false; } // Then try to parse one of our other initialization kinds. We do not support // parsing unknown here so we use that as our fail value. auto Tmp = llvm::StringSwitch(Str) .Case("reassign", AssignOwnershipQualifier::Reassign) .Case("reinit", AssignOwnershipQualifier::Reinit) .Case("init", AssignOwnershipQualifier::Init) .Default(AssignOwnershipQualifier::Unknown); // Thus return true (following the conventions in this file) if we fail. if (Tmp == AssignOwnershipQualifier::Unknown) return true; // Otherwise, assign Result and return false. Result = Tmp; return false; } // Parse a list of integer indices, prefaced with the given string label. // Returns true on error. static bool parseIndexList(Parser &P, StringRef label, SmallVectorImpl &indices, const Diagnostic &parseIndexDiag) { SourceLoc loc; // Parse `[