//===--- 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 "swift/AST/ASTWalker.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/NameLookup.h" #include "swift/AST/ProtocolConformance.h" #include "swift/Basic/Defer.h" #include "swift/Parse/Lexer.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/Subsystems.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/SaveAndRestore.h" using namespace swift; //===----------------------------------------------------------------------===// // SILParserState implementation //===----------------------------------------------------------------------===// namespace swift { class SILParserTUState { public: SILParserTUState(SILModule &M) : M(M) {} ~SILParserTUState(); SILModule &M; /// This is all of the forward referenced functions with /// the location for where the reference is. llvm::DenseMap> ForwardRefFns; /// A list of all functions forward-declared by a sil_scope. llvm::DenseSet PotentialZombieFns; /// A map from textual .sil scope number to SILDebugScopes. llvm::DenseMap ScopeSlots; /// Did we parse a sil_stage for this module? bool DidParseSILStage = false; DiagnosticEngine *Diags = nullptr; }; } // namespace swift SILParserState::SILParserState(SILModule *M) : M(M) { S = M ? new SILParserTUState(*M) : nullptr; } SILParserState::~SILParserState() { delete S; } SILParserTUState::~SILParserTUState() { if (!ForwardRefFns.empty()) for (auto Entry : ForwardRefFns) if (Entry.second.second.isValid()) Diags->diagnose(Entry.second.second, 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); } } //===----------------------------------------------------------------------===// // SILParser //===----------------------------------------------------------------------===// namespace { struct ParsedSubstitution { SourceLoc loc; Type replacement; }; struct ParsedSpecAttr { ArrayRef requirements; bool exported; SILSpecializeAttr::SpecializationKind kind; }; class SILParser { friend Parser; public: Parser &P; SILModule &SILMod; SILParserTUState &TUState; SILFunction *F = nullptr; GenericEnvironment *GenericEnv = nullptr; FunctionOwnershipEvaluator OwnershipEvaluator; 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; bool performTypeLocChecking(TypeLoc &T, bool IsSILType, GenericEnvironment *GenericEnv = nullptr, DeclContext *DC = nullptr); void convertRequirements(SILFunction *F, ArrayRef From, SmallVectorImpl &To); ProtocolConformance * parseProtocolConformanceHelper(ProtocolDecl *&proto, GenericEnvironment *GenericEnv, bool localScope); public: SILParser(Parser &P) : P(P), SILMod(*P.SIL->M), TUState(*P.SIL->S), ParsedTypeCallback([](Type ty) {}) {} /// 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 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; } P.Tok.getText().getAsInteger(0, Result); P.consumeToken(tok::integer_literal); return false; } /// @} /// @{ Type parsing. bool parseASTType(CanType &result); bool parseASTType(CanType &result, SourceLoc &TypeLoc) { TypeLoc = P.Tok.getLoc(); return parseASTType(result); } bool parseSILOwnership(Optional &OwnershipKind) { // We pare here @ . if (P.consumeIf(tok::at_sign) && P.Tok.isNot(tok::identifier)) { // Add error here. return true; } OwnershipKind = llvm::StringSwitch>(P.Tok.getText()) .Case("trivial", Optional(ValueOwnershipKind::Trivial)) .Case("unowned", Optional(ValueOwnershipKind::Unowned)) .Case("owned", Optional(ValueOwnershipKind::Owned)) .Case("guaranteed", Optional( ValueOwnershipKind::Guaranteed)) .Default(None); if (OwnershipKind.hasValue()) { P.consumeToken(); return false; } return true; } bool parseSILType(SILType &Result, GenericEnvironment *&genericEnv, bool IsFuncDecl = false); bool parseSILType(SILType &Result) { GenericEnvironment *IgnoredEnv; return parseSILType(Result, IgnoredEnv); } bool parseSILType(SILType &Result, SourceLoc &TypeLoc) { TypeLoc = P.Tok.getLoc(); return parseSILType(Result); } bool parseSILType(SILType &Result, SourceLoc &TypeLoc, GenericEnvironment *&GenericEnv) { TypeLoc = P.Tok.getLoc(); return parseSILType(Result, GenericEnv); } /// @} 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(ValueKind &Opcode, SourceLoc &OpcodeLoc, StringRef &OpcodeName); bool parseSILDebugVar(SILDebugVariable &Var); /// \brief 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 parseSILInstruction(SILBasicBlock *BB, SILBuilder &B); bool parseCallInstruction(SILLocation InstLoc, ValueKind Opcode, SILBuilder &B, SILInstruction *&ResultVal); bool parseSILFunctionRef(SILLocation InstLoc, SILBuilder &B, SILInstruction *&ResultVal); bool parseSILBasicBlock(SILBuilder &B); bool isStartOfSILInstruction(); bool parseSubstitutions(SmallVectorImpl &parsed, GenericEnvironment *GenericEnv=nullptr); ProtocolConformance *parseProtocolConformance(ProtocolDecl *&proto, GenericEnvironment *&genericEnv, bool localScope); ProtocolConformance *parseProtocolConformance() { ProtocolDecl *dummy; GenericEnvironment *env; return parseProtocolConformance(dummy, env, true); } Optional parseSILCoverageExpr(llvm::coverage::CounterExpressionBuilder &Builder); }; } // end anonymous namespace bool SILParser::parseSILIdentifier(Identifier &Result, SourceLoc &Loc, const Diagnostic &D) { switch (P.Tok.getKind()) { case tok::identifier: 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: // A binary operator can be part of a SILDeclRef. Result = P.Context.getIdentifier(P.Tok.getText()); break; case tok::kw_deinit: Result = P.Context.Id_deinit; break; case tok::kw_init: Result = P.Context.Id_init; break; case tok::kw_subscript: Result = P.Context.Id_subscript; 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; } /// 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.first, diag::sil_undefined_basicblock_use, Entry.second.second); 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 Loc) { // Check to see if a function of this name has been forward referenced. If so // complete the forward reference. auto It = TUState.ForwardRefFns.find(Name); if (It != TUState.ForwardRefFns.end()) { SILFunction *Fn = It->second.first; // Verify that the types match up. if (Fn->getLoweredFunctionType() != Ty) { P.diagnose(Loc, diag::sil_value_use_type_mismatch, Name.str(), Fn->getLoweredFunctionType(), Ty); P.diagnose(It->second.second, diag::sil_prior_reference); auto loc = RegularLocation(Loc); Fn = SILMod.createFunction(SILLinkage::Private, "", Ty, nullptr, loc, IsNotBare, IsNotTransparent, IsNotFragile); Fn->setDebugScope(new (SILMod) SILDebugScope(loc, Fn)); } assert(Fn->isExternalDeclaration() && "Forward defns cannot have bodies!"); TUState.ForwardRefFns.erase(It); // Move the function to this position in the module. SILMod.getFunctionList().remove(Fn); SILMod.getFunctionList().push_back(Fn); return Fn; } auto loc = RegularLocation(Loc); // 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(Loc, diag::sil_value_redefinition, Name.str()); auto *fn = SILMod.createFunction(SILLinkage::Private, "", Ty, nullptr, loc, IsNotBare, IsNotTransparent, IsNotFragile); fn->setDebugScope(new (SILMod) SILDebugScope(loc, fn)); return fn; } // Otherwise, this definition is the first use of this name. auto *fn = SILMod.createFunction(SILLinkage::Private, Name.str(), Ty, nullptr, loc, IsNotBare, IsNotTransparent, IsNotFragile); fn->setDebugScope(new (SILMod) SILDebugScope(loc, fn)); return fn; } /// getGlobalNameForReference - Given a reference to a global name, look it /// up and return an appropriate SIL function. SILFunction *SILParser::getGlobalNameForReference(Identifier Name, CanSILFunctionType Ty, SourceLoc Loc, bool IgnoreFwdRef) { auto loc = RegularLocation(Loc); // Check to see if we have a function by this name already. if (SILFunction *FnRef = SILMod.lookUpFunction(Name.str())) { // If so, check for matching types. if (FnRef->getLoweredFunctionType() != Ty) { P.diagnose(Loc, diag::sil_value_use_type_mismatch, Name.str(), FnRef->getLoweredFunctionType(), Ty); FnRef = SILMod.createFunction(SILLinkage::Private, "", Ty, nullptr, loc, IsNotBare, IsNotTransparent, IsNotFragile); FnRef->setDebugScope(new (SILMod) SILDebugScope(loc, FnRef)); } return FnRef; } // If we didn't find a function, create a new one - it must be a forward // reference. auto *Fn = SILMod.createFunction(SILLinkage::Private, Name.str(), Ty, nullptr, loc, IsNotBare, IsNotTransparent, IsNotFragile); Fn->setDebugScope(new (SILMod) SILDebugScope(loc, Fn)); TUState.ForwardRefFns[Name] = { Fn, IgnoreFwdRef ? SourceLoc() : Loc }; TUState.Diags = &P.Diags; 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] = {Loc, Name}; 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, &SILMod); // 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.getSwiftRValueType(), Type.getSwiftRValueType()); // Make sure to return something of the requested type. return new (SILMod) GlobalAddrInst(getDebugLoc(B, Loc), Type); } 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().getSwiftRValueType(), Value->getType().getSwiftRValueType()); HadError = true; } else { // Forward references only live here if they have a single result. Entry->replaceAllUsesWith(Value); } 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("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, SILParser &SP) { if (SP.P.consumeIf(tok::l_square)) { Identifier Id; SP.parseSILIdentifier(Id, diag::expected_in_attribute_list); SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list); Result = Id.str(); return true; } return false; } /// 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; } namespace { /// A helper class to perform lookup of IdentTypes in the /// current parser scope. class IdentTypeReprLookup : public ASTWalker { Parser &P; public: IdentTypeReprLookup(Parser &P) : P(P) {} bool walkToTypeReprPre(TypeRepr *Ty) { auto *T = dyn_cast_or_null(Ty); auto Comp = T->getComponentRange().front(); if (auto Entry = P.lookupInScope(Comp->getIdentifier())) if (isa(Entry)) { Comp->setValue(Entry); return false; } return true; } }; } // end anonymous namespace /// Remap RequirementReps to Requirements. void SILParser::convertRequirements(SILFunction *F, ArrayRef From, SmallVectorImpl &To) { if (From.empty()) { To.clear(); return; } auto *GenericEnv = F->getGenericEnvironment(); assert(GenericEnv); IdentTypeReprLookup PerformLookup(P); // Use parser lexical scopes to resolve references // to the generic parameters. auto ResolveToInterfaceType = [&](TypeLoc Ty) -> Type { Ty.getTypeRepr()->walk(PerformLookup); performTypeLocChecking(Ty, /* IsSIL */ false); assert(Ty.getType()); return GenericEnv->mapTypeOutOfContext(Ty.getType()->getCanonicalType()); }; for (auto &Req : From) { if (Req.getKind() == RequirementReprKind::SameType) { auto FirstType = ResolveToInterfaceType(Req.getFirstTypeLoc()); auto SecondType = ResolveToInterfaceType(Req.getSecondTypeLoc()); Requirement ConvertedRequirement(RequirementKind::SameType, FirstType, SecondType); To.push_back(ConvertedRequirement); continue; } if (Req.getKind() == RequirementReprKind::TypeConstraint) { auto FirstType = ResolveToInterfaceType(Req.getFirstTypeLoc()); auto SecondType = ResolveToInterfaceType(Req.getSecondTypeLoc()); Requirement ConvertedRequirement(RequirementKind::Conformance, FirstType, SecondType); To.push_back(ConvertedRequirement); continue; } if (Req.getKind() == RequirementReprKind::LayoutConstraint) { auto Subject = ResolveToInterfaceType(Req.getSubjectLoc()); Requirement ConvertedRequirement(RequirementKind::Layout, Subject, Req.getLayoutConstraint()); To.push_back(ConvertedRequirement); continue; } llvm_unreachable("Unsupported requirement kind"); } } static bool parseDeclSILOptional(bool *isTransparent, bool *isFragile, IsThunk_t *isThunk, bool *isGlobalInit, Inline_t *inlineStrategy, bool *isLet, SmallVectorImpl *Semantics, SmallVectorImpl *SpecAttrs, ValueDecl **ClangDecl, EffectsKind *MRK, SILParser &SP) { 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 (isFragile && SP.P.Tok.getText() == "fragile") *isFragile = true; else if (isThunk && SP.P.Tok.getText() == "thunk") *isThunk = IsThunk; else if (isThunk && SP.P.Tok.getText() == "reabstraction_thunk") *isThunk = IsReabstractionThunk; else if (isGlobalInit && SP.P.Tok.getText() == "global_init") *isGlobalInit = true; else if (inlineStrategy && SP.P.Tok.getText() == "noinline") *inlineStrategy = NoInline; 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 (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); 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; if (!SP.P.parseSpecializeAttribute(tok::r_square, AtLoc, Loc, Attr)) 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(); SpecAttrs->emplace_back(SpecAttr); 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; } bool SILParser::performTypeLocChecking(TypeLoc &T, bool IsSILType, GenericEnvironment *GenericEnv, DeclContext *DC) { // Do some type checking / name binding for the parsed type. assert(P.SF.ASTStage == SourceFile::Parsing && "Unexpected stage during parsing!"); if (GenericEnv == nullptr) GenericEnv = this->GenericEnv; if (!DC) DC = &P.SF; return swift::performTypeLocChecking(P.Context, T, /*isSILMode=*/true, IsSILType, GenericEnv, DC); } /// Find the top-level ValueDecl or Module given a name. static llvm::PointerUnion lookupTopDecl(Parser &P, Identifier Name) { // Use UnqualifiedLookup to look through all of the imports. // We have to lie and say we're done with parsing to make this happen. assert(P.SF.ASTStage == SourceFile::Parsing && "Unexpected stage during parsing!"); llvm::SaveAndRestore ASTStage(P.SF.ASTStage, SourceFile::Parsed); UnqualifiedLookup DeclLookup(Name, &P.SF, nullptr); assert(DeclLookup.isSuccess() && DeclLookup.Results.size() == 1); ValueDecl *VD = DeclLookup.Results.back().getValueDecl(); return VD; } /// Find the ValueDecl given an interface type and a member name. static ValueDecl *lookupMember(Parser &P, Type Ty, Identifier Name, SourceLoc Loc, SmallVectorImpl &Lookup, bool ExpectMultipleResults) { Type CheckTy = Ty; if (auto MetaTy = CheckTy->getAs()) CheckTy = MetaTy->getInstanceType(); if (auto nominal = CheckTy->getAnyNominal()) { 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) { ParserResult parsedType = P.parseType(); if (parsedType.isNull()) return true; TypeLoc loc = parsedType.get(); if (performTypeLocChecking(loc, /*IsSILType=*/ false)) return true; result = loc.getType()->getCanonicalType(); // Invoke the callback on the parsed type. ParsedTypeCallback(loc.getType()); return false; } /// sil-type: /// '$' '*'? attribute-list (generic-params)? type /// bool SILParser::parseSILType(SILType &Result, GenericEnvironment *&GenericEnv, bool IsFuncDecl){ GenericEnv = nullptr; 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. SourceLoc inoutLoc; TypeAttributes attrs; P.parseTypeAttributeList(inoutLoc, 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.convention = "thin"; } ParserResult TyR = P.parseType(diag::expected_sil_type, /*handleCodeCompletion*/ true, /*isSILFuncDecl*/ IsFuncDecl); if (TyR.isNull()) return true; // Resolve the generic environments for parsed generic function and box types. class HandleSILGenericParamsWalker : public ASTWalker { ASTContext &C; SourceFile *SF; public: HandleSILGenericParamsWalker(ASTContext &C, SourceFile *SF) : C(C), SF(SF) {} bool walkToTypeReprPre(TypeRepr *T) override { if (auto fnType = dyn_cast(T)) { if (auto generics = fnType->getGenericParams()) { auto env = handleSILGenericParams(C, generics, SF); fnType->setGenericEnvironment(env); } } if (auto boxType = dyn_cast(T)) { if (auto generics = boxType->getGenericParams()) { auto env = handleSILGenericParams(C, generics, SF); boxType->setGenericEnvironment(env); } } return true; } }; TyR.get() ->walk(HandleSILGenericParamsWalker(P.Context, &P.SF)); // Save the top-level function generic environment if there was one. if (auto fnType = dyn_cast(TyR.get())) if (auto env = fnType->getGenericEnvironment()) GenericEnv = env; // Apply attributes to the type. TypeLoc Ty = P.applyAttributeToType(TyR.get(), inoutLoc, attrs); if (performTypeLocChecking(Ty, /*IsSILType=*/true, nullptr)) return true; Result = SILType::getPrimitiveType(Ty.getType()->getCanonicalType(), category); // Invoke the callback on the parsed type. ParsedTypeCallback(Ty.getType()); 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()); if (parseSILIdentifier(Id, diag::expected_sil_constant)) return true; FullName.push_back(Id); } while (P.consumeIf(tok::period)); // Look up ValueDecl from a dotted path. ValueDecl *VD; llvm::PointerUnion Res = lookupTopDecl(P, FullName[0]); // 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 AccessorKind getAccessorKind(StringRef ident) { return llvm::StringSwitch(ident) .Case("getter", AccessorKind::IsGetter) .Case("setter", AccessorKind::IsSetter) .Case("addressor", AccessorKind::IsAddressor) .Case("mutableAddressor", AccessorKind::IsMutableAddressor) .Case("materializeForSet", AccessorKind::IsMaterializeForSet) .Default(AccessorKind::NotAccessor); } /// sil-decl-ref ::= '#' sil-identifier ('.' sil-identifier)* sil-decl-subref? /// sil-decl-subref ::= '!' sil-decl-subref-part ('.' sil-decl-uncurry-level)? /// ('.' sil-decl-lang)? /// sil-decl-subref ::= '!' sil-decl-uncurry-level ('.' sil-decl-lang)? /// sil-decl-subref ::= '!' sil-decl-lang /// sil-decl-subref-part ::= 'getter' /// sil-decl-subref-part ::= 'setter' /// sil-decl-subref-part ::= 'materializeForSet' /// 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-uncurry-level ::= [0-9]+ /// sil-decl-lang ::= 'foreign' bool SILParser::parseSILDeclRef(SILDeclRef &Result, SmallVectorImpl &values) { ValueDecl *VD; if (parseSILDottedPath(VD, values)) return true; // Initialize Kind, uncurryLevel and IsObjC. SILDeclRef::Kind Kind = SILDeclRef::Kind::Func; unsigned uncurryLevel = 0; bool IsObjC = false; ResilienceExpansion expansion = ResilienceExpansion::Minimal; if (!P.consumeIf(tok::sil_exclamation)) { // Construct SILDeclRef. Result = SILDeclRef(VD, Kind, expansion, uncurryLevel, IsObjC); return false; } // Handle sil-constant-kind-and-uncurry-level. // ParseState indicates the value we just handled. // 1 means we just handled Kind, 2 means we just handled uncurryLevel. // We accept func|getter|setter|...|foreign or an integer when ParseState is // 0; accept foreign or an integer when ParseState is 1; accept foreign when // ParseState is 2. 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; AccessorKind accessorKind; if (!ParseState && Id.str() == "func") { Kind = SILDeclRef::Kind::Func; ParseState = 1; } else if (!ParseState && (accessorKind = getAccessorKind(Id.str())) != AccessorKind::NotAccessor) { auto storageDecl = dyn_cast(VD); auto accessor = (storageDecl ? storageDecl->getAccessorFunction(accessorKind) : nullptr); if (!accessor) { P.diagnose(IdLoc, diag::referenced_value_no_accessor, 0); return true; } Kind = SILDeclRef::Kind::Func; VD = accessor; // Update values for this accessor kind. for (unsigned I = 0, E = values.size(); I < E; I++) if (auto otherDecl = dyn_cast(values[I])) if (auto otherAccessor = otherDecl->getAccessorFunction(accessorKind)) values[I] = otherAccessor; 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() == "globalgetter") { Kind = SILDeclRef::Kind::GlobalGetter; 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 (Id.str() == "foreign") { IsObjC = true; break; } else break; } else if (ParseState < 2 && P.Tok.is(tok::integer_literal)) { P.Tok.getText().getAsInteger(0, uncurryLevel); P.consumeToken(tok::integer_literal); ParseState = 2; } else // TODO: resilience expansion? break; } while (P.consumeIf(tok::period)); // Construct SILDeclRef. Result = SILDeclRef(VD, Kind, expansion, uncurryLevel, IsObjC); 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; } /// getInstructionKind - This method maps the string form of a SIL instruction /// opcode to an enum. bool SILParser::parseSILOpcode(ValueKind &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. Optional MaybeOpcode = llvm::StringSwitch>(OpcodeName) #define INST(Id, Parent, TextualName, MemBehavior, MayRelease) \ .Case(#TextualName, ValueKind::Id) #include "swift/SIL/SILNodes.def" .Default(None); 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; } if (P.Tok.getText().getAsInteger(0, Var.ArgNo)) return true; } 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; if (P.parseList(tok::r_paren, LParenLoc, RParenLoc, /*AllowSepAfterLast=*/false, diag::sil_basicblock_arg_rparen, [&]() -> ParserStatus { SILValue Arg; SourceLoc ArgLoc; if (parseTypedValueRef(Arg, ArgLoc, B)) return makeParserError(); Args.push_back(Arg); return makeParserSuccess(); }).isError()) return true; } return false; } /// Parse the substitution list for an apply instruction or /// specialized protocol conformance. bool SILParser::parseSubstitutions(SmallVectorImpl &parsed, GenericEnvironment *GenericEnv) { // Check for an opening '<' bracket. if (!P.Tok.isContextualPunctuator("<")) return false; P.consumeToken(); // 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; TypeLoc Ty = TyR.get(); if (performTypeLocChecking(Ty, /*IsSILType=*/ false, GenericEnv)) return true; parsed.push_back({Loc, Ty.getType()}); } while (P.consumeIf(tok::comma)); // Consume the closing '>'. if (!P.Tok.isContextualPunctuator(">")) { P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, ">"); return true; } P.consumeToken(); return false; } /// Collect conformances by looking up the conformance from replacement /// type and protocol decl. static bool getConformancesForSubstitution(Parser &P, ArrayRef protocols, Type subReplacement, SourceLoc loc, SmallVectorImpl &conformances) { auto M = P.SF.getParentModule(); for (auto proto : protocols) { auto conformance = M->lookupConformance(subReplacement, proto, nullptr); if (conformance) { conformances.push_back(*conformance); continue; } P.diagnose(loc, diag::sil_substitution_mismatch, subReplacement, proto->getName()); return true; } return false; } /// Reconstruct AST substitutions from parsed substitutions using archetypes /// from a SILFunctionType. bool getApplySubstitutionsFromParsed( SILParser &SP, GenericEnvironment *env, ArrayRef parses, SmallVectorImpl &subs) { if (parses.empty()) { assert(!env); return false; } assert(env); auto loc = parses[0].loc; // Collect conformance requirements in a convenient form. llvm::DenseMap> conformsTo; for (auto reqt : env->getGenericSignature()->getRequirements()) { if (reqt.getKind() == RequirementKind::Conformance) { auto canTy = reqt.getFirstType()->getCanonicalType(); auto nominal = reqt.getSecondType()->getAnyNominal(); conformsTo[canTy.getPointer()].push_back(cast(nominal)); } } // The replacement is for the corresponding dependent type by ordering. for (auto depTy : env->getGenericSignature()->getAllDependentTypes()) { auto canTy = depTy->getCanonicalType().getPointer(); if (parses.empty()) { SP.P.diagnose(loc, diag::sil_missing_substitutions); return true; } auto parsed = parses.front(); parses = parses.slice(1); SmallVector conformances; if (getConformancesForSubstitution(SP.P, conformsTo[canTy], parsed.replacement, parsed.loc, conformances)) return true; subs.push_back({parsed.replacement, SP.P.Context.AllocateCopy(conformances)}); } if (!parses.empty()) { SP.P.diagnose(loc, diag::sil_too_many_substitutions); return true; } return false; } static ArrayRef collectExistentialConformances(Parser &P, CanType conformingType, SourceLoc loc, CanType protocolType) { SmallVector protocols; bool isExistential = protocolType->isAnyExistentialType(protocols); assert(isExistential); (void)isExistential; 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; } bool SILParser::parseSILDeclRef(SILDeclRef &Member, bool FnTypeRequired) { SourceLoc TyLoc; SmallVector values; if (parseSILDeclRef(Member, values)) return true; // : ( or : < means that what follows is function type. if (!P.Tok.is(tok::colon)) return false; if (FnTypeRequired && !P.peekToken().is(tok::l_paren) && !P.peekToken().isContextualPunctuator("<")) return false; // Type of the SILDeclRef is optional to be compatible with the old format. if (!P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":")) { // Parse the type for SILDeclRef. Optional GenericsScope; GenericsScope.emplace(&P, ScopeKind::Generics); ParserResult TyR = P.parseType(); GenericsScope.reset(); if (TyR.isNull()) return true; TypeLoc Ty = TyR.get(); // The type can be polymorphic. GenericEnvironment *genericEnv = nullptr; if (auto fnType = dyn_cast(TyR.get())) { if (auto generics = fnType->getGenericParams()) { assert(!Ty.wasValidated() && Ty.getType().isNull()); genericEnv = handleSILGenericParams(P.Context, generics, &P.SF); fnType->setGenericEnvironment(genericEnv); } } if (performTypeLocChecking(Ty, /*IsSILType=*/ false, genericEnv)) return true; // Pick the ValueDecl that has the right type. ValueDecl *TheDecl = nullptr; auto declTy = Ty.getType()->getCanonicalType(); auto unlabeledDecl = declTy->getUnlabeledType(P.Context)->getCanonicalType(); for (unsigned I = 0, E = values.size(); I < E; I++) { auto lookupTy = values[I]->getInterfaceType(); auto unlabeledLookup = lookupTy->getUnlabeledType(P.Context)->getCanonicalType(); if (unlabeledDecl == unlabeledLookup) { TheDecl = values[I]; // Update SILDeclRef to point to the right Decl. Member.loc = TheDecl; break; } if (values.size() == 1 && !TheDecl) { P.diagnose(TyLoc, diag::sil_member_decl_type_mismatch, declTy, lookupTy); return true; } } if (!TheDecl) { P.diagnose(TyLoc, diag::sil_member_decl_not_found); return true; } } return false; } /// sil-instruction-def ::= (sil-value-name '=')? sil-instruction /// (',' sil-scope-ref)? (',' sil-loc)? bool SILParser::parseSILInstruction(SILBasicBlock *BB, SILBuilder &B) { // We require SIL instructions to be at the start of a line to assist // recovery. if (!P.Tok.isAtStartOfLine()) { P.diagnose(P.Tok, diag::expected_sil_instr_start_of_line); return true; } StringRef ResultName; SourceLoc ResultNameLoc; // If the instruction has a name '%foo =', parse it. if (P.Tok.is(tok::sil_local_name)) { ResultName = P.Tok.getText(); ResultNameLoc = P.Tok.getLoc(); P.consumeToken(tok::sil_local_name); if (P.parseToken(tok::equal, diag::expected_equal_in_sil_instr)) return true; } ValueKind Opcode; SourceLoc OpcodeLoc; StringRef OpcodeName; // Parse the opcode name. if (parseSILOpcode(Opcode, OpcodeLoc, OpcodeName)) return true; B.setInsertionPoint(BB); SmallVector OpList; SILValue Val; SILLocation InstLoc = RegularLocation(OpcodeLoc); auto parseCastConsumptionKind = [&](Identifier name, SourceLoc loc, CastConsumptionKind &out) -> bool { auto kind = llvm::StringSwitch>(name.str()) .Case("take_always", CastConsumptionKind::TakeAlways) .Case("take_on_success", CastConsumptionKind::TakeOnSuccess) .Case("copy_on_success", CastConsumptionKind::CopyOnSuccess) .Default(None); if (kind) { out = kind.getValue(); return false; } P.diagnose(loc, diag::expected_tok_in_sil_instr, "cast consumption kind"); return true; }; auto parseOpenExistAddrKind = [&](Identifier name, SourceLoc loc, OpenedExistentialAccess &out) -> bool { auto kind = llvm::StringSwitch>(name.str()) .Case("mutable_access", OpenedExistentialAccess::Mutable) .Case("immutable_access", OpenedExistentialAccess::Immutable) .Default(None); if (kind) { out = kind.getValue(); return false; } P.diagnose(loc, diag::expected_tok_in_sil_instr, "opened existential access kind"); return true; }; // Validate the opcode name, and do opcode-specific parsing logic based on the // opcode we find. SILInstruction *ResultVal; switch (Opcode) { case ValueKind::SILPHIArgument: case ValueKind::SILFunctionArgument: case ValueKind::SILUndef: llvm_unreachable("not an instruction"); case ValueKind::AllocBoxInst: { SILType Ty; if (parseSILType(Ty)) return true; SILDebugVariable VarInfo; if (parseSILDebugVar(VarInfo)) return true; if (parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createAllocBox(InstLoc, Ty.castTo(), VarInfo); break; } case ValueKind::ApplyInst: case ValueKind::PartialApplyInst: case ValueKind::TryApplyInst: if (parseCallInstruction(InstLoc, Opcode, B, ResultVal)) return true; break; case ValueKind::IntegerLiteralInst: { SILType Ty; if (parseSILType(Ty) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",")) return true; bool Negative = false; if (P.Tok.isAnyOperator() && P.Tok.getText() == "-") { Negative = true; P.consumeToken(); } if (P.Tok.getKind() != tok::integer_literal) { P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "integer"); return true; } auto intTy = Ty.getAs(); if (!intTy) { P.diagnose(P.Tok, diag::sil_integer_literal_not_integer_type); return true; } APInt value(intTy->getGreatestWidth(), 0); bool error = P.Tok.getText().getAsInteger(0, value); assert(!error && "integer_literal token did not parse as APInt?!"); (void)error; if (Negative) value = -value; if (value.getBitWidth() != intTy->getGreatestWidth()) value = value.zextOrTrunc(intTy->getGreatestWidth()); P.consumeToken(tok::integer_literal); if (parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createIntegerLiteral(InstLoc, Ty, value); break; } case ValueKind::FloatLiteralInst: { SILType Ty; if (parseSILType(Ty) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",")) return true; // The value is expressed as bits. if (P.Tok.getKind() != tok::integer_literal) { P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "integer"); return true; } auto floatTy = Ty.getAs(); if (!floatTy) { P.diagnose(P.Tok, diag::sil_float_literal_not_float_type); return true; } APInt bits(floatTy->getBitWidth(), 0); bool error = P.Tok.getText().getAsInteger(0, bits); assert(!error && "float_literal token did not parse as APInt?!"); (void)error; if (bits.getBitWidth() != floatTy->getBitWidth()) bits = bits.zextOrTrunc(floatTy->getBitWidth()); APFloat value(floatTy->getAPFloatSemantics(), bits); if (parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createFloatLiteral(InstLoc, Ty, value); P.consumeToken(tok::integer_literal); break; } case ValueKind::StringLiteralInst: { if (P.Tok.getKind() != tok::identifier) { P.diagnose(P.Tok, diag::sil_string_no_encoding); return true; } StringLiteralInst::Encoding encoding; if (P.Tok.getText() == "utf8") { encoding = StringLiteralInst::Encoding::UTF8; } else if (P.Tok.getText() == "utf16") { encoding = StringLiteralInst::Encoding::UTF16; } else if (P.Tok.getText() == "objc_selector") { encoding = StringLiteralInst::Encoding::ObjCSelector; } else { P.diagnose(P.Tok, diag::sil_string_invalid_encoding, P.Tok.getText()); return true; } P.consumeToken(tok::identifier); 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 rawString = P.Tok.getText().drop_front().drop_back(); // Ask the lexer to interpret the entire string as a literal segment. SmallVector stringBuffer; StringRef string = P.L->getEncodedStringSegment(rawString, stringBuffer); P.consumeToken(tok::string_literal); if (parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createStringLiteral(InstLoc, string, encoding); break; } case ValueKind::AllocValueBufferInst: { SILType Ty; if (parseSILType(Ty) || parseVerbatim("in") || parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createAllocValueBuffer(InstLoc, Ty, Val); break; } case ValueKind::ProjectValueBufferInst: { SILType Ty; if (parseSILType(Ty) || parseVerbatim("in") || parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createProjectValueBuffer(InstLoc, Ty, Val); break; } case ValueKind::DeallocValueBufferInst: { SILType Ty; if (parseSILType(Ty) || parseVerbatim("in") || parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createDeallocValueBuffer(InstLoc, Ty, Val); break; } case ValueKind::ProjectBoxInst: { if (parseTypedValueRef(Val, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",")) return true; if (!P.Tok.is(tok::integer_literal)) { P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "integer"); return true; } unsigned Index; bool error = P.Tok.getText().getAsInteger(0, Index); assert(!error && "project_box index did not parse as integer?!"); (void)error; P.consumeToken(tok::integer_literal); if (parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createProjectBox(InstLoc, Val, Index); break; } case ValueKind::ProjectExistentialBoxInst: { SILType Ty; if (parseSILType(Ty) || parseVerbatim("in") || parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createProjectExistentialBox(InstLoc, Ty, Val); break; } case ValueKind::FunctionRefInst: if (parseSILFunctionRef(InstLoc, B, ResultVal)) return true; break; case ValueKind::BuiltinInst: { if (P.Tok.getKind() != tok::string_literal) { P.diagnose(P.Tok, diag::expected_tok_in_sil_instr,"builtin name"); return true; } StringRef Str = P.Tok.getText(); Identifier Id = P.Context.getIdentifier(Str.substr(1, Str.size()-2)); P.consumeToken(tok::string_literal); // Find the builtin in the Builtin module SmallVector foundBuiltins; P.Context.TheBuiltinModule->lookupMember(foundBuiltins, P.Context.TheBuiltinModule, Id, Identifier()); if (foundBuiltins.empty()) { P.diagnose(P.Tok, diag::expected_tok_in_sil_instr,"builtin name"); return true; } assert(foundBuiltins.size() == 1 && "ambiguous builtin name?!"); auto *builtinFunc = cast(foundBuiltins[0]); GenericEnvironment *genericEnv = builtinFunc->getGenericEnvironment(); SmallVector parsedSubs; SmallVector subs; if (parseSubstitutions(parsedSubs)) return true; if (!parsedSubs.empty()) { if (!genericEnv) { P.diagnose(P.Tok, diag::sil_substitutions_on_non_polymorphic_type); return true; } if (getApplySubstitutionsFromParsed(*this, genericEnv, parsedSubs, subs)) return true; } if (P.Tok.getKind() != tok::l_paren) { P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "("); return true; } P.consumeToken(tok::l_paren); SmallVector Args; while (true) { if (P.consumeIf(tok::r_paren)) break; SILValue Val; if (parseTypedValueRef(Val, B)) return true; Args.push_back(Val); if (P.consumeIf(tok::comma)) continue; if (P.consumeIf(tok::r_paren)) break; P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "(' or ',"); return true; } if (P.Tok.getKind() != tok::colon) { P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, ":"); return true; } P.consumeToken(tok::colon); SILType ResultTy; if (parseSILType(ResultTy)) return true; if (parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createBuiltin(InstLoc, Id, ResultTy, subs, Args); break; } case ValueKind::OpenExistentialAddrInst: case ValueKind::OpenExistentialBoxInst: case ValueKind::OpenExistentialMetatypeInst: case ValueKind::OpenExistentialRefInst: case ValueKind::OpenExistentialOpaqueInst: { SILType Ty; Identifier ToToken; SourceLoc ToLoc; OpenedExistentialAccess accessKind; Identifier accessKindToken; SourceLoc accessKindLoc; if (Opcode == ValueKind::OpenExistentialAddrInst) { if (parseSILIdentifier(accessKindToken, accessKindLoc, diag::expected_tok_in_sil_instr, "opened existential access kind") || parseOpenExistAddrKind(accessKindToken, accessKindLoc, accessKind)) return true; } if (parseTypedValueRef(Val, B) || parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr, "to") || parseSILType(Ty)) return true; if (ToToken.str() != "to") { P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to"); return true; } if (parseSILDebugLocation(InstLoc, B)) return true; switch (Opcode) { case ValueKind::OpenExistentialAddrInst: ResultVal = B.createOpenExistentialAddr(InstLoc, Val, Ty, accessKind); break; case ValueKind::OpenExistentialMetatypeInst: ResultVal = B.createOpenExistentialMetatype(InstLoc, Val, Ty); break; case ValueKind::OpenExistentialRefInst: ResultVal = B.createOpenExistentialRef(InstLoc, Val, Ty); break; case ValueKind::OpenExistentialBoxInst: ResultVal = B.createOpenExistentialBox(InstLoc, Val, Ty); break; case ValueKind::OpenExistentialOpaqueInst: ResultVal = B.createOpenExistentialOpaque(InstLoc, Val, Ty); break; default: llvm_unreachable("Inner switch out of sync with outer switch"); } break; } #define UNARY_INSTRUCTION(ID) \ case ValueKind::ID##Inst: \ if (parseTypedValueRef(Val, B)) return true; \ if (parseSILDebugLocation(InstLoc, B)) return true; \ ResultVal = B.create##ID(InstLoc, Val); \ break; #define REFCOUNTING_INSTRUCTION(ID) \ case ValueKind::ID##Inst: { \ Atomicity atomicity = Atomicity::Atomic; \ StringRef Optional; \ if (parseSILOptional(Optional, *this)) { \ if (Optional == "nonatomic") { \ atomicity = Atomicity::NonAtomic; \ } else { \ return true; \ } \ } \ if (parseTypedValueRef(Val, B)) \ return true; \ if (parseSILDebugLocation(InstLoc, B)) \ return true; \ ResultVal = B.create##ID(InstLoc, Val, atomicity); \ } break; UNARY_INSTRUCTION(FixLifetime) UNARY_INSTRUCTION(CopyBlock) UNARY_INSTRUCTION(IsUnique) UNARY_INSTRUCTION(IsUniqueOrPinned) UNARY_INSTRUCTION(DestroyAddr) UNARY_INSTRUCTION(CopyValue) UNARY_INSTRUCTION(CopyUnownedValue) UNARY_INSTRUCTION(DestroyValue) UNARY_INSTRUCTION(CondFail) UNARY_INSTRUCTION(EndBorrowArgument) UNARY_INSTRUCTION(UnmanagedReleaseValue) UNARY_INSTRUCTION(UnmanagedRetainValue) UNARY_INSTRUCTION(UnmanagedAutoreleaseValue) REFCOUNTING_INSTRUCTION(StrongPin) REFCOUNTING_INSTRUCTION(StrongRetain) REFCOUNTING_INSTRUCTION(StrongRelease) REFCOUNTING_INSTRUCTION(StrongUnpin) REFCOUNTING_INSTRUCTION(StrongRetainUnowned) REFCOUNTING_INSTRUCTION(UnownedRetain) REFCOUNTING_INSTRUCTION(UnownedRelease) REFCOUNTING_INSTRUCTION(AutoreleaseValue) REFCOUNTING_INSTRUCTION(SetDeallocating) REFCOUNTING_INSTRUCTION(ReleaseValue) REFCOUNTING_INSTRUCTION(RetainValue) #undef UNARY_INSTRUCTION #undef REFCOUNTING_INSTRUCTION case ValueKind::DebugValueInst: case ValueKind::DebugValueAddrInst: { SILDebugVariable VarInfo; if (parseTypedValueRef(Val, B) || parseSILDebugVar(VarInfo) || parseSILDebugLocation(InstLoc, B)) return true; if (Opcode == ValueKind::DebugValueInst) ResultVal = B.createDebugValue(InstLoc, Val, VarInfo); else ResultVal = B.createDebugValueAddr(InstLoc, Val, VarInfo); break; } case ValueKind::LoadInst: { LoadOwnershipQualifier Qualifier; SourceLoc AddrLoc; if (parseLoadOwnershipQualifier(Qualifier, *this) || parseTypedValueRef(Val, AddrLoc, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createLoad(InstLoc, Val, Qualifier); break; } case ValueKind::LoadBorrowInst: { SourceLoc AddrLoc; if (parseTypedValueRef(Val, AddrLoc, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createLoadBorrow(InstLoc, Val); break; } case ValueKind::BeginBorrowInst: { SourceLoc AddrLoc; if (parseTypedValueRef(Val, AddrLoc, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createBeginBorrow(InstLoc, Val); break; } case ValueKind::LoadUnownedInst: case ValueKind::LoadWeakInst: { bool isTake = false; SourceLoc addrLoc; if (parseSILOptional(isTake, *this, "take") || parseTypedValueRef(Val, addrLoc, B) || parseSILDebugLocation(InstLoc, B)) return true; if (Opcode == ValueKind::LoadUnownedInst) { if (!Val->getType().is()) { P.diagnose(addrLoc, diag::sil_operand_not_unowned_address, "source", OpcodeName); } ResultVal = B.createLoadUnowned(InstLoc, Val, IsTake_t(isTake)); } else { if (!Val->getType().is()) { P.diagnose(addrLoc, diag::sil_operand_not_weak_address, "source", OpcodeName); } ResultVal = B.createLoadWeak(InstLoc, Val, IsTake_t(isTake)); } break; } case ValueKind::MarkDependenceInst: { SILValue Base; if (parseTypedValueRef(Val, B) || parseVerbatim("on") || parseTypedValueRef(Base, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createMarkDependence(InstLoc, Val, Base); break; } // Conversion instructions. case ValueKind::UncheckedRefCastInst: case ValueKind::UncheckedAddrCastInst: case ValueKind::UncheckedTrivialBitCastInst: case ValueKind::UncheckedBitwiseCastInst: case ValueKind::UpcastInst: case ValueKind::AddressToPointerInst: case ValueKind::BridgeObjectToRefInst: case ValueKind::BridgeObjectToWordInst: case ValueKind::RefToRawPointerInst: case ValueKind::RawPointerToRefInst: case ValueKind::RefToUnownedInst: case ValueKind::UnownedToRefInst: case ValueKind::RefToUnmanagedInst: case ValueKind::UnmanagedToRefInst: case ValueKind::ThinFunctionToPointerInst: case ValueKind::PointerToThinFunctionInst: case ValueKind::ThinToThickFunctionInst: case ValueKind::ThickToObjCMetatypeInst: case ValueKind::ObjCToThickMetatypeInst: case ValueKind::ConvertFunctionInst: case ValueKind::ObjCExistentialMetatypeToObjectInst: case ValueKind::ObjCMetatypeToObjectInst: { SILType Ty; Identifier ToToken; SourceLoc ToLoc; if (parseTypedValueRef(Val, B) || parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr, "to") || parseSILType(Ty) || parseSILDebugLocation(InstLoc, B)) return true; if (ToToken.str() != "to") { P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to"); return true; } switch (Opcode) { default: llvm_unreachable("Out of sync with parent switch"); case ValueKind::UncheckedRefCastInst: ResultVal = B.createUncheckedRefCast(InstLoc, Val, Ty); break; case ValueKind::UncheckedAddrCastInst: ResultVal = B.createUncheckedAddrCast(InstLoc, Val, Ty); break; case ValueKind::UncheckedTrivialBitCastInst: ResultVal = B.createUncheckedTrivialBitCast(InstLoc, Val, Ty); break; case ValueKind::UncheckedBitwiseCastInst: ResultVal = B.createUncheckedBitwiseCast(InstLoc, Val, Ty); break; case ValueKind::UpcastInst: ResultVal = B.createUpcast(InstLoc, Val, Ty); break; case ValueKind::ConvertFunctionInst: ResultVal = B.createConvertFunction(InstLoc, Val, Ty); break; case ValueKind::AddressToPointerInst: ResultVal = B.createAddressToPointer(InstLoc, Val, Ty); break; case ValueKind::BridgeObjectToRefInst: ResultVal = B.createBridgeObjectToRef(InstLoc, Val, Ty); break; case ValueKind::BridgeObjectToWordInst: ResultVal = B.createBridgeObjectToWord(InstLoc, Val); break; case ValueKind::RefToRawPointerInst: ResultVal = B.createRefToRawPointer(InstLoc, Val, Ty); break; case ValueKind::RawPointerToRefInst: ResultVal = B.createRawPointerToRef(InstLoc, Val, Ty); break; case ValueKind::RefToUnownedInst: ResultVal = B.createRefToUnowned(InstLoc, Val, Ty); break; case ValueKind::UnownedToRefInst: ResultVal = B.createUnownedToRef(InstLoc, Val, Ty); break; case ValueKind::RefToUnmanagedInst: ResultVal = B.createRefToUnmanaged(InstLoc, Val, Ty); break; case ValueKind::UnmanagedToRefInst: ResultVal = B.createUnmanagedToRef(InstLoc, Val, Ty); break; case ValueKind::ThinFunctionToPointerInst: ResultVal = B.createThinFunctionToPointer(InstLoc, Val, Ty); break; case ValueKind::PointerToThinFunctionInst: ResultVal = B.createPointerToThinFunction(InstLoc, Val, Ty); break; case ValueKind::ThinToThickFunctionInst: ResultVal = B.createThinToThickFunction(InstLoc, Val, Ty); break; case ValueKind::ThickToObjCMetatypeInst: ResultVal = B.createThickToObjCMetatype(InstLoc, Val, Ty); break; case ValueKind::ObjCToThickMetatypeInst: ResultVal = B.createObjCToThickMetatype(InstLoc, Val, Ty); break; case ValueKind::ObjCMetatypeToObjectInst: ResultVal = B.createObjCMetatypeToObject(InstLoc, Val, Ty); break; case ValueKind::ObjCExistentialMetatypeToObjectInst: ResultVal = B.createObjCExistentialMetatypeToObject(InstLoc, Val, Ty); break; } break; } case ValueKind::PointerToAddressInst: { SILType Ty; Identifier ToToken; SourceLoc ToLoc; bool isStrict = false; if (parseTypedValueRef(Val, B) || parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr, "to") || parseSILOptional(isStrict, *this, "strict") || parseSILType(Ty) || parseSILDebugLocation(InstLoc, B)) return true; if (ToToken.str() != "to") { P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to"); return true; } ResultVal = B.createPointerToAddress(InstLoc, Val, Ty, isStrict); break; } case ValueKind::RefToBridgeObjectInst: { SILValue BitsVal; if (parseTypedValueRef(Val, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseTypedValueRef(BitsVal, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createRefToBridgeObject(InstLoc, Val, BitsVal); break; } // Indirect checked conversion instructions. case ValueKind::UnconditionalCheckedCastAddrInst: case ValueKind::CheckedCastAddrBranchInst: case ValueKind::UncheckedRefCastAddrInst: { CastConsumptionKind consumptionKind; if (Opcode == ValueKind::UncheckedRefCastAddrInst) consumptionKind = CastConsumptionKind::TakeAlways; else { Identifier consumptionKindToken; SourceLoc consumptionKindLoc; if (parseSILIdentifier(consumptionKindToken, consumptionKindLoc, diag::expected_tok_in_sil_instr, "cast consumption kind") || parseCastConsumptionKind(consumptionKindToken, consumptionKindLoc, consumptionKind)) return true; } auto parseFormalTypeAndValue = [&](CanType &formalType, SILValue &value) -> bool { return (parseASTType(formalType) || parseVerbatim("in") || parseTypedValueRef(value, B)); }; CanType sourceType, targetType; SILValue sourceAddr, destAddr; if (parseFormalTypeAndValue(sourceType, sourceAddr) || parseVerbatim("to") || parseFormalTypeAndValue(targetType, destAddr)) return true; if (Opcode == ValueKind::UncheckedRefCastAddrInst) { if (parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createUncheckedRefCastAddr(InstLoc, sourceAddr, sourceType, destAddr, targetType); break; } else if (Opcode == ValueKind::UnconditionalCheckedCastAddrInst) { if (parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createUnconditionalCheckedCastAddr(InstLoc, consumptionKind, sourceAddr, sourceType, destAddr, targetType); break; } // The conditional cast still needs its branch destinations. Identifier successBBName, failureBBName; SourceLoc successBBLoc, failureBBLoc; if (P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILIdentifier(successBBName, successBBLoc, diag::expected_sil_block_name) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILIdentifier(failureBBName, failureBBLoc, diag::expected_sil_block_name) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createCheckedCastAddrBranch(InstLoc, consumptionKind, sourceAddr, sourceType, destAddr, targetType, getBBForReference(successBBName, successBBLoc), getBBForReference(failureBBName, failureBBLoc)); break; } // Checked Conversion instructions. case ValueKind::UnconditionalCheckedCastInst: case ValueKind::CheckedCastBranchInst: { SILType ty; SILValue destVal; Identifier toToken; SourceLoc toLoc; bool isExact = false; if (Opcode == ValueKind::CheckedCastBranchInst && parseSILOptional(isExact, *this, "exact")) return true; if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(ty)) return true; // An unconditional cast instruction is finished here. if (Opcode == ValueKind::UnconditionalCheckedCastInst) { if (parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createUnconditionalCheckedCast(InstLoc, Val, ty); break; } // The conditional cast still needs its branch destinations. Identifier successBBName, failureBBName; SourceLoc successBBLoc, failureBBLoc; if (P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILIdentifier(successBBName, successBBLoc, diag::expected_sil_block_name) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILIdentifier(failureBBName, failureBBLoc, diag::expected_sil_block_name) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createCheckedCastBranch(InstLoc, isExact, Val, ty, getBBForReference(successBBName, successBBLoc), getBBForReference(failureBBName, failureBBLoc)); break; } case ValueKind::MarkUninitializedInst: { if (P.parseToken(tok::l_square, diag::expected_tok_in_sil_instr, "[")) return true; Identifier KindId; SourceLoc KindLoc = P.Tok.getLoc(); if (P.consumeIf(tok::kw_var)) KindId = P.Context.getIdentifier("var"); else if (P.parseIdentifier(KindId, KindLoc, diag::expected_tok_in_sil_instr, "kind")) return true; if (P.parseToken(tok::r_square, diag::expected_tok_in_sil_instr, "]")) return true; MarkUninitializedInst::Kind Kind; if (KindId.str() == "var") Kind = MarkUninitializedInst::Var; else if (KindId.str() == "rootself") Kind = MarkUninitializedInst::RootSelf; else if (KindId.str() == "derivedself") Kind = MarkUninitializedInst::DerivedSelf; else if (KindId.str() == "derivedselfonly") Kind = MarkUninitializedInst::DerivedSelfOnly; else if (KindId.str() == "delegatingself") Kind = MarkUninitializedInst::DelegatingSelf; else { P.diagnose(KindLoc, diag::expected_tok_in_sil_instr, "var, rootself, derivedself, derivedselfonly, " "or delegatingself"); return true; } if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createMarkUninitialized(InstLoc, Val, Kind); break; } case ValueKind::MarkUninitializedBehaviorInst: { UnresolvedValueName InitStorageFuncName, StorageName, SetterFuncName, SelfName; SmallVector ParsedInitStorageSubs, ParsedSetterSubs; GenericEnvironment *InitStorageEnv, *SetterEnv; SILType InitStorageTy, SetterTy; // mark_uninitialized_behavior %init(%storage) : $T -> U, // %set(%self) : $V -> W if (parseValueName(InitStorageFuncName) || parseSubstitutions(ParsedInitStorageSubs) || P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "(") || parseValueName(StorageName) || P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")") || P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") || parseSILType(InitStorageTy, InitStorageEnv) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseValueName(SetterFuncName) || parseSubstitutions(ParsedSetterSubs) || P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "(") || parseValueName(SelfName) || P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")") || P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") || parseSILType(SetterTy, SetterEnv) || parseSILDebugLocation(InstLoc, B)) return true; // Resolve the types of the operands. SILValue InitStorageFunc = getLocalValue(InitStorageFuncName, InitStorageTy, InstLoc, B); SILValue SetterFunc = getLocalValue(SetterFuncName, SetterTy, InstLoc, B); SmallVector InitStorageSubs, SetterSubs; if (getApplySubstitutionsFromParsed(*this, InitStorageEnv, ParsedInitStorageSubs, InitStorageSubs) || getApplySubstitutionsFromParsed(*this, SetterEnv, ParsedSetterSubs, SetterSubs)) return true; auto SubstInitStorageTy = InitStorageTy.castTo() ->substGenericArgs(B.getModule(), InitStorageSubs); auto SubstSetterTy = SetterTy.castTo() ->substGenericArgs(B.getModule(), SetterSubs); // Derive the storage type from the initStorage method. auto StorageTy = SILType::getPrimitiveAddressType( SubstInitStorageTy->getSingleResult().getType()); auto Storage = getLocalValue(StorageName, StorageTy, InstLoc, B); SILFunctionConventions substConv(SubstSetterTy, B.getModule()); auto SelfTy = substConv.getSILType(SubstSetterTy->getSelfParameter()); auto Self = getLocalValue(SelfName, SelfTy, InstLoc, B); auto PropTy = SubstInitStorageTy->getParameters()[0] .getSILStorageType() .getAddressType(); ResultVal = B.createMarkUninitializedBehavior(InstLoc, InitStorageFunc, InitStorageSubs, Storage, SetterFunc, SetterSubs, Self, PropTy); break; } case ValueKind::MarkFunctionEscapeInst: { SmallVector OpList; do { if (parseTypedValueRef(Val, B)) return true; OpList.push_back(Val); } while (!peekSILDebugLocation(P) && P.consumeIf(tok::comma)); if (parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createMarkFunctionEscape(InstLoc, OpList); break; } case ValueKind::StoreInst: { UnresolvedValueName From; SourceLoc ToLoc, AddrLoc; Identifier ToToken; SILValue AddrVal; StoreOwnershipQualifier Qualifier; if (parseValueName(From) || parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr, "to")) return true; if (parseStoreOwnershipQualifier(Qualifier, *this)) return true; if (parseTypedValueRef(AddrVal, AddrLoc, B) || parseSILDebugLocation(InstLoc, B)) return true; if (ToToken.str() != "to") { P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to"); return true; } if (!AddrVal->getType().isAddress()) { P.diagnose(AddrLoc, diag::sil_operand_not_address, "destination", OpcodeName); return true; } SILType ValType = AddrVal->getType().getObjectType(); ResultVal = B.createStore(InstLoc, getLocalValue(From, ValType, InstLoc, B), AddrVal, Qualifier); break; } case ValueKind::EndBorrowInst: { UnresolvedValueName BorrowedFromName, BorrowedValueName; SourceLoc ToLoc; Identifier ToToken; SILType BorrowedFromTy, BorrowedValueTy; if (parseValueName(BorrowedValueName) || parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr, "from") || parseValueName(BorrowedFromName) || P.parseToken(tok::colon, diag::expected_sil_colon_value_ref) || parseSILType(BorrowedValueTy) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILType(BorrowedFromTy) || parseSILDebugLocation(InstLoc, B)) return true; if (ToToken.str() != "from") { P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "from"); return true; } SILValue BorrowedValue = getLocalValue(BorrowedValueName, BorrowedValueTy, InstLoc, B); SILValue BorrowedFrom = getLocalValue(BorrowedFromName, BorrowedFromTy, InstLoc, B); ResultVal = B.createEndBorrow(InstLoc, BorrowedValue, BorrowedFrom); break; } case ValueKind::StoreBorrowInst: case ValueKind::AssignInst: case ValueKind::StoreUnownedInst: case ValueKind::StoreWeakInst: { UnresolvedValueName from; SourceLoc toLoc, addrLoc; Identifier toToken; SILValue addrVal; bool isInit = false; if (parseValueName(from) || parseSILIdentifier(toToken, toLoc, diag::expected_tok_in_sil_instr, "to") || ((Opcode == ValueKind::StoreWeakInst || Opcode == ValueKind::StoreUnownedInst) && parseSILOptional(isInit, *this, "initialization")) || parseTypedValueRef(addrVal, addrLoc, B) || parseSILDebugLocation(InstLoc, B)) return true; if (toToken.str() != "to") { P.diagnose(toLoc, diag::expected_tok_in_sil_instr, "to"); return true; } if (!addrVal->getType().isAddress()) { P.diagnose(addrLoc, diag::sil_operand_not_address, "destination", OpcodeName); return true; } if (Opcode == ValueKind::StoreBorrowInst) { SILType valueTy = addrVal->getType().getObjectType(); ResultVal = B.createStoreBorrow( InstLoc, getLocalValue(from, valueTy, InstLoc, B), addrVal); break; } if (Opcode == ValueKind::StoreUnownedInst) { auto refType = addrVal->getType().getAs(); if (!refType) { P.diagnose(addrLoc, diag::sil_operand_not_unowned_address, "destination", OpcodeName); return true; } auto valueTy = SILType::getPrimitiveObjectType(refType.getReferentType()); ResultVal = B.createStoreUnowned(InstLoc, getLocalValue(from, valueTy, InstLoc, B), addrVal, IsInitialization_t(isInit)); break; } if (Opcode == ValueKind::StoreWeakInst) { auto refType = addrVal->getType().getAs(); if (!refType) { P.diagnose(addrLoc, diag::sil_operand_not_weak_address, "destination", OpcodeName); return true; } auto valueTy = SILType::getPrimitiveObjectType(refType.getReferentType()); ResultVal = B.createStoreWeak(InstLoc, getLocalValue(from, valueTy, InstLoc, B), addrVal, IsInitialization_t(isInit)); break; } SILType ValType = addrVal->getType().getObjectType(); assert(Opcode == ValueKind::AssignInst); ResultVal = B.createAssign(InstLoc, getLocalValue(from, ValType, InstLoc, B), addrVal); break; } case ValueKind::AllocStackInst: case ValueKind::MetatypeInst: { SILType Ty; if (parseSILType(Ty)) return true; if (Opcode == ValueKind::AllocStackInst) { SILDebugVariable VarInfo; if (parseSILDebugVar(VarInfo) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createAllocStack(InstLoc, Ty, VarInfo); } else { assert(Opcode == ValueKind::MetatypeInst); if (parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createMetatype(InstLoc, Ty); } break; } case ValueKind::AllocRefInst: case ValueKind::AllocRefDynamicInst: { bool IsObjC = false; bool OnStack = false; SmallVector ElementTypes; SmallVector ElementCounts; StringRef Optional; while (P.consumeIf(tok::l_square)) { Identifier Id; parseSILIdentifier(Id, diag::expected_in_attribute_list); StringRef Optional = Id.str(); if (Optional == "objc") { IsObjC = true; } else if (Optional == "stack") { OnStack = true; } else if (Optional == "tail_elems") { SILType ElemTy; if (parseSILType(ElemTy) || !P.Tok.isAnyOperator() || P.Tok.getText() != "*") return true; P.consumeToken(); SILValue ElemCount; if (parseTypedValueRef(ElemCount, B)) return true; ElementTypes.push_back(ElemTy); ElementCounts.push_back(ElemCount); } else { return true; } P.parseToken(tok::r_square, diag::expected_in_attribute_list); } SILValue Metadata; if (Opcode == ValueKind::AllocRefDynamicInst) { if (parseTypedValueRef(Metadata, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",")) return true; } SILType ObjectType; if (parseSILType(ObjectType)) return true; if (parseSILDebugLocation(InstLoc, B)) return true; if (IsObjC && ElementTypes.size() != 0) { P.diagnose(P.Tok, diag::sil_objc_with_tail_elements); return true; } if (Opcode == ValueKind::AllocRefDynamicInst) { if (OnStack) return true; ResultVal = B.createAllocRefDynamic(InstLoc, Metadata, ObjectType, IsObjC, ElementTypes, ElementCounts); } else { ResultVal = B.createAllocRef(InstLoc, ObjectType, IsObjC, OnStack, ElementTypes, ElementCounts); } break; } case ValueKind::DeallocStackInst: if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createDeallocStack(InstLoc, Val); break; case ValueKind::DeallocRefInst: { bool OnStack = false; if (parseSILOptional(OnStack, *this, "stack")) return true; if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createDeallocRef(InstLoc, Val, OnStack); break; } case ValueKind::DeallocPartialRefInst: { SILValue Metatype, Instance; if (parseTypedValueRef(Instance, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseTypedValueRef(Metatype, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createDeallocPartialRef(InstLoc, Instance, Metatype); break; } case ValueKind::DeallocBoxInst: if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createDeallocBox(InstLoc, Val); break; case ValueKind::ValueMetatypeInst: case ValueKind::ExistentialMetatypeInst: { SILType Ty; if (parseSILType(Ty) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B)) return true; switch (Opcode) { default: llvm_unreachable("Out of sync with parent switch"); case ValueKind::ValueMetatypeInst: ResultVal = B.createValueMetatype(InstLoc, Ty, Val); break; case ValueKind::ExistentialMetatypeInst: ResultVal = B.createExistentialMetatype(InstLoc, Ty, Val); break; case ValueKind::DeallocBoxInst: ResultVal = B.createDeallocBox(InstLoc, Val); break; } break; } case ValueKind::DeallocExistentialBoxInst: { CanType ConcreteTy; if (parseTypedValueRef(Val, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") || parseASTType(ConcreteTy) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createDeallocExistentialBox(InstLoc, ConcreteTy, Val); break; } case ValueKind::TupleInst: { // Tuple instructions have two different syntaxes, one for simple tuple // types, one for complicated ones. if (P.Tok.isNot(tok::sil_dollar)) { // If there is no type, parse the simple form. if (P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "(")) return true; // TODO: Check for a type here. This is how tuples with "interesting" // types are described. // This form is used with tuples that have elements with no names or // default values. SmallVector TypeElts; if (P.Tok.isNot(tok::r_paren)) { do { if (parseTypedValueRef(Val, B)) return true; OpList.push_back(Val); TypeElts.push_back(Val->getType().getSwiftRValueType()); } while (P.consumeIf(tok::comma)); } HadError |= P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr,")"); auto Ty = TupleType::get(TypeElts, P.Context); auto Ty2 = SILType::getPrimitiveObjectType(Ty->getCanonicalType()); if (parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createTuple(InstLoc, Ty2, OpList); break; } // Otherwise, parse the fully general form. SILType Ty; if (parseSILType(Ty) || P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "(")) return true; TupleType *TT = Ty.getAs(); if (TT == nullptr) { P.diagnose(OpcodeLoc, diag::expected_tuple_type_in_tuple); return true; } SmallVector TypeElts; if (P.Tok.isNot(tok::r_paren)) { do { if (TypeElts.size() > TT->getNumElements()) { P.diagnose(P.Tok, diag::sil_tuple_inst_wrong_value_count, TT->getNumElements()); return true; } Type EltTy = TT->getElement(TypeElts.size()).getType(); if (parseValueRef(Val, SILType::getPrimitiveObjectType(EltTy->getCanonicalType()), RegularLocation(P.Tok.getLoc()), B)) return true; OpList.push_back(Val); TypeElts.push_back(Val->getType().getSwiftRValueType()); } while (P.consumeIf(tok::comma)); } HadError |= P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr,")"); if (TypeElts.size() != TT->getNumElements()) { P.diagnose(OpcodeLoc, diag::sil_tuple_inst_wrong_value_count, TT->getNumElements()); return true; } if (parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createTuple(InstLoc, Ty, OpList); break; } case ValueKind::EnumInst: { SILType Ty; SILDeclRef Elt; SILValue Operand; if (parseSILType(Ty) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILDeclRef(Elt)) return true; if (P.Tok.is(tok::comma) && !peekSILDebugLocation(P)) { P.consumeToken(tok::comma); if (parseTypedValueRef(Operand, B)) return true; } if (parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createEnum(InstLoc, Operand, cast(Elt.getDecl()), Ty); break; } case ValueKind::InitEnumDataAddrInst: case ValueKind::UncheckedEnumDataInst: case ValueKind::UncheckedTakeEnumDataAddrInst: { SILValue Operand; SILDeclRef EltRef; if (parseTypedValueRef(Operand, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILDeclRef(EltRef) || parseSILDebugLocation(InstLoc, B)) return true; EnumElementDecl *Elt = cast(EltRef.getDecl()); auto ResultTy = Operand->getType().getEnumElementType(Elt, SILMod); switch (Opcode) { case swift::ValueKind::InitEnumDataAddrInst: ResultVal = B.createInitEnumDataAddr(InstLoc, Operand, Elt, ResultTy); break; case swift::ValueKind::UncheckedTakeEnumDataAddrInst: ResultVal = B.createUncheckedTakeEnumDataAddr(InstLoc, Operand, Elt, ResultTy); break; case swift::ValueKind::UncheckedEnumDataInst: ResultVal = B.createUncheckedEnumData(InstLoc, Operand, Elt, ResultTy); break; default: llvm_unreachable("switch out of sync"); } break; } case ValueKind::InjectEnumAddrInst: { SILValue Operand; SILDeclRef EltRef; if (parseTypedValueRef(Operand, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILDeclRef(EltRef) || parseSILDebugLocation(InstLoc, B)) return true; EnumElementDecl *Elt = cast(EltRef.getDecl()); ResultVal = B.createInjectEnumAddr(InstLoc, Operand, Elt); break; } case ValueKind::TupleElementAddrInst: case ValueKind::TupleExtractInst: { SourceLoc NameLoc; if (parseTypedValueRef(Val, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",")) return true; unsigned Field = 0; TupleType *TT = Val->getType().getAs(); if (P.Tok.isNot(tok::integer_literal) || P.Tok.getText().getAsInteger(10, Field) || Field >= TT->getNumElements()) { P.diagnose(P.Tok, diag::sil_tuple_inst_wrong_field); return true; } P.consumeToken(tok::integer_literal); if (parseSILDebugLocation(InstLoc, B)) return true; auto ResultTy = TT->getElement(Field).getType()->getCanonicalType(); if (Opcode == ValueKind::TupleElementAddrInst) ResultVal = B.createTupleElementAddr(InstLoc, Val, Field, SILType::getPrimitiveAddressType(ResultTy)); else ResultVal = B.createTupleExtract(InstLoc, Val, Field, SILType::getPrimitiveObjectType(ResultTy)); break; } case ValueKind::ReturnInst: { if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createReturn(InstLoc, Val); break; } case ValueKind::ThrowInst: { if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createThrow(InstLoc, Val); break; } case ValueKind::BranchInst: { Identifier BBName; SourceLoc NameLoc; if (parseSILIdentifier(BBName, NameLoc, diag::expected_sil_block_name)) return true; SmallVector Args; if (parseSILBBArgsAtBranch(Args, B)) return true; if (parseSILDebugLocation(InstLoc, B)) return true; // Note, the basic block here could be a reference to an undefined // basic block, which will be parsed later on. ResultVal = B.createBranch(InstLoc, getBBForReference(BBName, NameLoc), Args); break; } case ValueKind::CondBranchInst: { UnresolvedValueName Cond; Identifier BBName, BBName2; SourceLoc NameLoc, NameLoc2; SmallVector Args, Args2; if (parseValueName(Cond) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILIdentifier(BBName, NameLoc, diag::expected_sil_block_name) || parseSILBBArgsAtBranch(Args, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILIdentifier(BBName2, NameLoc2, diag::expected_sil_block_name) || parseSILBBArgsAtBranch(Args2, B) || parseSILDebugLocation(InstLoc, B)) return true; auto I1Ty = SILType::getBuiltinIntegerType(1, BB->getParent()->getASTContext()); SILValue CondVal = getLocalValue(Cond, I1Ty, InstLoc, B); ResultVal = B.createCondBranch(InstLoc, CondVal, getBBForReference(BBName, NameLoc), Args, getBBForReference(BBName2, NameLoc2), Args2); break; } case ValueKind::UnreachableInst: if (parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createUnreachable(InstLoc); break; case ValueKind::ClassMethodInst: case ValueKind::SuperMethodInst: case ValueKind::DynamicMethodInst: { bool IsVolatile = false; if (parseSILOptional(IsVolatile, *this, "volatile")) return true; SILDeclRef Member; SILType MethodTy; SourceLoc TyLoc; SmallVector values; if (parseTypedValueRef(Val, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",")) return true; if (parseSILDeclRef(Member, true)) return true; if (P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILType(MethodTy, TyLoc) || parseSILDebugLocation(InstLoc, B)) return true; switch (Opcode) { default: llvm_unreachable("Out of sync with parent switch"); case ValueKind::ClassMethodInst: ResultVal = B.createClassMethod(InstLoc, Val, Member, MethodTy, IsVolatile); break; case ValueKind::SuperMethodInst: ResultVal = B.createSuperMethod(InstLoc, Val, Member, MethodTy, IsVolatile); break; case ValueKind::DynamicMethodInst: ResultVal = B.createDynamicMethod(InstLoc, Val, Member, MethodTy, IsVolatile); break; } break; } case ValueKind::WitnessMethodInst: { bool IsVolatile = false; if (parseSILOptional(IsVolatile, *this, "volatile")) return true; CanType LookupTy; SILDeclRef Member; SILType MethodTy; SourceLoc TyLoc; if (P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") || parseASTType(LookupTy) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",")) return true; if (parseSILDeclRef(Member, true)) return true; // Optional operand. SILValue Operand; if (P.Tok.is(tok::comma)) { P.consumeToken(tok::comma); if (parseTypedValueRef(Operand, B)) return true; } if (P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") || parseSILType(MethodTy, TyLoc) || parseSILDebugLocation(InstLoc, B)) return true; // If LookupTy is a non-archetype, look up its conformance. ProtocolDecl *proto = dyn_cast(Member.getDecl()->getDeclContext()); if (!proto) { P.diagnose(TyLoc, diag::sil_witness_method_not_protocol); return true; } ProtocolConformanceRef Conformance(proto); if (!isa(LookupTy)) { auto lookup = P.SF.getParentModule()->lookupConformance( LookupTy, proto, nullptr); if (!lookup) { P.diagnose(TyLoc, diag::sil_witness_method_type_does_not_conform); return true; } Conformance = ProtocolConformanceRef(*lookup); } ResultVal = B.createWitnessMethod(InstLoc, LookupTy, Conformance, Member, MethodTy, IsVolatile); break; } case ValueKind::CopyAddrInst: { bool IsTake = false, IsInit = false; UnresolvedValueName SrcLName; SILValue DestLVal; SourceLoc ToLoc, DestLoc; Identifier ToToken; if (parseSILOptional(IsTake, *this, "take") || parseValueName(SrcLName) || parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr, "to") || parseSILOptional(IsInit, *this, "initialization") || parseTypedValueRef(DestLVal, DestLoc, B) || parseSILDebugLocation(InstLoc, B)) return true; if (ToToken.str() != "to") { P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to"); return true; } if (!DestLVal->getType().isAddress()) { P.diagnose(DestLoc, diag::sil_invalid_instr_operands); return true; } SILValue SrcLVal = getLocalValue(SrcLName, DestLVal->getType(), InstLoc, B); ResultVal = B.createCopyAddr(InstLoc, SrcLVal, DestLVal, IsTake_t(IsTake), IsInitialization_t(IsInit)); break; } case ValueKind::BindMemoryInst: { SILValue IndexVal; Identifier ToToken; SourceLoc ToLoc; SILType EltTy; if (parseTypedValueRef(Val, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseTypedValueRef(IndexVal, B) || parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr, "to") || parseSILType(EltTy) || parseSILDebugLocation(InstLoc, B)) return true; if (ToToken.str() != "to") { P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to"); return true; } ResultVal = B.createBindMemory(InstLoc, Val, IndexVal, EltTy); break; } case ValueKind::StructInst: { SILType StructTy; if (parseSILType(StructTy) || P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "(")) return true; // Parse a list of SILValue. if (P.Tok.isNot(tok::r_paren)) { do { if (parseTypedValueRef(Val, B)) return true; OpList.push_back(Val); } while (P.consumeIf(tok::comma)); } if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr,")") || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createStruct(InstLoc, StructTy, OpList); break; } case ValueKind::StructElementAddrInst: case ValueKind::StructExtractInst: { ValueDecl *FieldV; SourceLoc NameLoc = P.Tok.getLoc(); if (parseTypedValueRef(Val, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILDottedPath(FieldV) || parseSILDebugLocation(InstLoc, B)) return true; if (!FieldV || !isa(FieldV)) { P.diagnose(NameLoc, diag::sil_struct_inst_wrong_field); return true; } VarDecl *Field = cast(FieldV); // FIXME: substitution means this type should be explicit to improve // performance. auto ResultTy = Val->getType().getFieldType(Field, SILMod); if (Opcode == ValueKind::StructElementAddrInst) ResultVal = B.createStructElementAddr(InstLoc, Val, Field, ResultTy.getAddressType()); else ResultVal = B.createStructExtract(InstLoc, Val, Field, ResultTy.getObjectType()); break; } case ValueKind::RefElementAddrInst: { ValueDecl *FieldV; SourceLoc NameLoc; if (parseTypedValueRef(Val, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILDottedPath(FieldV) || parseSILDebugLocation(InstLoc, B)) return true; if (!FieldV || !isa(FieldV)) { P.diagnose(NameLoc, diag::sil_ref_inst_wrong_field); return true; } VarDecl *Field = cast(FieldV); auto ResultTy = Val->getType().getFieldType(Field, SILMod); ResultVal = B.createRefElementAddr(InstLoc, Val, Field, ResultTy); break; } case ValueKind::RefTailAddrInst: { SourceLoc NameLoc; SILType ResultObjTy; if (parseTypedValueRef(Val, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILType(ResultObjTy) || parseSILDebugLocation(InstLoc, B)) return true; SILType ResultTy = ResultObjTy.getAddressType(); ResultVal = B.createRefTailAddr(InstLoc, Val, ResultTy); break; } case ValueKind::IsNonnullInst: { SourceLoc Loc; if (parseTypedValueRef(Val, Loc, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createIsNonnull(InstLoc, Val); break; } case ValueKind::IndexAddrInst: { SILValue IndexVal; if (parseTypedValueRef(Val, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseTypedValueRef(IndexVal, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createIndexAddr(InstLoc, Val, IndexVal); break; } case ValueKind::TailAddrInst: { SILValue IndexVal; SILType ResultObjTy; if (parseTypedValueRef(Val, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseTypedValueRef(IndexVal, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILType(ResultObjTy) || parseSILDebugLocation(InstLoc, B)) return true; SILType ResultTy = ResultObjTy.getAddressType(); ResultVal = B.createTailAddr(InstLoc, Val, IndexVal, ResultTy); break; } case ValueKind::IndexRawPointerInst: { SILValue IndexVal; if (parseTypedValueRef(Val, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseTypedValueRef(IndexVal, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createIndexRawPointer(InstLoc, Val, IndexVal); break; } case ValueKind::ObjCProtocolInst: { Identifier ProtocolName; SILType Ty; if (P.parseToken(tok::pound, diag::expected_sil_constant) || parseSILIdentifier(ProtocolName, diag::expected_sil_constant) || P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") || parseSILType(Ty) || parseSILDebugLocation(InstLoc, B)) return true; // Find the decl for the protocol name. ValueDecl *VD; SmallVector CurModuleResults; // Perform a module level lookup on the first component of the // fully-qualified name. P.SF.getParentModule()->lookupValue(ModuleDecl::AccessPathTy(), ProtocolName, NLKind::UnqualifiedLookup, CurModuleResults); assert(CurModuleResults.size() == 1); VD = CurModuleResults[0]; ResultVal = B.createObjCProtocol(InstLoc, cast(VD), Ty); break; } case ValueKind::AllocGlobalInst: { Identifier GlobalName; SourceLoc IdLoc; if (P.parseToken(tok::at_sign, diag::expected_sil_value_name) || parseSILIdentifier(GlobalName, IdLoc, diag::expected_sil_value_name) || parseSILDebugLocation(InstLoc, B)) return true; // Go through list of global variables in the SILModule. SILGlobalVariable *global = SILMod.lookUpGlobalVariable(GlobalName.str()); if (!global) { P.diagnose(IdLoc, diag::sil_global_variable_not_found, GlobalName); return true; } ResultVal = B.createAllocGlobal(InstLoc, global); break; } case ValueKind::GlobalAddrInst: { Identifier GlobalName; SourceLoc IdLoc; SILType Ty; if (P.parseToken(tok::at_sign, diag::expected_sil_value_name) || parseSILIdentifier(GlobalName, IdLoc, diag::expected_sil_value_name) || P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") || parseSILType(Ty) || parseSILDebugLocation(InstLoc, B)) return true; // Go through list of global variables in the SILModule. SILGlobalVariable *global = SILMod.lookUpGlobalVariable(GlobalName.str()); if (!global) { P.diagnose(IdLoc, diag::sil_global_variable_not_found, GlobalName); return true; } if (global->getLoweredType().getAddressType() != Ty) { P.diagnose(IdLoc, diag::sil_value_use_type_mismatch, GlobalName.str(), global->getLoweredType().getSwiftRValueType(), Ty.getSwiftRValueType()); return true; } ResultVal = B.createGlobalAddr(InstLoc, global); break; } case ValueKind::SelectEnumInst: case ValueKind::SelectEnumAddrInst: { if (parseTypedValueRef(Val, B)) return true; SmallVector, 4> CaseValueNames; Optional DefaultValueName; while (P.consumeIf(tok::comma)) { Identifier BBName; SourceLoc BBLoc; // Parse 'default' sil-value. UnresolvedValueName tmp; if (P.consumeIf(tok::kw_default)) { if (parseValueName(tmp)) return true; DefaultValueName = tmp; break; } // Parse 'case' sil-decl-ref ':' sil-value. if (P.consumeIf(tok::kw_case)) { SILDeclRef ElemRef; if (parseSILDeclRef(ElemRef)) return true; assert(ElemRef.hasDecl() && isa(ElemRef.getDecl())); P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":"); parseValueName(tmp); CaseValueNames.push_back(std::make_pair( cast(ElemRef.getDecl()), tmp)); continue; } P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "case or default"); return true; } // Parse the type of the result operands. SILType ResultType; if (P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") || parseSILType(ResultType) || parseSILDebugLocation(InstLoc, B)) return true; // Resolve the results. SmallVector, 4> CaseValues; SILValue DefaultValue; if (DefaultValueName) DefaultValue = getLocalValue(*DefaultValueName, ResultType, InstLoc, B); for (auto &caseName : CaseValueNames) CaseValues.push_back(std::make_pair( caseName.first, getLocalValue(caseName.second, ResultType, InstLoc, B))); if (Opcode == ValueKind::SelectEnumInst) ResultVal = B.createSelectEnum(InstLoc, Val, ResultType, DefaultValue, CaseValues); else ResultVal = B.createSelectEnumAddr(InstLoc, Val, ResultType, DefaultValue, CaseValues); break; } case ValueKind::SwitchEnumInst: case ValueKind::SwitchEnumAddrInst: { if (parseTypedValueRef(Val, B)) return true; SmallVector, 4> CaseBBs; SILBasicBlock *DefaultBB = nullptr; while (!peekSILDebugLocation(P) && P.consumeIf(tok::comma)) { Identifier BBName; SourceLoc BBLoc; // Parse 'default' sil-identifier. if (P.consumeIf(tok::kw_default)) { parseSILIdentifier(BBName, BBLoc, diag::expected_sil_block_name); DefaultBB = getBBForReference(BBName, BBLoc); break; } // Parse 'case' sil-decl-ref ':' sil-identifier. if (P.consumeIf(tok::kw_case)) { SILDeclRef ElemRef; if (parseSILDeclRef(ElemRef)) return true; assert(ElemRef.hasDecl() && isa(ElemRef.getDecl())); P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":"); parseSILIdentifier(BBName, BBLoc, diag::expected_sil_block_name); CaseBBs.push_back( {cast(ElemRef.getDecl()), getBBForReference(BBName, BBLoc)} ); continue; } P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "case or default"); return true; } if (parseSILDebugLocation(InstLoc, B)) return true; if (Opcode == ValueKind::SwitchEnumInst) ResultVal = B.createSwitchEnum(InstLoc, Val, DefaultBB, CaseBBs); else ResultVal = B.createSwitchEnumAddr(InstLoc, Val, DefaultBB, CaseBBs); break; } case ValueKind::SwitchValueInst: { if (parseTypedValueRef(Val, B)) return true; SmallVector, 4> CaseBBs; SILBasicBlock *DefaultBB = nullptr; while (!peekSILDebugLocation(P) && P.consumeIf(tok::comma)) { Identifier BBName; SourceLoc BBLoc; SILValue CaseVal; // Parse 'default' sil-identifier. if (P.consumeIf(tok::kw_default)) { parseSILIdentifier(BBName, BBLoc, diag::expected_sil_block_name); DefaultBB = getBBForReference(BBName, BBLoc); break; } // Parse 'case' value-ref ':' sil-identifier. if (P.consumeIf(tok::kw_case)) { if (parseValueRef(CaseVal, Val->getType(), RegularLocation(P.Tok.getLoc()), B)) { // TODO: Issue a proper error message here P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "reference to a value"); return true; } auto intTy = Val->getType().getAs(); auto functionTy = Val->getType().getAs(); if (!intTy && !functionTy) { P.diagnose(P.Tok, diag::sil_integer_literal_not_integer_type); return true; } if (intTy) { // If it is a switch on an integer type, check that all case values // are integer literals or undef. if (!isa(CaseVal)) { auto *IL = dyn_cast(CaseVal); if (!IL) { P.diagnose(P.Tok, diag::sil_integer_literal_not_integer_type); return true; } APInt CaseValue = IL->getValue(); if (CaseValue.getBitWidth() != intTy->getGreatestWidth()) CaseVal = B.createIntegerLiteral( IL->getLoc(), Val->getType(), CaseValue.zextOrTrunc(intTy->getGreatestWidth())); } } if (functionTy) { // If it is a switch on a function type, check that all case values // are function references or undef. if (!isa(CaseVal)) { auto *FR = dyn_cast(CaseVal); if (!FR) { if (auto *CF = dyn_cast(CaseVal)) { FR = dyn_cast(CF->getOperand()); } } if (!FR) { P.diagnose(P.Tok, diag::sil_integer_literal_not_integer_type); return true; } } } P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":"); parseSILIdentifier(BBName, BBLoc, diag::expected_sil_block_name); CaseBBs.push_back({CaseVal, getBBForReference(BBName, BBLoc)}); continue; } P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "case or default"); return true; } if (parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createSwitchValue(InstLoc, Val, DefaultBB, CaseBBs); break; } case ValueKind::SelectValueInst: { if (parseTypedValueRef(Val, B)) return true; SmallVector, 4> CaseValueAndResultNames; Optional DefaultResultName; while (P.consumeIf(tok::comma)) { Identifier BBName; SourceLoc BBLoc; // Parse 'default' sil-value. UnresolvedValueName tmp; if (P.consumeIf(tok::kw_default)) { if (parseValueName(tmp)) return true; DefaultResultName = tmp; break; } // Parse 'case' sil-decl-ref ':' sil-value. if (P.consumeIf(tok::kw_case)) { UnresolvedValueName casevalue; parseValueName(casevalue); P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":"); parseValueName(tmp); CaseValueAndResultNames.push_back(std::make_pair( casevalue, tmp)); continue; } P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "case or default"); return true; } if (!DefaultResultName) { P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "default"); return true; } // Parse the type of the result operands. SILType ResultType; if (P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") || parseSILType(ResultType) || parseSILDebugLocation(InstLoc, B)) return true; // Resolve the results. SmallVector, 4> CaseValues; SILValue DefaultValue; if (DefaultResultName) DefaultValue = getLocalValue(*DefaultResultName, ResultType, InstLoc, B); SILType ValType = Val->getType(); for (auto &caseName : CaseValueAndResultNames) CaseValues.push_back(std::make_pair( getLocalValue(caseName.first, ValType, InstLoc, B), getLocalValue(caseName.second, ResultType, InstLoc, B))); ResultVal = B.createSelectValue(InstLoc, Val, ResultType, DefaultValue, CaseValues); break; } case ValueKind::DeinitExistentialAddrInst: { if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createDeinitExistentialAddr(InstLoc, Val); break; } case ValueKind::InitExistentialAddrInst: { CanType Ty; SourceLoc TyLoc; if (parseTypedValueRef(Val, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") || parseASTType(Ty, TyLoc) || parseSILDebugLocation(InstLoc, B)) return true; // Lower the type at the abstraction level of the existential. auto archetype = ArchetypeType::getOpened(Val->getType().getSwiftRValueType()) ->getCanonicalType(); SILType LoweredTy = SILMod.Types.getLoweredType( Lowering::AbstractionPattern(archetype), Ty) .getAddressType(); // Collect conformances for the type. ArrayRef conformances = collectExistentialConformances(P, Ty, TyLoc, Val->getType().getSwiftRValueType()); ResultVal = B.createInitExistentialAddr(InstLoc, Val, Ty, LoweredTy, conformances); break; } case ValueKind::AllocExistentialBoxInst: { SILType ExistentialTy; CanType ConcreteFormalTy; SourceLoc TyLoc; if (parseSILType(ExistentialTy) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") || parseASTType(ConcreteFormalTy, TyLoc) || parseSILDebugLocation(InstLoc, B)) return true; // Collect conformances for the type. ArrayRef conformances = collectExistentialConformances(P, ConcreteFormalTy, TyLoc, ExistentialTy.getSwiftRValueType()); ResultVal = B.createAllocExistentialBox(InstLoc, ExistentialTy, ConcreteFormalTy, conformances); break; } case ValueKind::InitExistentialRefInst: { CanType FormalConcreteTy; SILType ExistentialTy; SourceLoc TyLoc; if (parseTypedValueRef(Val, B) || P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") || P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") || parseASTType(FormalConcreteTy, TyLoc) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILType(ExistentialTy) || parseSILDebugLocation(InstLoc, B)) return true; ArrayRef conformances = collectExistentialConformances(P, FormalConcreteTy, TyLoc, ExistentialTy.getSwiftRValueType()); // FIXME: Conformances in InitExistentialRefInst is currently not included // in SIL.rst. ResultVal = B.createInitExistentialRef(InstLoc, ExistentialTy, FormalConcreteTy, Val, conformances); break; } case ValueKind::InitExistentialMetatypeInst: { SourceLoc TyLoc; SILType ExistentialTy; if (parseTypedValueRef(Val, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILType(ExistentialTy, TyLoc) || parseSILDebugLocation(InstLoc, B)) return true; auto baseExType = ExistentialTy.getSwiftRValueType(); auto formalConcreteType = Val->getType().getSwiftRValueType(); while (auto instExType = dyn_cast(baseExType)) { baseExType = instExType.getInstanceType(); formalConcreteType = cast(formalConcreteType).getInstanceType(); } ArrayRef conformances = collectExistentialConformances(P, formalConcreteType, TyLoc, ExistentialTy.getSwiftRValueType()); ResultVal = B.createInitExistentialMetatype(InstLoc, Val, ExistentialTy, conformances); break; } case ValueKind::DynamicMethodBranchInst: { SILDeclRef Member; Identifier BBName, BBName2; SourceLoc NameLoc, NameLoc2; if (parseTypedValueRef(Val, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILDeclRef(Member) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILIdentifier(BBName, NameLoc, diag::expected_sil_block_name) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILIdentifier(BBName2, NameLoc2, diag::expected_sil_block_name) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createDynamicMethodBranch(InstLoc, Val, Member, getBBForReference(BBName, NameLoc), getBBForReference(BBName2, NameLoc2)); break; } case ValueKind::ProjectBlockStorageInst: { if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B)) return true; ResultVal = B.createProjectBlockStorage(InstLoc, Val); break; } case ValueKind::InitBlockStorageHeaderInst: { Identifier invoke, type; SourceLoc invokeLoc, typeLoc; UnresolvedValueName invokeName; SILType invokeTy; GenericEnvironment *invokeGenericEnv; SILType blockType; SmallVector parsedSubs; if (parseTypedValueRef(Val, B) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILIdentifier(invoke, invokeLoc, diag::expected_tok_in_sil_instr, "invoke") || parseValueName(invokeName) || parseSubstitutions(parsedSubs) || P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") || parseSILType(invokeTy, invokeGenericEnv) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseSILIdentifier(type, typeLoc, diag::expected_tok_in_sil_instr, "type") || parseSILType(blockType) || parseSILDebugLocation(InstLoc, B)) return true; if (invoke.str() != "invoke") { P.diagnose(invokeLoc, diag::expected_tok_in_sil_instr, "invoke"); return true; } if (type.str() != "type") { P.diagnose(invokeLoc, diag::expected_tok_in_sil_instr, "type"); return true; } auto invokeVal = getLocalValue(invokeName, invokeTy, InstLoc, B); SmallVector subs; if (!parsedSubs.empty()) { if (!invokeGenericEnv) { P.diagnose(typeLoc, diag::sil_substitutions_on_non_polymorphic_type); return true; } if (getApplySubstitutionsFromParsed(*this, invokeGenericEnv, parsedSubs, subs)) return true; } ResultVal = B.createInitBlockStorageHeader(InstLoc, Val, invokeVal, blockType, subs); break; } } // Store the named value if we had a name. if (ResultNameLoc.isValid()) setLocalValue(ResultVal, ResultName, ResultNameLoc); return false; } bool SILParser::parseCallInstruction(SILLocation InstLoc, ValueKind Opcode, SILBuilder &B, SILInstruction *&ResultVal) { UnresolvedValueName FnName; SmallVector ArgNames; auto PartialApplyConvention = ParameterConvention::Direct_Owned; bool IsNonThrowingApply = false; StringRef AttrName; if (parseSILOptional(AttrName, *this)) { if (AttrName.equals("nothrow")) IsNonThrowingApply = true; else if (AttrName.equals("callee_guaranteed")) PartialApplyConvention = ParameterConvention::Direct_Guaranteed; else return true; } if (parseValueName(FnName)) return true; SmallVector parsedSubs; if (parseSubstitutions(parsedSubs)) return true; if (P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "(")) return true; if (P.Tok.isNot(tok::r_paren)) { do { UnresolvedValueName Arg; if (parseValueName(Arg)) return true; ArgNames.push_back(Arg); } while (P.consumeIf(tok::comma)); } SILType Ty; SourceLoc TypeLoc; GenericEnvironment *GenericEnv = nullptr; if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")") || P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") || parseSILType(Ty, TypeLoc, GenericEnv)) return true; auto FTI = Ty.getAs(); if (!FTI) { P.diagnose(TypeLoc, diag::expected_sil_type_kind, "be a function"); return true; } SmallVector subs; if (!parsedSubs.empty()) { if (!GenericEnv) { P.diagnose(TypeLoc, diag::sil_substitutions_on_non_polymorphic_type); return true; } if (getApplySubstitutionsFromParsed(*this, GenericEnv, parsedSubs, subs)) return true; } SILValue FnVal = getLocalValue(FnName, Ty, InstLoc, B); SILType FnTy = FnVal->getType(); CanSILFunctionType substFTI = FTI; if (!subs.empty()) { auto silFnTy = FnTy.castTo(); substFTI = silFnTy->substGenericArgs(SILMod, subs); FnTy = SILType::getPrimitiveObjectType(substFTI); } SILFunctionConventions substConv(substFTI, B.getModule()); switch (Opcode) { default: llvm_unreachable("Unexpected case"); case ValueKind::ApplyInst : { if (parseSILDebugLocation(InstLoc, B)) return true; if (substConv.getNumSILArguments() != ArgNames.size()) { P.diagnose(TypeLoc, diag::expected_sil_type_kind, "to have the same number of arg names as arg types"); return true; } unsigned ArgNo = 0; SmallVector Args; for (auto &ArgName : ArgNames) { SILType expectedTy = substConv.getSILArgumentType(ArgNo++); Args.push_back(getLocalValue(ArgName, expectedTy, InstLoc, B)); } ResultVal = B.createApply(InstLoc, FnVal, FnTy, substConv.getSILResultType(), subs, Args, IsNonThrowingApply); break; } case ValueKind::PartialApplyInst: { if (parseSILDebugLocation(InstLoc, B)) return true; if (substFTI->getParameters().size() < ArgNames.size()) { P.diagnose(TypeLoc, diag::expected_sil_type_kind, "have the right argument types"); return true; } // Compute the result type of the partial_apply, based on which arguments // are getting applied. SmallVector Args; unsigned ArgNo = substConv.getNumSILArguments() - ArgNames.size(); for (auto &ArgName : ArgNames) { SILType expectedTy = substConv.getSILArgumentType(ArgNo++); Args.push_back(getLocalValue(ArgName, expectedTy, InstLoc, B)); } SILType closureTy = SILBuilder::getPartialApplyResultType(Ty, ArgNames.size(), SILMod, subs, PartialApplyConvention); // FIXME: Why the arbitrary order difference in IRBuilder type argument? ResultVal = B.createPartialApply(InstLoc, FnVal, FnTy, subs, Args, closureTy); break; } case ValueKind::TryApplyInst: { Identifier normalBBName, errorBBName; SourceLoc normalBBLoc, errorBBLoc; if (P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseVerbatim("normal") || parseSILIdentifier(normalBBName, normalBBLoc, diag::expected_sil_block_name) || P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") || parseVerbatim("error") || parseSILIdentifier(errorBBName, errorBBLoc, diag::expected_sil_block_name) || parseSILDebugLocation(InstLoc, B)) return true; if (substConv.getNumSILArguments() != ArgNames.size()) { P.diagnose(TypeLoc, diag::expected_sil_type_kind, "to have the same number of arg names as arg types"); return true; } unsigned argNo = 0; SmallVector args; for (auto &argName : ArgNames) { SILType expectedTy = substConv.getSILArgumentType(argNo++); args.push_back(getLocalValue(argName, expectedTy, InstLoc, B)); } SILBasicBlock *normalBB = getBBForReference(normalBBName, normalBBLoc); SILBasicBlock *errorBB = getBBForReference(errorBBName, errorBBLoc); ResultVal = B.createTryApply(InstLoc, FnVal, FnTy, subs, args, normalBB, errorBB); break; } } return false; } bool SILParser::parseSILFunctionRef(SILLocation InstLoc, SILBuilder &B, SILInstruction *&ResultVal) { Identifier Name; SILType Ty; SourceLoc Loc = P.Tok.getLoc(); if (parseGlobalName(Name) || P.parseToken(tok::colon, diag::expected_sil_colon_value_ref) || parseSILType(Ty) || parseSILDebugLocation(InstLoc, B)) return true; auto FnTy = Ty.getAs(); if (!FnTy || !Ty.isObject()) { P.diagnose(Loc, diag::expected_sil_function_type); return true; } ResultVal = B.createFunctionRef(InstLoc, getGlobalNameForReference(Name, FnTy, Loc)); return false; } /// True if the current token sequence looks like the start of a SIL /// instruction, either: /// %name /// or: /// identifier | keyword /// where identifier is not followed by a '(' or ':', which would indicate /// a basic block. bool SILParser::isStartOfSILInstruction() { if (P.Tok.is(tok::sil_local_name)) return true; if (P.Tok.is(tok::identifier) || P.Tok.isKeyword()) { auto &peek = P.peekToken(); return !peek.is(tok::l_paren) && !peek.is(tok::colon); } return false; } /// sil-basic-block: /// sil-instruction+ /// identifier sil-bb-argument-list? ':' sil-instruction+ /// sil-bb-argument-list: /// '(' sil-typed-valueref (',' sil-typed-valueref)+ ')' bool SILParser::parseSILBasicBlock(SILBuilder &B) { SILBasicBlock *BB; // The basic block name is optional. if (P.Tok.is(tok::sil_local_name)) { BB = getBBForDefinition(Identifier(), SourceLoc()); } else { Identifier BBName; SourceLoc NameLoc; if (parseSILIdentifier(BBName, NameLoc, diag::expected_sil_block_name)) return true; BB = getBBForDefinition(BBName, NameLoc); // For now, since we always assume that PHIArguments have // ValueOwnershipKind::Any, do not parse or do anything special. Eventually // we will parse the convention. bool IsEntry = BB->isEntry(); // If there is a basic block argument list, process it. if (P.consumeIf(tok::l_paren)) { do { SILType Ty; Optional OwnershipKind; SourceLoc NameLoc; StringRef Name = P.Tok.getText(); if (P.parseToken(tok::sil_local_name, NameLoc, diag::expected_sil_value_name) || P.parseToken(tok::colon, diag::expected_sil_colon_value_ref)) return true; // If SILOwnership is enabled and we are not assuming that we are // parsing unqualified SIL, look for printed value ownership kinds. if (!F->getModule() .getOptions() .AssumeUnqualifiedOwnershipWhenParsing && F->getModule().getOptions().EnableSILOwnership && parseSILOwnership(OwnershipKind)) return true; if (parseSILType(Ty)) return true; SILArgument *Arg; if (IsEntry) { Arg = BB->createFunctionArgument(Ty); } else { Arg = BB->createPHIArgument( Ty, OwnershipKind.getValueOr( ValueOwnershipKind(ValueOwnershipKind::Any))); } setLocalValue(Arg, Name, NameLoc); } while (P.consumeIf(tok::comma)); if (P.parseToken(tok::r_paren, diag::sil_basicblock_arg_rparen)) return true; } if (P.parseToken(tok::colon, diag::expected_sil_block_colon)) return true; } // Make sure the block is at the end of the function so that forward // references don't affect block layout. F->getBlocks().remove(BB); F->getBlocks().push_back(BB); bool AssumeUnqualifiedOwnershipWhenParsing = F->getModule().getOptions().AssumeUnqualifiedOwnershipWhenParsing; if (AssumeUnqualifiedOwnershipWhenParsing) { F->setUnqualifiedOwnership(); } do { if (parseSILInstruction(BB, B)) return true; // Evaluate how the just parsed instruction effects this functions Ownership // Qualification. For more details, see the comment on the // FunctionOwnershipEvaluator class. SILInstruction *ParsedInst = &*BB->rbegin(); if (!AssumeUnqualifiedOwnershipWhenParsing && !OwnershipEvaluator.evaluate(ParsedInst)) { P.diagnose(ParsedInst->getLoc().getSourceLoc(), diag::found_unqualified_instruction_in_qualified_function, F->getName()); } } while (isStartOfSILInstruction()); return false; } /// decl-sil: [[only in SIL mode]] /// 'sil' sil-linkage '@' identifier ':' sil-type decl-sil-body? /// decl-sil-body: /// '{' sil-basic-block+ '}' bool Parser::parseDeclSIL() { // Inform the lexer that we're lexing the body of the SIL declaration. Do // this before we consume the 'sil' token so that all later tokens are // properly handled. Lexer::SILBodyRAII Tmp(*L); consumeToken(tok::kw_sil); SILParser FunctionState(*this); Optional FnLinkage; Identifier FnName; SILType FnType; SourceLoc FnNameLoc; Scope S(this, ScopeKind::TopLevel); bool isTransparent = false; bool isFragile = false; IsThunk_t isThunk = IsNotThunk; bool isGlobalInit = false; Inline_t inlineStrategy = InlineDefault; SmallVector Semantics; SmallVector SpecAttrs; ValueDecl *ClangDecl = nullptr; EffectsKind MRK = EffectsKind::Unspecified; if (parseSILLinkage(FnLinkage, *this) || parseDeclSILOptional(&isTransparent, &isFragile, &isThunk, &isGlobalInit, &inlineStrategy, nullptr, &Semantics, &SpecAttrs, &ClangDecl, &MRK, FunctionState) || parseToken(tok::at_sign, diag::expected_sil_function_name) || parseIdentifier(FnName, FnNameLoc, diag::expected_sil_function_name) || parseToken(tok::colon, diag::expected_sil_type)) return true; { // Construct a Scope for the function body so TypeAliasDecl can be added to // the scope. Scope Body(this, ScopeKind::FunctionBody); GenericEnvironment *GenericEnv; if (FunctionState.parseSILType(FnType, GenericEnv, true /*IsFuncDecl*/)) return true; auto SILFnType = FnType.getAs(); if (!SILFnType || !FnType.isObject()) { diagnose(FnNameLoc, diag::expected_sil_function_type); return true; } FunctionState.F = FunctionState.getGlobalNameForDefinition(FnName, SILFnType, FnNameLoc); FunctionState.F->setBare(IsBare); FunctionState.F->setTransparent(IsTransparent_t(isTransparent)); FunctionState.F->setFragile(IsFragile_t(isFragile)); FunctionState.F->setThunk(IsThunk_t(isThunk)); FunctionState.F->setGlobalInit(isGlobalInit); FunctionState.F->setInlineStrategy(inlineStrategy); FunctionState.F->setEffectsKind(MRK); if (ClangDecl) FunctionState.F->setClangNodeOwner(ClangDecl); for (auto &Attr : Semantics) { FunctionState.F->addSemanticsAttr(Attr); } // Now that we have a SILFunction parse the body, if present. bool isDefinition = false; SourceLoc LBraceLoc = Tok.getLoc(); if (consumeIf(tok::l_brace)) { isDefinition = true; FunctionState.GenericEnv = GenericEnv; FunctionState.F->setGenericEnvironment(GenericEnv); if (GenericEnv && !SpecAttrs.empty()) { for (auto &Attr : SpecAttrs) { SmallVector requirements; // Resolve types and convert requirements. FunctionState.convertRequirements(FunctionState.F, Attr.requirements, requirements); FunctionState.F->addSpecializeAttr(SILSpecializeAttr::create( FunctionState.F->getModule(), requirements, Attr.exported, Attr.kind)); } } // Parse the basic block list. FunctionState.OwnershipEvaluator.reset(FunctionState.F); SILOpenedArchetypesTracker OpenedArchetypesTracker(*FunctionState.F); SILBuilder B(*FunctionState.F, /*isParsing*/ true); // Track the archetypes just like SILGen. This // is required for adding typedef operands to instructions. B.setOpenedArchetypesTracker(&OpenedArchetypesTracker); // Define a callback to be invoked on the deserialized types. auto OldParsedTypeCallback = FunctionState.ParsedTypeCallback; SWIFT_DEFER { FunctionState.ParsedTypeCallback = OldParsedTypeCallback; }; FunctionState.ParsedTypeCallback = [&OpenedArchetypesTracker, &FunctionState](Type ty) { OpenedArchetypesTracker.registerUsedOpenedArchetypes(ty); }; do { if (FunctionState.parseSILBasicBlock(B)) return true; } while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)); SourceLoc RBraceLoc; parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace, LBraceLoc); // Check that there are no unresolved forward definitions of opened // archetypes. if (OpenedArchetypesTracker.hasUnresolvedOpenedArchetypeDefinitions()) llvm_unreachable( "All forward definitions of opened archetypes should be resolved"); } FunctionState.F->setLinkage(resolveSILLinkage(FnLinkage, isDefinition)); } if (FunctionState.diagnoseProblems()) return true; // If SIL parsing succeeded, verify the generated SIL. if (!FunctionState.P.Diags.hadAnyError()) FunctionState.F->verify(); // Link the static initializer for global variables. for (SILGlobalVariable &v : FunctionState.SILMod.getSILGlobals()) { if (v.getInitializer()) if (FnName.str() == v.getInitializer()->getName()) v.setInitializer(FunctionState.F); } return false; } /// decl-sil-stage: [[only in SIL mode]] /// 'sil_stage' ('raw' | 'canonical') bool Parser::parseDeclSILStage() { SourceLoc stageLoc = consumeToken(tok::kw_sil_stage); if (!Tok.is(tok::identifier)) { diagnose(Tok, diag::expected_sil_stage_name); return true; } SILStage stage; if (Tok.isContextualKeyword("raw")) { stage = SILStage::Raw; consumeToken(); } else if (Tok.isContextualKeyword("canonical")) { stage = SILStage::Canonical; consumeToken(); } else if (Tok.isContextualKeyword("lowered")) { stage = SILStage::Lowered; consumeToken(); } else { diagnose(Tok, diag::expected_sil_stage_name); consumeToken(); return true; } if (SIL->S->DidParseSILStage) { diagnose(stageLoc, diag::multiple_sil_stage_decls); return false; } SIL->M->setStage(stage); SIL->S->DidParseSILStage = true; return false; } /// decl-sil-global: [[only in SIL mode]] /// 'sil_global' sil-linkage @name : sil-type [external] bool Parser::parseSILGlobal() { consumeToken(tok::kw_sil_global); Optional GlobalLinkage; Identifier GlobalName; SILType GlobalType; SourceLoc NameLoc; bool isFragile = false; bool isLet = false; // Inform the lexer that we're lexing the body of the SIL declaration. Lexer::SILBodyRAII Tmp(*L); Scope S(this, ScopeKind::TopLevel); SILParser State(*this); if (parseSILLinkage(GlobalLinkage, *this) || parseDeclSILOptional(nullptr, &isFragile, nullptr, nullptr, nullptr, &isLet, nullptr, nullptr, nullptr, nullptr, State) || parseToken(tok::at_sign, diag::expected_sil_value_name) || parseIdentifier(GlobalName, NameLoc, diag::expected_sil_value_name) || parseToken(tok::colon, diag::expected_sil_type)) return true; if (State.parseSILType(GlobalType)) return true; // Non-external global variables are definitions by default. if (!GlobalLinkage.hasValue()) GlobalLinkage = SILLinkage::DefaultForDefinition; // FIXME: check for existing global variable? auto *GV = SILGlobalVariable::create(*SIL->M, GlobalLinkage.getValue(), (IsFragile_t)isFragile, GlobalName.str(),GlobalType, RegularLocation(NameLoc)); GV->setLet(isLet); // Parse static initializer if exists. if (State.P.consumeIf(tok::comma)) { Identifier Name; SILType Ty; SourceLoc Loc = State.P.Tok.getLoc(); if (State.parseGlobalName(Name) || State.P.parseToken(tok::colon, diag::expected_sil_colon_value_ref) || State.parseSILType(Ty)) return true; auto FnTy = Ty.getAs(); if (!FnTy || !Ty.isObject()) { State.P.diagnose(Loc, diag::expected_sil_function_type); return true; } GV->setInitializer(State.getGlobalNameForReference(Name, FnTy, Loc)); } return false; } /// decl-sil-vtable: [[only in SIL mode]] /// 'sil_vtable' ClassName decl-sil-vtable-body /// decl-sil-vtable-body: /// '{' sil-vtable-entry* '}' /// sil-vtable-entry: /// SILDeclRef ':' SILFunctionName bool Parser::parseSILVTable() { consumeToken(tok::kw_sil_vtable); SILParser VTableState(*this); // Parse the class name. Identifier Name; SourceLoc Loc; if (VTableState.parseSILIdentifier(Name, Loc, diag::expected_sil_value_name)) return true; // Find the class decl. llvm::PointerUnion Res = lookupTopDecl(*this, Name); assert(Res.is() && "Class look-up should return a Decl"); ValueDecl *VD = Res.get(); if (!VD) { diagnose(Loc, diag::sil_vtable_class_not_found, Name); return true; } ClassDecl *theClass = dyn_cast(VD); if (!theClass) { diagnose(Loc, diag::sil_vtable_class_not_found, Name); return true; } SourceLoc LBraceLoc = Tok.getLoc(); consumeToken(tok::l_brace); // We need to turn on InSILBody to parse SILDeclRef. Lexer::SILBodyRAII Tmp(*L); Scope S(this, ScopeKind::TopLevel); // Parse the entry list. std::vector vtableEntries; if (Tok.isNot(tok::r_brace)) { do { SILDeclRef Ref; Identifier FuncName; SourceLoc FuncLoc; if (VTableState.parseSILDeclRef(Ref, true)) return true; SILFunction *Func = nullptr; Optional Linkage = SILLinkage::Private; if (Tok.is(tok::kw_nil)) { consumeToken(); } else { if (parseToken(tok::colon, diag::expected_sil_vtable_colon) || parseSILLinkage(Linkage, *this) || VTableState.parseSILIdentifier(FuncName, FuncLoc, diag::expected_sil_value_name)) return true; Func = SIL->M->lookUpFunction(FuncName.str()); if (!Func) { diagnose(FuncLoc, diag::sil_vtable_func_not_found, FuncName); return true; } if (!Linkage) Linkage = stripExternalFromLinkage(Func->getLinkage()); } vtableEntries.emplace_back(Ref, Func, Linkage.getValue()); } while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)); } SourceLoc RBraceLoc; parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace, LBraceLoc); SILVTable::create(*SIL->M, theClass, vtableEntries); return false; } static ProtocolDecl *parseProtocolDecl(Parser &P, SILParser &SP) { Identifier DeclName; SourceLoc DeclLoc; if (SP.parseSILIdentifier(DeclName, DeclLoc, diag::expected_sil_value_name)) return nullptr; // Find the protocol decl. The protocol can be imported. llvm::PointerUnion Res = lookupTopDecl(P, DeclName); assert(Res.is() && "Protocol look-up should return a Decl"); ValueDecl *VD = Res.get(); if (!VD) { P.diagnose(DeclLoc, diag::sil_witness_protocol_not_found, DeclName); return nullptr; } ProtocolDecl *proto = dyn_cast(VD); if (!proto) P.diagnose(DeclLoc, diag::sil_witness_protocol_not_found, DeclName); return proto; } static AssociatedTypeDecl *parseAssociatedTypeDecl(Parser &P, SILParser &SP, ProtocolDecl *proto) { Identifier DeclName; SourceLoc DeclLoc; if (SP.parseSILIdentifier(DeclName, DeclLoc, diag::expected_sil_value_name)) return nullptr; // We can return multiple decls, for now, we use the first lookup result. // One example is two decls when searching for Generator of Sequence: // one from Sequence, the other from _Sequence_Type. SmallVector values; auto VD = lookupMember(P, proto->getInterfaceType(), DeclName, DeclLoc, values, true/*ExpectMultipleResults*/); if (!VD) { P.diagnose(DeclLoc, diag::sil_witness_assoc_not_found, DeclName); return nullptr; } return dyn_cast(VD); } static NormalProtocolConformance *parseNormalProtocolConformance(Parser &P, SILParser &SP, Type ConformingTy, ProtocolDecl *&proto) { Identifier ModuleKeyword, ModuleName; SourceLoc Loc, KeywordLoc; proto = parseProtocolDecl(P, SP); if (!proto) return nullptr; if (P.parseIdentifier(ModuleKeyword, KeywordLoc, diag::expected_tok_in_sil_instr, "module") || SP.parseSILIdentifier(ModuleName, Loc, diag::expected_sil_value_name)) return nullptr; if (ModuleKeyword.str() != "module") { P.diagnose(KeywordLoc, diag::expected_tok_in_sil_instr, "module"); return nullptr; } // FIXME: we currently emit _CocoaArrayType: _CocoaArrayType. if (ConformingTy->is() && ConformingTy->getAs()->getDecl() == proto) return nullptr; // Calling lookupConformance on a BoundGenericType will return a specialized // conformance. We use UnboundGenericType to find the normal conformance. Type lookupTy = ConformingTy; if (auto bound = lookupTy->getAs()) lookupTy = bound->getDecl()->getDeclaredType(); auto lookup = P.SF.getParentModule()->lookupConformance( lookupTy, proto, nullptr); if (!lookup) { P.diagnose(KeywordLoc, diag::sil_witness_protocol_conformance_not_found); return nullptr; } if (!lookup->isConcrete()) { P.diagnose(KeywordLoc, diag::sil_witness_protocol_conformance_not_found); return nullptr; } return lookup->getConcrete()->getRootNormalConformance(); } /// protocol-conformance ::= normal-protocol-conformance /// protocol-conformance ::= /// generic-parameter-list? type: 'inherit' '(' protocol-conformance ')' /// protocol-conformance ::= /// generic-parameter-list? type: 'specialize' '<' substitution* '>' /// '(' protocol-conformance ')' /// normal-protocol-conformance ::= /// generic-parameter-list? type: protocolName module ModuleName /// Note that generic-parameter-list is already parsed before calling this. ProtocolConformance *SILParser::parseProtocolConformance( ProtocolDecl *&proto, GenericEnvironment *&genericEnv, bool localScope) { // Parse generic params for the protocol conformance. We need to make sure // they have the right scope. Optional GenericsScope; if (localScope) GenericsScope.emplace(&P, ScopeKind::Generics); // Make sure we don't leave it uninitialized in the caller genericEnv = nullptr; auto *genericParams = P.maybeParseGenericParams().getPtrOrNull(); if (genericParams) { genericEnv = handleSILGenericParams(P.Context, genericParams, &P.SF); } ProtocolConformance *retVal = parseProtocolConformanceHelper(proto, genericEnv, localScope); if (localScope) { GenericsScope.reset(); } return retVal; } ProtocolConformance *SILParser::parseProtocolConformanceHelper( ProtocolDecl *&proto, GenericEnvironment *witnessEnv, bool localScope) { // Parse AST type. ParserResult TyR = P.parseType(); if (TyR.isNull()) return nullptr; TypeLoc Ty = TyR.get(); if (performTypeLocChecking(Ty, /*IsSILType=*/ false, witnessEnv)) return nullptr; auto ConformingTy = Ty.getType(); if (P.parseToken(tok::colon, diag::expected_sil_witness_colon)) return nullptr; if (P.Tok.is(tok::identifier) && P.Tok.getText() == "specialize") { P.consumeToken(); // Parse substitutions for specialized conformance. SmallVector parsedSubs; if (parseSubstitutions(parsedSubs, witnessEnv)) return nullptr; if (P.parseToken(tok::l_paren, diag::expected_sil_witness_lparen)) return nullptr; ProtocolDecl *dummy; GenericEnvironment *specializedEnv; auto genericConform = parseProtocolConformance(dummy, specializedEnv, localScope); if (!genericConform) return nullptr; if (P.parseToken(tok::r_paren, diag::expected_sil_witness_rparen)) return nullptr; SmallVector subs; if (getApplySubstitutionsFromParsed(*this, specializedEnv, parsedSubs, subs)) return nullptr; auto result = P.Context.getSpecializedConformance( ConformingTy, genericConform, subs); return result; } if (P.Tok.is(tok::identifier) && P.Tok.getText() == "inherit") { P.consumeToken(); if (P.parseToken(tok::l_paren, diag::expected_sil_witness_lparen)) return nullptr; auto baseConform = parseProtocolConformance(); if (!baseConform) return nullptr; if (P.parseToken(tok::r_paren, diag::expected_sil_witness_rparen)) return nullptr; return P.Context.getInheritedConformance(ConformingTy, baseConform); } auto retVal = parseNormalProtocolConformance(P, *this, ConformingTy, proto); return retVal; } /// decl-sil-witness ::= 'sil_witness_table' sil-linkage? /// normal-protocol-conformance decl-sil-witness-body /// normal-protocol-conformance ::= /// generic-parameter-list? type: protocolName module ModuleName /// decl-sil-witness-body: /// '{' sil-witness-entry* '}' /// sil-witness-entry: /// method SILDeclRef ':' @SILFunctionName /// associated_type AssociatedTypeDeclName: Type /// associated_type_protocol (AssocName: ProtocolName): /// protocol-conformance|dependent /// base_protocol ProtocolName: protocol-conformance bool Parser::parseSILWitnessTable() { consumeToken(tok::kw_sil_witness_table); SILParser WitnessState(*this); // Parse the linkage. Optional Linkage; parseSILLinkage(Linkage, *this); bool isFragile = false; if (parseDeclSILOptional(nullptr, &isFragile, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, WitnessState)) return true; Scope S(this, ScopeKind::TopLevel); // We should use WitnessTableBody. This ensures that the generic params // are visible. Optional BodyScope; BodyScope.emplace(this, ScopeKind::FunctionBody); // Parse the protocol conformance. ProtocolDecl *proto; GenericEnvironment *witnessEnv; auto conf = WitnessState.parseProtocolConformance(proto, witnessEnv, false/*localScope*/); WitnessState.GenericEnv = witnessEnv; NormalProtocolConformance *theConformance = conf ? dyn_cast(conf) : nullptr; SILWitnessTable *wt = nullptr; if (theConformance) { wt = SIL->M->lookUpWitnessTable(theConformance, false); assert((!wt || wt->isDeclaration()) && "Attempting to create duplicate witness table."); } // If we don't have an lbrace, then this witness table is a declaration. if (Tok.getKind() != tok::l_brace) { // Default to public external linkage. if (!Linkage) Linkage = SILLinkage::PublicExternal; // We ignore empty witness table without normal protocol conformance. if (!wt && theConformance) wt = SILWitnessTable::create(*SIL->M, *Linkage, theConformance); BodyScope.reset(); return false; } if (!theConformance) { diagnose(Tok, diag::sil_witness_protocol_conformance_not_found); return true; } SourceLoc LBraceLoc = Tok.getLoc(); consumeToken(tok::l_brace); // We need to turn on InSILBody to parse SILDeclRef. Lexer::SILBodyRAII Tmp(*L); // Parse the entry list. std::vector witnessEntries; if (Tok.isNot(tok::r_brace)) { do { Identifier EntryKeyword; SourceLoc KeywordLoc; if (parseIdentifier(EntryKeyword, KeywordLoc, diag::expected_tok_in_sil_instr, "method, associated_type, associated_type_protocol, base_protocol")) return true; if (EntryKeyword.str() == "base_protocol") { ProtocolDecl *proto = parseProtocolDecl(*this, WitnessState); if (!proto) return true; if (parseToken(tok::colon, diag::expected_sil_witness_colon)) return true; ProtocolConformance *conform = WitnessState.parseProtocolConformance(); if (!conform) // Ignore this witness entry for now. continue; witnessEntries.push_back(SILWitnessTable::BaseProtocolWitness{ proto, conform }); continue; } if (EntryKeyword.str() == "associated_type_protocol") { if (parseToken(tok::l_paren, diag::expected_sil_witness_lparen)) return true; AssociatedTypeDecl *assoc = parseAssociatedTypeDecl(*this, WitnessState, proto); if (!assoc) return true; if (parseToken(tok::colon, diag::expected_sil_witness_colon)) return true; ProtocolDecl *proto = parseProtocolDecl(*this, WitnessState); if (!proto) return true; if (parseToken(tok::r_paren, diag::expected_sil_witness_rparen) || parseToken(tok::colon, diag::expected_sil_witness_colon)) return true; ProtocolConformanceRef conformance(proto); if (Tok.getText() != "dependent") { auto concrete = WitnessState.parseProtocolConformance(); if (!concrete) // Ignore this witness entry for now. continue; conformance = ProtocolConformanceRef(concrete); } else { consumeToken(); } witnessEntries.push_back(SILWitnessTable::AssociatedTypeProtocolWitness{ assoc, proto, ProtocolConformanceRef(conformance) }); continue; } if (EntryKeyword.str() == "associated_type") { AssociatedTypeDecl *assoc = parseAssociatedTypeDecl(*this, WitnessState, proto); if (!assoc) return true; if (parseToken(tok::colon, diag::expected_sil_witness_colon)) return true; // Parse AST type. ParserResult TyR = parseType(); if (TyR.isNull()) return true; TypeLoc Ty = TyR.get(); if (swift::performTypeLocChecking(Context, Ty, /*isSILMode=*/false, /*isSILType=*/false, witnessEnv, &SF)) return true; witnessEntries.push_back(SILWitnessTable::AssociatedTypeWitness{ assoc, Ty.getType()->getCanonicalType() }); continue; } if (EntryKeyword.str() != "method") { diagnose(KeywordLoc, diag::expected_tok_in_sil_instr, "method"); return true; } SILDeclRef Ref; Identifier FuncName; SourceLoc FuncLoc; if (WitnessState.parseSILDeclRef(Ref, true) || parseToken(tok::colon, diag::expected_sil_witness_colon)) return true; SILFunction *Func = nullptr; if (Tok.is(tok::kw_nil)) { consumeToken(); } else { if (parseToken(tok::at_sign, diag::expected_sil_function_name) || WitnessState.parseSILIdentifier(FuncName, FuncLoc, diag::expected_sil_value_name)) return true; Func = SIL->M->lookUpFunction(FuncName.str()); if (!Func) { diagnose(FuncLoc, diag::sil_witness_func_not_found, FuncName); return true; } } witnessEntries.push_back(SILWitnessTable::MethodWitness{ Ref, Func }); } while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)); } SourceLoc RBraceLoc; parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace, LBraceLoc); // Default to public linkage. if (!Linkage) Linkage = SILLinkage::Public; if (!wt) wt = SILWitnessTable::create(*SIL->M, *Linkage, theConformance); wt->convertToDefinition(witnessEntries, isFragile); BodyScope.reset(); return false; } /// decl-sil-default-witness ::= 'sil_default_witness_table' /// sil-linkage identifier /// decl-sil-default-witness-body /// decl-sil-default-witness-body: /// '{' sil-default-witness-entry* '}' /// sil-default-witness-entry: /// 'method' SILDeclRef ':' @SILFunctionName /// 'no_default' bool Parser::parseSILDefaultWitnessTable() { consumeToken(tok::kw_sil_default_witness_table); SILParser WitnessState(*this); // Parse the linkage. Optional Linkage; parseSILLinkage(Linkage, *this); Scope S(this, ScopeKind::TopLevel); // We should use WitnessTableBody. This ensures that the generic params // are visible. Optional BodyScope; BodyScope.emplace(this, ScopeKind::FunctionBody); // Parse the protocol. ProtocolDecl *protocol = parseProtocolDecl(*this, WitnessState); // Parse the body. SourceLoc LBraceLoc = Tok.getLoc(); consumeToken(tok::l_brace); // We need to turn on InSILBody to parse SILDeclRef. Lexer::SILBodyRAII Tmp(*L); // Parse the entry list. std::vector witnessEntries; if (Tok.isNot(tok::r_brace)) { do { Identifier EntryKeyword; SourceLoc KeywordLoc; if (parseIdentifier(EntryKeyword, KeywordLoc, diag::expected_tok_in_sil_instr, "method, no_default")) return true; if (EntryKeyword.str() == "no_default") { witnessEntries.push_back(SILDefaultWitnessTable::Entry()); continue; } if (EntryKeyword.str() != "method") { diagnose(KeywordLoc, diag::expected_tok_in_sil_instr, "method"); return true; } SILDeclRef Ref; Identifier FuncName; SourceLoc FuncLoc; if (WitnessState.parseSILDeclRef(Ref, true) || parseToken(tok::colon, diag::expected_sil_witness_colon)) return true; if (parseToken(tok::at_sign, diag::expected_sil_function_name) || WitnessState.parseSILIdentifier(FuncName, FuncLoc, diag::expected_sil_value_name)) return true; SILFunction *Func = SIL->M->lookUpFunction(FuncName.str()); if (!Func) { diagnose(FuncLoc, diag::sil_witness_func_not_found, FuncName); return true; } witnessEntries.push_back(SILDefaultWitnessTable::Entry{ Ref, Func }); } while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)); } SourceLoc RBraceLoc; parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace, LBraceLoc); // Default to public linkage. if (!Linkage) Linkage = SILLinkage::Public; SILDefaultWitnessTable::create(*SIL->M, *Linkage, protocol, witnessEntries); BodyScope.reset(); return false; } llvm::Optional SILParser::parseSILCoverageExpr( llvm::coverage::CounterExpressionBuilder &Builder) { if (P.Tok.is(tok::integer_literal)) { unsigned CounterId; if (parseInteger(CounterId, diag::sil_coverage_invalid_counter)) return None; return llvm::coverage::Counter::getCounter(CounterId); } if (P.Tok.is(tok::identifier)) { Identifier Zero; SourceLoc Loc; if (parseSILIdentifier(Zero, Loc, diag::sil_coverage_invalid_counter)) return None; if (Zero.str() != "zero") { P.diagnose(Loc, diag::sil_coverage_invalid_counter); return None; } return llvm::coverage::Counter::getZero(); } if (P.Tok.is(tok::l_paren)) { P.consumeToken(tok::l_paren); auto LHS = parseSILCoverageExpr(Builder); if (!LHS) return None; Identifier Operator; SourceLoc Loc; if (P.parseAnyIdentifier(Operator, Loc, diag::sil_coverage_invalid_operator)) return None; if (Operator.str() != "+" && Operator.str() != "-") { P.diagnose(Loc, diag::sil_coverage_invalid_operator); return None; } auto RHS = parseSILCoverageExpr(Builder); if (!RHS) return None; if (P.parseToken(tok::r_paren, diag::sil_coverage_expected_rparen)) return None; if (Operator.str() == "+") return Builder.add(*LHS, *RHS); return Builder.subtract(*LHS, *RHS); } P.diagnose(P.Tok, diag::sil_coverage_invalid_counter); return None; } /// decl-sil-coverage-map ::= 'sil_coverage_map' CoveredName CoverageHash /// decl-sil-coverage-body /// decl-sil-coverage-body: /// '{' sil-coverage-entry* '}' /// sil-coverage-entry: /// sil-coverage-loc ':' sil-coverage-expr /// sil-coverage-loc: /// StartLine ':' StartCol '->' EndLine ':' EndCol /// sil-coverage-expr: /// ... bool Parser::parseSILCoverageMap() { consumeToken(tok::kw_sil_coverage_map); SILParser State(*this); // Parse the filename. Identifier Filename; SourceLoc FileLoc; if (State.parseSILIdentifier(Filename, FileLoc, diag::expected_sil_value_name)) return true; // Parse the covered name. Identifier FuncName; SourceLoc FuncLoc; if (State.parseSILIdentifier(FuncName, FuncLoc, diag::expected_sil_value_name)) return true; SILFunction *Func = SIL->M->lookUpFunction(FuncName.str()); if (!Func) { diagnose(FuncLoc, diag::sil_coverage_func_not_found, FuncName); return true; } uint64_t Hash; if (State.parseInteger(Hash, diag::sil_coverage_invalid_hash)) return true; if (!Tok.is(tok::l_brace)) { diagnose(Tok, diag::sil_coverage_expected_lbrace); return true; } SourceLoc LBraceLoc = Tok.getLoc(); consumeToken(tok::l_brace); llvm::coverage::CounterExpressionBuilder Builder; std::vector Regions; bool BodyHasError = false; if (Tok.isNot(tok::r_brace)) { do { unsigned StartLine, StartCol, EndLine, EndCol; if (State.parseInteger(StartLine, diag::sil_coverage_expected_loc) || parseToken(tok::colon, diag::sil_coverage_expected_loc) || State.parseInteger(StartCol, diag::sil_coverage_expected_loc) || parseToken(tok::arrow, diag::sil_coverage_expected_arrow) || State.parseInteger(EndLine, diag::sil_coverage_expected_loc) || parseToken(tok::colon, diag::sil_coverage_expected_loc) || State.parseInteger(EndCol, diag::sil_coverage_expected_loc)) { BodyHasError = true; break; } if (parseToken(tok::colon, diag::sil_coverage_expected_colon)) { BodyHasError = true; break; } auto Counter = State.parseSILCoverageExpr(Builder); if (!Counter) { BodyHasError = true; break; } Regions.emplace_back(StartLine, StartCol, EndLine, EndCol, *Counter); } while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)); } if (BodyHasError) skipUntilDeclRBrace(); SourceLoc RBraceLoc; parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace, LBraceLoc); if (!BodyHasError) SILCoverageMap::create(*SIL->M, Filename.str(), FuncName.str(), Func->isPossiblyUsedExternally(), Hash, Regions, Builder.getExpressions()); return false; } /// sil-scope-ref ::= 'scope' [0-9]+ /// sil-scope ::= 'sil_scope' [0-9]+ '{' /// debug-loc /// 'parent' scope-parent /// ('inlined_at' sil-scope-ref)? /// '}' /// scope-parent ::= sil-function-name ':' sil-type /// scope-parent ::= sil-scope-ref /// debug-loc ::= 'loc' string-literal ':' [0-9]+ ':' [0-9]+ bool Parser::parseSILScope() { consumeToken(tok::kw_sil_scope); SILParser ScopeState(*this); SourceLoc SlotLoc = Tok.getLoc(); unsigned Slot; if (ScopeState.parseInteger(Slot, diag::sil_invalid_scope_slot)) return true; SourceLoc LBraceLoc = Tok.getLoc(); consumeToken(tok::l_brace); StringRef Key = Tok.getText(); RegularLocation Loc{SILLocation::DebugLoc()}; if (Key == "loc") if (ScopeState.parseSILLocation(Loc)) return true; ScopeState.parseVerbatim("parent"); Identifier FnName; SILDebugScope *Parent = nullptr; SILFunction *ParentFn = nullptr; if (Tok.is(tok::integer_literal)) { /// scope-parent ::= sil-scope-ref if (ScopeState.parseScopeRef(Parent)) return true; } else { /// scope-parent ::= sil-function-name SILType Ty; SourceLoc FnLoc = Tok.getLoc(); // We need to turn on InSILBody to parse the function reference. Lexer::SILBodyRAII Tmp(*L); GenericEnvironment *IgnoredEnv; Scope S(this, ScopeKind::TopLevel); Scope Body(this, ScopeKind::FunctionBody); if ((ScopeState.parseGlobalName(FnName)) || parseToken(tok::colon, diag::expected_sil_colon_value_ref) || ScopeState.parseSILType(Ty, IgnoredEnv, true)) return true; // The function doesn't exist yet. Create a zombie forward declaration. auto FnTy = Ty.getAs(); if (!FnTy || !Ty.isObject()) { diagnose(FnLoc, diag::expected_sil_function_type); return true; } ParentFn = ScopeState.getGlobalNameForReference(FnName, FnTy, FnLoc, true); ScopeState.TUState.PotentialZombieFns.insert(ParentFn); } SILDebugScope *InlinedAt = nullptr; if (Tok.getText() == "inlined_at") { consumeToken(); if (ScopeState.parseScopeRef(InlinedAt)) return true; } SourceLoc RBraceLoc; parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace, LBraceLoc); auto &Scope = SIL->S->ScopeSlots[Slot]; if (Scope) { diagnose(SlotLoc, diag::sil_scope_redefined, Slot); return true; } Scope = new (*SIL->M) SILDebugScope(Loc, ParentFn, Parent, InlinedAt); return false; }