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