blob: 133295dd1861ea65685ae4bc940a63fe0a190c43 [file] [log] [blame]
//===--- ParseSIL.cpp - SIL File Parsing logic ----------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "SILParserFunctionBuilder.h"
#include "SILParserState.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/NameLookupRequests.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/SILGenRequests.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/Defer.h"
#include "swift/Demangling/Demangle.h"
#include "swift/Parse/Lexer.h"
#include "swift/Parse/ParseSILSupport.h"
#include "swift/Parse/Parser.h"
#include "swift/SIL/AbstractionPattern.h"
#include "swift/SIL/InstructionUtils.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILDebugScope.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILUndef.h"
#include "swift/SIL/TypeLowering.h"
#include "swift/Subsystems.h"
#include "swift/Syntax/SyntaxKind.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace swift;
using namespace swift::syntax;
//===----------------------------------------------------------------------===//
// SILParserState implementation
//===----------------------------------------------------------------------===//
SILParserState::~SILParserState() {
if (!ForwardRefFns.empty()) {
for (auto Entry : ForwardRefFns) {
if (Entry.second.Loc.isValid()) {
M.getASTContext().Diags.diagnose(Entry.second.Loc,
diag::sil_use_of_undefined_value,
Entry.first.str());
}
}
}
// Turn any debug-info-only function declarations into zombies.
for (auto *Fn : PotentialZombieFns)
if (Fn->isExternalDeclaration()) {
Fn->setInlined();
M.eraseFunction(Fn);
}
}
std::unique_ptr<SILModule>
ParseSILModuleRequest::evaluate(Evaluator &evaluator,
ASTLoweringDescriptor desc) const {
auto *SF = desc.getSourceFileToParse();
assert(SF);
auto bufferID = SF->getBufferID();
assert(bufferID);
auto silMod = SILModule::createEmptyModule(desc.context, desc.conv,
desc.opts);
SILParserState parserState(*silMod.get());
Parser parser(*bufferID, *SF, &parserState);
PrettyStackTraceParser StackTrace(parser);
auto hadError = parser.parseTopLevelSIL();
if (hadError) {
// The rest of the SIL pipeline expects well-formed SIL, so if we encounter
// a parsing error, just return an empty SIL module.
//
// Because the SIL parser's notion of failing with an error is distinct from
// the ASTContext's notion of having emitted a diagnostic, it's possible for
// the parser to fail silently without emitting a diagnostic. This assertion
// ensures that +asserts builds will fail fast. If you crash here, please go
// back and add a diagnostic after identifying where the SIL parser failed.
assert(SF->getASTContext().hadError() &&
"Failed to parse SIL but did not emit any errors!");
return SILModule::createEmptyModule(desc.context, desc.conv, desc.opts);
}
return silMod;
}
//===----------------------------------------------------------------------===//
// SILParser
//===----------------------------------------------------------------------===//
namespace {
struct ParsedSubstitution {
SourceLoc loc;
Type replacement;
};
struct ParsedSpecAttr {
ArrayRef<RequirementRepr> requirements;
bool exported;
SILSpecializeAttr::SpecializationKind kind;
SILFunction *target = nullptr;
Identifier spiGroupID;
ModuleDecl *spiModule;
};
class SILParser {
friend SILParserState;
public:
Parser &P;
SILModule &SILMod;
SILParserState &TUState;
SILFunction *F = nullptr;
GenericEnvironment *ContextGenericEnv = nullptr;
GenericParamList *ContextGenericParams = nullptr;
private:
/// HadError - Have we seen an error parsing this function?
bool HadError = false;
/// Data structures used to perform name lookup of basic blocks.
llvm::DenseMap<Identifier, SILBasicBlock*> BlocksByName;
llvm::DenseMap<SILBasicBlock*,
Located<Identifier>> UndefinedBlocks;
/// Data structures used to perform name lookup for local values.
llvm::StringMap<ValueBase*> LocalValues;
llvm::StringMap<SourceLoc> ForwardRefLocalValues;
/// A callback to be invoked every time a type was deserialized.
std::function<void(Type)> ParsedTypeCallback;
Type performTypeResolution(TypeRepr *TyR, bool IsSILType,
GenericEnvironment *GenericEnv,
GenericParamList *GenericParams);
void convertRequirements(ArrayRef<RequirementRepr> From,
SmallVectorImpl<Requirement> &To);
ProtocolConformanceRef parseProtocolConformanceHelper(
ProtocolDecl *&proto,
GenericEnvironment *GenericEnv,
GenericParamList *WitnessParams);
public:
SILParser(Parser &P)
: P(P), SILMod(static_cast<SILParserState *>(P.SIL)->M),
TUState(*static_cast<SILParserState *>(P.SIL)),
ParsedTypeCallback([](Type ty) {}) {}
~SILParser();
/// diagnoseProblems - After a function is fully parse, emit any diagnostics
/// for errors and return true if there were any.
bool diagnoseProblems();
/// getGlobalNameForReference - Given a reference to a global name, look it
/// up and return an appropriate SIL function.
SILFunction *getGlobalNameForReference(Identifier Name,
CanSILFunctionType Ty,
SourceLoc Loc,
bool IgnoreFwdRef = false);
/// getGlobalNameForDefinition - Given a definition of a global name, look
/// it up and return an appropriate SIL function.
SILFunction *getGlobalNameForDefinition(Identifier Name,
CanSILFunctionType Ty,
SourceLoc Loc);
/// getBBForDefinition - Return the SILBasicBlock for a definition of the
/// specified block.
SILBasicBlock *getBBForDefinition(Identifier Name, SourceLoc Loc);
/// getBBForReference - return the SILBasicBlock of the specified name. The
/// source location is used to diagnose a failure if the block ends up never
/// being defined.
SILBasicBlock *getBBForReference(Identifier Name, SourceLoc Loc);
struct UnresolvedValueName {
StringRef Name;
SourceLoc NameLoc;
bool isUndef() const { return Name == "undef"; }
};
/// getLocalValue - Get a reference to a local value with the specified name
/// and type.
SILValue getLocalValue(UnresolvedValueName Name, SILType Type,
SILLocation L, SILBuilder &B);
/// setLocalValue - When an instruction or block argument is defined, this
/// method is used to register it and update our symbol table.
void setLocalValue(ValueBase *Value, StringRef Name, SourceLoc NameLoc);
SILDebugLocation getDebugLoc(SILBuilder & B, SILLocation Loc) {
return SILDebugLocation(Loc, F->getDebugScope());
}
/// @{ Primitive parsing.
/// \verbatim
/// sil-identifier ::= [A-Za-z_0-9]+
/// \endverbatim
bool parseSILIdentifier(Identifier &Result, SourceLoc &Loc,
const Diagnostic &D);
template<typename ...DiagArgTypes, typename ...ArgTypes>
bool parseSILIdentifier(Identifier &Result, Diag<DiagArgTypes...> ID,
ArgTypes... Args) {
SourceLoc L;
return parseSILIdentifier(Result, L, Diagnostic(ID, Args...));
}
template <typename T, typename... DiagArgTypes, typename... ArgTypes>
bool parseSILIdentifierSwitch(T &Result, ArrayRef<StringRef> Strings,
Diag<DiagArgTypes...> 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<typename ...DiagArgTypes, typename ...ArgTypes>
bool parseSILIdentifier(Identifier &Result, SourceLoc &L,
Diag<DiagArgTypes...> ID, ArgTypes... Args) {
return parseSILIdentifier(Result, L, Diagnostic(ID, Args...));
}
bool parseVerbatim(StringRef identifier);
template <typename T>
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 <typename T>
bool parseIntegerLiteral(StringRef text, unsigned radix, T &result) {
text = prepareIntegerLiteralForParsing(text);
return text.getAsInteger(radix, result);
}
StringRef prepareIntegerLiteralForParsing(StringRef text) {
// tok::integer_literal can contain characters that the library
// parsing routines don't expect.
if (text.contains('_'))
text = P.copyAndStripUnderscores(text);
return text;
}
/// @}
/// @{ Type parsing.
bool parseASTType(CanType &result,
GenericEnvironment *genericEnv=nullptr,
GenericParamList *genericParams=nullptr);
bool parseASTType(CanType &result,
SourceLoc &TypeLoc,
GenericEnvironment *genericEnv=nullptr,
GenericParamList *genericParams=nullptr) {
TypeLoc = P.Tok.getLoc();
return parseASTType(result, genericEnv, genericParams);
}
bool parseSILOwnership(ValueOwnershipKind &OwnershipKind) {
// We parse here @ <identifier>.
if (!P.consumeIf(tok::at_sign)) {
// If we fail, we must have @any ownership. We check elsewhere in the
// parser that this matches what the function signature wants.
OwnershipKind = OwnershipKind::None;
return false;
}
StringRef AllOwnershipKinds[3] = {"unowned", "owned",
"guaranteed"};
return parseSILIdentifierSwitch(OwnershipKind, AllOwnershipKinds,
diag::expected_sil_value_ownership_kind);
}
void bindSILGenericParams(TypeRepr *TyR);
bool parseSILType(SILType &Result,
GenericEnvironment *&parsedGenericEnv,
GenericParamList *&parsedGenericParams,
bool IsFuncDecl=false,
GenericEnvironment *parentGenericEnv=nullptr,
GenericParamList *parentGenericParams=nullptr);
bool parseSILType(SILType &Result) {
GenericEnvironment *IgnoredEnv = nullptr;
GenericParamList *IgnoredParams = nullptr;
return parseSILType(Result, IgnoredEnv, IgnoredParams);
}
bool parseSILType(SILType &Result, SourceLoc &TypeLoc) {
TypeLoc = P.Tok.getLoc();
return parseSILType(Result);
}
bool parseSILType(SILType &Result, SourceLoc &TypeLoc,
GenericEnvironment *&parsedGenericEnv,
GenericParamList *&parsedGenericParams,
GenericEnvironment *parentGenericEnv = nullptr,
GenericParamList *parentGenericParams = nullptr) {
TypeLoc = P.Tok.getLoc();
return parseSILType(Result, parsedGenericEnv, parsedGenericParams,
false, parentGenericEnv, parentGenericParams);
}
/// @}
bool parseSILDottedPath(ValueDecl *&Decl,
SmallVectorImpl<ValueDecl *> &values);
bool parseSILDottedPath(ValueDecl *&Decl) {
SmallVector<ValueDecl *, 4> values;
return parseSILDottedPath(Decl, values);
}
bool parseSILDottedPathWithoutPound(ValueDecl *&Decl,
SmallVectorImpl<ValueDecl *> &values);
bool parseSILDottedPathWithoutPound(ValueDecl *&Decl) {
SmallVector<ValueDecl *, 4> 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<ValueDecl *> &values);
bool parseSILDeclRef(SILDeclRef &Result) {
SmallVector<ValueDecl *, 4> 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<SILValue, 6> &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<SILType> &operandTypes,
SourceLoc componentLoc,
Identifier componentKind,
SILLocation InstLoc,
GenericEnvironment *patternEnv,
GenericParamList *patternParams);
bool isStartOfSILInstruction();
bool parseSubstitutions(SmallVectorImpl<ParsedSubstitution> &parsed,
GenericEnvironment *GenericEnv=nullptr,
GenericParamList *GenericParams=nullptr);
ProtocolConformanceRef parseProtocolConformance(
ProtocolDecl *&proto,
GenericEnvironment *&genericEnv,
GenericParamList *&genericParams);
ProtocolConformanceRef
parseProtocolConformance() {
ProtocolDecl *dummy = nullptr;
GenericEnvironment *genericEnv = nullptr;
GenericParamList *genericParams = nullptr;
return parseProtocolConformance(dummy, genericEnv, genericParams);
}
Optional<llvm::coverage::Counter>
parseSILCoverageExpr(llvm::coverage::CounterExpressionBuilder &Builder);
template <class T>
struct ParsedEnum {
Optional<T> Value;
StringRef Name;
SourceLoc Loc;
bool isSet() const { return Value.hasValue(); }
T operator*() const { return *Value; }
};
template <class T>
void setEnum(ParsedEnum<T> &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 <class T>
void maybeSetEnum(bool allowed, ParsedEnum<T> &existing,
T value, StringRef name, SourceLoc loc) {
if (allowed)
setEnum(existing, value, name, loc);
else
P.diagnose(loc, diag::unknown_attribute, name);
}
};
} // end anonymous namespace
bool SILParser::parseSILIdentifier(Identifier &Result, SourceLoc &Loc,
const Diagnostic &D) {
switch (P.Tok.getKind()) {
case tok::identifier:
case tok::dollarident:
Result = P.Context.getIdentifier(P.Tok.getText());
break;
case tok::string_literal: {
// Drop the double quotes.
StringRef rawString = P.Tok.getText().drop_front().drop_back();
Result = P.Context.getIdentifier(rawString);
break;
}
case tok::oper_binary_unspaced: // fixme?
case tok::oper_binary_spaced:
case tok::kw_init:
// A binary operator or `init` can be part of a SILDeclRef.
Result = P.Context.getIdentifier(P.Tok.getText());
break;
default:
// If it's some other keyword, grab an identifier for it.
if (P.Tok.isKeyword()) {
Result = P.Context.getIdentifier(P.Tok.getText());
break;
}
P.diagnose(P.Tok, D);
return true;
}
Loc = P.Tok.getLoc();
P.consumeToken();
return false;
}
bool SILParser::parseVerbatim(StringRef name) {
Identifier tok;
SourceLoc loc;
if (parseSILIdentifier(tok, loc, diag::expected_tok_in_sil_instr, name)) {
return true;
}
if (tok.str() != name) {
P.diagnose(loc, diag::expected_tok_in_sil_instr, name);
return true;
}
return false;
}
SILParser::~SILParser() {
for (auto &Entry : ForwardRefLocalValues) {
if (ValueBase *dummyVal = LocalValues[Entry.first()]) {
dummyVal->replaceAllUsesWith(SILUndef::get(dummyVal->getType(), SILMod));
SILInstruction::destroy(cast<GlobalAddrInst>(dummyVal));
SILMod.deallocateInst(cast<GlobalAddrInst>(dummyVal));
}
}
}
/// diagnoseProblems - After a function is fully parse, emit any diagnostics
/// for errors and return true if there were any.
bool SILParser::diagnoseProblems() {
// Check for any uses of basic blocks that were not defined.
if (!UndefinedBlocks.empty()) {
// FIXME: These are going to come out in nondeterministic order.
for (auto Entry : UndefinedBlocks)
P.diagnose(Entry.second.Loc, diag::sil_undefined_basicblock_use,
Entry.second.Item);
HadError = true;
}
if (!ForwardRefLocalValues.empty()) {
// FIXME: These are going to come out in nondeterministic order.
for (auto &Entry : ForwardRefLocalValues)
P.diagnose(Entry.second, diag::sil_use_of_undefined_value,
Entry.first());
HadError = true;
}
return HadError;
}
/// getGlobalNameForDefinition - Given a definition of a global name, look
/// it up and return an appropriate SIL function.
SILFunction *SILParser::getGlobalNameForDefinition(Identifier name,
CanSILFunctionType ty,
SourceLoc sourceLoc) {
SILParserFunctionBuilder builder(SILMod);
auto silLoc = RegularLocation(sourceLoc);
// Check to see if a function of this name has been forward referenced. If so
// complete the forward reference.
auto iter = TUState.ForwardRefFns.find(name);
if (iter != TUState.ForwardRefFns.end()) {
SILFunction *fn = iter->second.Item;
// Verify that the types match up.
if (fn->getLoweredFunctionType() != ty) {
P.diagnose(sourceLoc, diag::sil_value_use_type_mismatch, name.str(),
fn->getLoweredFunctionType(), ty);
P.diagnose(iter->second.Loc, diag::sil_prior_reference);
fn = builder.createFunctionForForwardReference("" /*name*/, ty, silLoc);
}
assert(fn->isExternalDeclaration() && "Forward defns cannot have bodies!");
TUState.ForwardRefFns.erase(iter);
// Move the function to this position in the module.
//
// FIXME: Should we move this functionality into SILParserFunctionBuilder?
SILMod.getFunctionList().remove(fn);
SILMod.getFunctionList().push_back(fn);
return fn;
}
// If we don't have a forward reference, make sure the function hasn't been
// defined already.
if (SILMod.lookUpFunction(name.str()) != nullptr) {
P.diagnose(sourceLoc, diag::sil_value_redefinition, name.str());
return builder.createFunctionForForwardReference("" /*name*/, ty, silLoc);
}
// Otherwise, this definition is the first use of this name.
return builder.createFunctionForForwardReference(name.str(), ty, silLoc);
}
/// getGlobalNameForReference - Given a reference to a global name, look it
/// up and return an appropriate SIL function.
SILFunction *SILParser::getGlobalNameForReference(Identifier name,
CanSILFunctionType funcTy,
SourceLoc sourceLoc,
bool ignoreFwdRef) {
SILParserFunctionBuilder builder(SILMod);
auto silLoc = RegularLocation(sourceLoc);
// Check to see if we have a function by this name already.
if (SILFunction *fn = SILMod.lookUpFunction(name.str())) {
// If so, check for matching types.
if (fn->getLoweredFunctionType() == funcTy) {
return fn;
}
P.diagnose(sourceLoc, diag::sil_value_use_type_mismatch, name.str(),
fn->getLoweredFunctionType(), funcTy);
return builder.createFunctionForForwardReference("" /*name*/, funcTy,
silLoc);
}
// If we didn't find a function, create a new one - it must be a forward
// reference.
auto *fn =
builder.createFunctionForForwardReference(name.str(), funcTy, silLoc);
TUState.ForwardRefFns[name] = {fn, ignoreFwdRef ? SourceLoc() : sourceLoc};
return fn;
}
/// getBBForDefinition - Return the SILBasicBlock for a definition of the
/// specified block.
SILBasicBlock *SILParser::getBBForDefinition(Identifier Name, SourceLoc Loc) {
// If there was no name specified for this block, just create a new one.
if (Name.empty())
return F->createBasicBlock();
SILBasicBlock *&BB = BlocksByName[Name];
// If the block has never been named yet, just create it.
if (BB == nullptr)
return BB = F->createBasicBlock();
// If it already exists, it was either a forward reference or a redefinition.
// If it is a forward reference, it should be in our undefined set.
if (!UndefinedBlocks.erase(BB)) {
// If we have a redefinition, return a new BB to avoid inserting
// instructions after the terminator.
P.diagnose(Loc, diag::sil_basicblock_redefinition, Name);
HadError = true;
return F->createBasicBlock();
}
// FIXME: Splice the block to the end of the function so they come out in the
// right order.
return BB;
}
/// getBBForReference - return the SILBasicBlock of the specified name. The
/// source location is used to diagnose a failure if the block ends up never
/// being defined.
SILBasicBlock *SILParser::getBBForReference(Identifier Name, SourceLoc Loc) {
// If the block has already been created, use it.
SILBasicBlock *&BB = BlocksByName[Name];
if (BB != nullptr)
return BB;
// Otherwise, create it and remember that this is a forward reference so
// that we can diagnose use without definition problems.
BB = F->createBasicBlock();
UndefinedBlocks[BB] = {Name, Loc};
return BB;
}
/// sil-global-name:
/// '@' identifier
bool SILParser::parseGlobalName(Identifier &Name) {
return P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
parseSILIdentifier(Name, diag::expected_sil_value_name);
}
/// getLocalValue - Get a reference to a local value with the specified name
/// and type.
SILValue SILParser::getLocalValue(UnresolvedValueName Name, SILType Type,
SILLocation Loc, SILBuilder &B) {
if (Name.isUndef())
return SILUndef::get(Type, B.getFunction());
// Check to see if this is already defined.
ValueBase *&Entry = LocalValues[Name.Name];
if (Entry) {
// If this value is already defined, check it to make sure types match.
SILType EntryTy = Entry->getType();
if (EntryTy != Type) {
HadError = true;
P.diagnose(Name.NameLoc, diag::sil_value_use_type_mismatch, Name.Name,
EntryTy.getASTType(), Type.getASTType());
// Make sure to return something of the requested type.
return SILUndef::get(Type, B.getFunction());
}
return SILValue(Entry);
}
// Otherwise, this is a forward reference. Create a dummy node to represent
// it until we see a real definition.
ForwardRefLocalValues[Name.Name] = Name.NameLoc;
Entry = new (SILMod) GlobalAddrInst(getDebugLoc(B, Loc), Type);
return Entry;
}
/// setLocalValue - When an instruction or block argument is defined, this
/// method is used to register it and update our symbol table.
void SILParser::setLocalValue(ValueBase *Value, StringRef Name,
SourceLoc NameLoc) {
ValueBase *&Entry = LocalValues[Name];
// If this value was already defined, it is either a redefinition, or a
// specification for a forward referenced value.
if (Entry) {
if (!ForwardRefLocalValues.erase(Name)) {
P.diagnose(NameLoc, diag::sil_value_redefinition, Name);
HadError = true;
return;
}
// If the forward reference was of the wrong type, diagnose this now.
if (Entry->getType() != Value->getType()) {
P.diagnose(NameLoc, diag::sil_value_def_type_mismatch, Name,
Entry->getType().getASTType(),
Value->getType().getASTType());
HadError = true;
} else {
// Forward references only live here if they have a single result.
Entry->replaceAllUsesWith(Value);
SILInstruction::destroy(cast<GlobalAddrInst>(Entry));
SILMod.deallocateInst(cast<GlobalAddrInst>(Entry));
}
Entry = Value;
return;
}
// Otherwise, just store it in our map.
Entry = Value;
}
//===----------------------------------------------------------------------===//
// SIL Parsing Logic
//===----------------------------------------------------------------------===//
/// parseSILLinkage - Parse a linkage specifier if present.
/// sil-linkage:
/// /*empty*/ // default depends on whether this is a definition
/// 'public'
/// 'hidden'
/// 'shared'
/// 'private'
/// 'public_external'
/// 'hidden_external'
/// 'private_external'
static bool parseSILLinkage(Optional<SILLinkage> &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<Optional<SILLinkage>>(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<SILLinkage> linkage,
bool isDefinition) {
if (linkage.hasValue()) {
return linkage.getValue();
} else if (isDefinition) {
return SILLinkage::DefaultForDefinition;
} else {
return SILLinkage::DefaultForDeclaration;
}
}
static bool parseSILOptional(StringRef &Result, SourceLoc &Loc, SILParser &SP) {
if (SP.P.consumeIf(tok::l_square)) {
Identifier Id;
SP.parseSILIdentifier(Id, Loc, diag::expected_in_attribute_list);
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
Result = Id.str();
return true;
}
return false;
}
static bool parseSILOptional(StringRef &Result, SILParser &SP) {
SourceLoc Loc;
return parseSILOptional(Result, Loc, SP);
}
/// Parse an option attribute ('[' Expected ']')?
static bool parseSILOptional(bool &Result, SILParser &SP, StringRef Expected) {
StringRef Optional;
if (parseSILOptional(Optional, SP)) {
if (Optional != Expected)
return true;
Result = true;
}
return false;
}
/// Remap RequirementReps to Requirements.
void SILParser::convertRequirements(ArrayRef<RequirementRepr> From,
SmallVectorImpl<Requirement> &To) {
if (From.empty()) {
To.clear();
return;
}
// Use parser lexical scopes to resolve references
// to the generic parameters.
auto ResolveToInterfaceType = [&](TypeRepr *TyR) -> Type {
return performTypeResolution(TyR, /*IsSILType=*/false,
ContextGenericEnv, ContextGenericParams)
->mapTypeOutOfContext();
};
for (auto &Req : From) {
if (Req.getKind() == RequirementReprKind::SameType) {
auto FirstType = ResolveToInterfaceType(Req.getFirstTypeRepr());
auto SecondType = ResolveToInterfaceType(Req.getSecondTypeRepr());
Requirement ConvertedRequirement(RequirementKind::SameType, FirstType,
SecondType);
To.push_back(ConvertedRequirement);
continue;
}
if (Req.getKind() == RequirementReprKind::TypeConstraint) {
auto Subject = ResolveToInterfaceType(Req.getSubjectRepr());
auto Constraint = ResolveToInterfaceType(Req.getConstraintRepr());
Requirement ConvertedRequirement(RequirementKind::Conformance, Subject,
Constraint);
To.push_back(ConvertedRequirement);
continue;
}
if (Req.getKind() == RequirementReprKind::LayoutConstraint) {
auto Subject = ResolveToInterfaceType(Req.getSubjectRepr());
Requirement ConvertedRequirement(RequirementKind::Layout, Subject,
Req.getLayoutConstraint());
To.push_back(ConvertedRequirement);
continue;
}
llvm_unreachable("Unsupported requirement kind");
}
}
static bool parseDeclSILOptional(bool *isTransparent,
IsSerialized_t *isSerialized,
bool *isCanonical,
bool *hasOwnershipSSA,
IsThunk_t *isThunk,
IsDynamicallyReplaceable_t *isDynamic,
IsExactSelfClass_t *isExactSelfClass,
SILFunction **dynamicallyReplacedFunction,
Identifier *objCReplacementFor,
SILFunction::Purpose *specialPurpose,
Inline_t *inlineStrategy,
OptimizationMode *optimizationMode,
bool *isLet,
bool *isWeakImported,
AvailabilityContext *availability,
bool *isWithoutActuallyEscapingThunk,
SmallVectorImpl<std::string> *Semantics,
SmallVectorImpl<ParsedSpecAttr> *SpecAttrs,
ValueDecl **ClangDecl,
EffectsKind *MRK, SILParser &SP,
SILModule &M) {
while (SP.P.consumeIf(tok::l_square)) {
if (isLet && SP.P.Tok.is(tok::kw_let)) {
*isLet = true;
SP.P.consumeToken(tok::kw_let);
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
continue;
}
else if (SP.P.Tok.isNot(tok::identifier)) {
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
return true;
} else if (isTransparent && SP.P.Tok.getText() == "transparent")
*isTransparent = true;
else if (isSerialized && SP.P.Tok.getText() == "serialized")
*isSerialized = IsSerialized;
else if (isDynamic && SP.P.Tok.getText() == "dynamically_replacable")
*isDynamic = IsDynamic;
else if (isExactSelfClass && SP.P.Tok.getText() == "exact_self_class")
*isExactSelfClass = IsExactSelfClass;
else if (isSerialized && SP.P.Tok.getText() == "serializable")
*isSerialized = IsSerializable;
else if (isCanonical && SP.P.Tok.getText() == "canonical")
*isCanonical = true;
else if (hasOwnershipSSA && SP.P.Tok.getText() == "ossa")
*hasOwnershipSSA = true;
else if (isThunk && SP.P.Tok.getText() == "thunk")
*isThunk = IsThunk;
else if (isThunk && SP.P.Tok.getText() == "signature_optimized_thunk")
*isThunk = IsSignatureOptimizedThunk;
else if (isThunk && SP.P.Tok.getText() == "reabstraction_thunk")
*isThunk = IsReabstractionThunk;
else if (isWithoutActuallyEscapingThunk
&& SP.P.Tok.getText() == "without_actually_escaping")
*isWithoutActuallyEscapingThunk = true;
else if (specialPurpose && SP.P.Tok.getText() == "global_init")
*specialPurpose = SILFunction::Purpose::GlobalInit;
else if (specialPurpose && SP.P.Tok.getText() == "lazy_getter")
*specialPurpose = SILFunction::Purpose::LazyPropertyGetter;
else if (specialPurpose && SP.P.Tok.getText() == "global_init_once_fn")
*specialPurpose = SILFunction::Purpose::GlobalInitOnceFunction;
else if (isWeakImported && SP.P.Tok.getText() == "weak_imported") {
if (M.getASTContext().LangOpts.Target.isOSBinFormatCOFF())
SP.P.diagnose(SP.P.Tok, diag::attr_unsupported_on_target,
SP.P.Tok.getText(),
M.getASTContext().LangOpts.Target.str());
else
*isWeakImported = true;
} else if (availability && SP.P.Tok.getText() == "available") {
SP.P.consumeToken(tok::identifier);
SourceRange range;
llvm::VersionTuple version;
if (SP.P.parseVersionTuple(version, range,
diag::sil_availability_expected_version))
return true;
*availability = AvailabilityContext(VersionRange::allGTE(version));
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
continue;
} else if (inlineStrategy && SP.P.Tok.getText() == "noinline")
*inlineStrategy = NoInline;
else if (optimizationMode && SP.P.Tok.getText() == "Onone")
*optimizationMode = OptimizationMode::NoOptimization;
else if (optimizationMode && SP.P.Tok.getText() == "Ospeed")
*optimizationMode = OptimizationMode::ForSpeed;
else if (optimizationMode && SP.P.Tok.getText() == "Osize")
*optimizationMode = OptimizationMode::ForSize;
else if (inlineStrategy && SP.P.Tok.getText() == "always_inline")
*inlineStrategy = AlwaysInline;
else if (MRK && SP.P.Tok.getText() == "readnone")
*MRK = EffectsKind::ReadNone;
else if (MRK && SP.P.Tok.getText() == "readonly")
*MRK = EffectsKind::ReadOnly;
else if (MRK && SP.P.Tok.getText() == "readwrite")
*MRK = EffectsKind::ReadWrite;
else if (MRK && SP.P.Tok.getText() == "releasenone")
*MRK = EffectsKind::ReleaseNone;
else if (dynamicallyReplacedFunction && SP.P.Tok.getText() == "dynamic_replacement_for") {
SP.P.consumeToken(tok::identifier);
if (SP.P.Tok.getKind() != tok::string_literal) {
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
return true;
}
// Drop the double quotes.
StringRef replacedFunc = SP.P.Tok.getText().drop_front().drop_back();
SILFunction *Func = M.lookUpFunction(replacedFunc.str());
if (!Func) {
Identifier Id = SP.P.Context.getIdentifier(replacedFunc);
SP.P.diagnose(SP.P.Tok, diag::sil_dynamically_replaced_func_not_found,
Id);
return true;
}
*dynamicallyReplacedFunction = Func;
SP.P.consumeToken(tok::string_literal);
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
continue;
} else if (objCReplacementFor &&
SP.P.Tok.getText() == "objc_replacement_for") {
SP.P.consumeToken(tok::identifier);
if (SP.P.Tok.getKind() != tok::string_literal) {
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
return true;
}
// Drop the double quotes.
StringRef replacedFunc = SP.P.Tok.getText().drop_front().drop_back();
*objCReplacementFor = SP.P.Context.getIdentifier(replacedFunc);
SP.P.consumeToken(tok::string_literal);
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
continue;
} else if (Semantics && SP.P.Tok.getText() == "_semantics") {
SP.P.consumeToken(tok::identifier);
if (SP.P.Tok.getKind() != tok::string_literal) {
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
return true;
}
// Drop the double quotes.
StringRef rawString = SP.P.Tok.getText().drop_front().drop_back();
Semantics->push_back(rawString.str());
SP.P.consumeToken(tok::string_literal);
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
continue;
} else if (SpecAttrs && SP.P.Tok.getText() == "_specialize") {
SourceLoc AtLoc = SP.P.Tok.getLoc();
SourceLoc Loc(AtLoc);
// Parse a _specialized attribute, building a parsed substitution list
// and pushing a new ParsedSpecAttr on the SpecAttrs list. Conformances
// cannot be generated until the function declaration is fully parsed so
// that the function's generic signature can be consulted.
ParsedSpecAttr SpecAttr;
SpecAttr.requirements = {};
SpecAttr.exported = false;
SpecAttr.kind = SILSpecializeAttr::SpecializationKind::Full;
SpecializeAttr *Attr;
StringRef targetFunctionName;
ModuleDecl *module = nullptr;
if (!SP.P.parseSpecializeAttribute(
tok::r_square, AtLoc, Loc, Attr,
[&targetFunctionName](Parser &P) -> bool {
if (P.Tok.getKind() != tok::string_literal) {
P.diagnose(P.Tok, diag::expected_in_attribute_list);
return true;
}
// Drop the double quotes.
targetFunctionName = P.Tok.getText().drop_front().drop_back();
P.consumeToken(tok::string_literal);
return true;
},
[&module](Parser &P) -> bool {
if (P.Tok.getKind() != tok::identifier) {
P.diagnose(P.Tok, diag::expected_in_attribute_list);
return true;
}
auto ident = P.Context.getIdentifier(P.Tok.getText());
module = P.Context.getModuleByIdentifier(ident);
assert(module);
P.consumeToken();
return true;
}))
return true;
SILFunction *targetFunction = nullptr;
if (!targetFunctionName.empty()) {
targetFunction = M.lookUpFunction(targetFunctionName.str());
if (!targetFunction) {
Identifier Id = SP.P.Context.getIdentifier(targetFunctionName);
SP.P.diagnose(SP.P.Tok, diag::sil_specialize_target_func_not_found,
Id);
return true;
}
}
// Convert SpecializeAttr into ParsedSpecAttr.
SpecAttr.requirements = Attr->getTrailingWhereClause()->getRequirements();
SpecAttr.kind = Attr->getSpecializationKind() ==
swift::SpecializeAttr::SpecializationKind::Full
? SILSpecializeAttr::SpecializationKind::Full
: SILSpecializeAttr::SpecializationKind::Partial;
SpecAttr.exported = Attr->isExported();
SpecAttr.target = targetFunction;
SpecAttrs->emplace_back(SpecAttr);
if (!Attr->getSPIGroups().empty()) {
SpecAttr.spiGroupID = Attr->getSPIGroups()[0];
}
continue;
}
else if (ClangDecl && SP.P.Tok.getText() == "clang") {
SP.P.consumeToken(tok::identifier);
if (SP.parseSILDottedPathWithoutPound(*ClangDecl))
return true;
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
continue;
}
else {
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
return true;
}
SP.P.consumeToken(tok::identifier);
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
}
return false;
}
Type SILParser::performTypeResolution(TypeRepr *TyR, bool IsSILType,
GenericEnvironment *GenericEnv,
GenericParamList *GenericParams) {
if (GenericEnv == nullptr)
GenericEnv = ContextGenericEnv;
return swift::performTypeResolution(TyR, P.Context,
/*isSILMode=*/true, IsSILType,
GenericEnv, GenericParams,
&P.SF);
}
/// Find the top-level ValueDecl or Module given a name.
static llvm::PointerUnion<ValueDecl *, ModuleDecl *>
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<ValueDecl *> &Lookup,
bool ExpectMultipleResults) {
Type CheckTy = Ty;
if (auto MetaTy = CheckTy->getAs<AnyMetatypeType>())
CheckTy = MetaTy->getInstanceType();
if (auto nominal = CheckTy->getAnyNominal()) {
if (Name == DeclBaseName::createDestructor() &&
isa<ClassDecl>(nominal)) {
auto *classDecl = cast<ClassDecl>(nominal);
Lookup.push_back(classDecl->getDestructor());
} else {
auto found = nominal->lookupDirect(Name);
Lookup.append(found.begin(), found.end());
}
} else if (auto moduleTy = CheckTy->getAs<ModuleType>()) {
moduleTy->getModule()->lookupValue(Name, NLKind::QualifiedLookup, Lookup);
} else {
P.diagnose(Loc, diag::sil_member_lookup_bad_type, Name, Ty);
return nullptr;
}
if (Lookup.empty() || (!ExpectMultipleResults && Lookup.size() != 1)) {
P.diagnose(Loc, diag::sil_named_member_decl_not_found, Name, Ty);
return nullptr;
}
return Lookup[0];
}
bool SILParser::parseASTType(CanType &result,
GenericEnvironment *genericEnv,
GenericParamList *genericParams) {
ParserResult<TypeRepr> parsedType = P.parseType();
if (parsedType.isNull()) return true;
bool wantInterfaceType = true;
if (genericEnv == nullptr) {
genericEnv = ContextGenericEnv;
wantInterfaceType = false;
}
if (genericParams == nullptr)
genericParams = ContextGenericParams;
bindSILGenericParams(parsedType.get());
const auto resolvedType =
performTypeResolution(parsedType.get(), /*isSILType=*/false,
genericEnv, genericParams);
if (resolvedType->hasError())
return true;
if (wantInterfaceType)
result = resolvedType->mapTypeOutOfContext()->getCanonicalType();
else
result = resolvedType->getCanonicalType();
// Invoke the callback on the parsed type.
ParsedTypeCallback(resolvedType);
return false;
}
void SILParser::bindSILGenericParams(TypeRepr *TyR) {
// Resolve the generic environments for parsed generic function and box types.
class HandleSILGenericParamsWalker : public ASTWalker {
SourceFile *SF;
public:
HandleSILGenericParamsWalker(SourceFile *SF) : SF(SF) {}
bool walkToTypeReprPre(TypeRepr *T) override {
if (auto fnType = dyn_cast<FunctionTypeRepr>(T)) {
if (auto *genericParams = fnType->getGenericParams()) {
auto *env = handleSILGenericParams(genericParams, SF);
fnType->setGenericEnvironment(env);
}
if (auto *genericParams = fnType->getPatternGenericParams()) {
auto *env = handleSILGenericParams(genericParams, SF);
fnType->setPatternGenericEnvironment(env);
}
}
if (auto boxType = dyn_cast<SILBoxTypeRepr>(T)) {
if (auto *genericParams = boxType->getGenericParams()) {
auto *env = handleSILGenericParams(genericParams, SF);
boxType->setGenericEnvironment(env);
}
}
return true;
}
};
TyR->walk(HandleSILGenericParamsWalker(&P.SF));
}
/// sil-type:
/// '$' '*'? attribute-list (generic-params)? type
///
bool SILParser::parseSILType(SILType &Result,
GenericEnvironment *&ParsedGenericEnv,
GenericParamList *&ParsedGenericParams,
bool IsFuncDecl,
GenericEnvironment *OuterGenericEnv,
GenericParamList *OuterGenericParams) {
ParsedGenericEnv = nullptr;
ParsedGenericParams = nullptr;
if (OuterGenericEnv == nullptr)
OuterGenericEnv = ContextGenericEnv;
if (OuterGenericParams == nullptr)
OuterGenericParams = ContextGenericParams;
if (P.parseToken(tok::sil_dollar, diag::expected_sil_type))
return true;
// If we have a '*', then this is an address type.
SILValueCategory category = SILValueCategory::Object;
if (P.Tok.isAnyOperator() && P.Tok.getText().startswith("*")) {
category = SILValueCategory::Address;
P.consumeStartingCharacterOfCurrentToken();
}
// Parse attributes.
ParamDecl::Specifier specifier;
SourceLoc specifierLoc;
TypeAttributes attrs;
P.parseTypeAttributeList(specifier, specifierLoc, attrs);
// Global functions are implicitly @convention(thin) if not specified otherwise.
if (IsFuncDecl && !attrs.has(TAK_convention)) {
// Use a random location.
attrs.setAttr(TAK_convention, P.PreviousLoc);
attrs.ConventionArguments =
TypeAttributes::Convention::makeSwiftConvention("thin");
}
ParserResult<TypeRepr> TyR = P.parseType(diag::expected_sil_type,
/*isSILFuncDecl*/ IsFuncDecl);
if (TyR.isNull())
return true;
bindSILGenericParams(TyR.get());
// Apply attributes to the type.
auto *attrRepr =
P.applyAttributeToType(TyR.get(), attrs, specifier, specifierLoc);
const auto Ty =
performTypeResolution(attrRepr, /*IsSILType=*/true,
OuterGenericEnv, OuterGenericParams);
if (Ty->hasError())
return true;
// Save the top-level function generic environment if there was one.
if (auto fnType = dyn_cast<FunctionTypeRepr>(TyR.get())) {
if (auto *genericEnv = fnType->getGenericEnvironment())
ParsedGenericEnv = genericEnv;
if (auto *genericParams = fnType->getGenericParams())
ParsedGenericParams = genericParams;
}
Result = SILType::getPrimitiveType(Ty->getCanonicalType(),
category);
// Invoke the callback on the parsed type.
ParsedTypeCallback(Ty);
return false;
}
bool SILParser::parseSILDottedPath(ValueDecl *&Decl,
SmallVectorImpl<ValueDecl *> &values) {
if (P.parseToken(tok::pound, diag::expected_sil_constant))
return true;
return parseSILDottedPathWithoutPound(Decl, values);
}
bool SILParser::parseSILDottedPathWithoutPound(ValueDecl *&Decl,
SmallVectorImpl<ValueDecl *> &values) {
// Handle sil-dotted-path.
Identifier Id;
SmallVector<DeclBaseName, 4> FullName;
SmallVector<SourceLoc, 4> 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<ValueDecl*, ModuleDecl *> 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<ModuleDecl*>()) {
assert(FullName.size() > 1 &&
"A single module is not a full path to SILDeclRef");
auto Mod = Res.get<ModuleDecl*>();
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<ValueDecl*>();
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<AccessorKind> getAccessorKind(StringRef ident) {
return llvm::StringSwitch<Optional<AccessorKind>>(ident)
.Case("getter", AccessorKind::Get)
.Case("setter", AccessorKind::Set)
.Case("addressor", AccessorKind::Address)
.Case("mutableAddressor", AccessorKind::MutableAddress)
.Case("read", AccessorKind::Read)
.Case("modify", AccessorKind::Modify)
.Default(None);
}
/// sil-decl-ref ::= '#' sil-identifier ('.' sil-identifier)* sil-decl-subref?
/// sil-decl-subref ::= '!' sil-decl-subref-part ('.' sil-decl-lang)?
/// ('.' sil-decl-autodiff)?
/// sil-decl-subref ::= '!' sil-decl-lang
/// sil-decl-subref ::= '!' sil-decl-autodiff
/// sil-decl-subref-part ::= 'getter'
/// sil-decl-subref-part ::= 'setter'
/// sil-decl-subref-part ::= 'allocator'
/// sil-decl-subref-part ::= 'initializer'
/// sil-decl-subref-part ::= 'enumelt'
/// sil-decl-subref-part ::= 'destroyer'
/// sil-decl-subref-part ::= 'globalaccessor'
/// sil-decl-lang ::= 'foreign'
/// sil-decl-autodiff ::= sil-decl-autodiff-kind '.' sil-decl-autodiff-indices
/// sil-decl-autodiff-kind ::= 'jvp'
/// sil-decl-autodiff-kind ::= 'vjp'
/// sil-decl-autodiff-indices ::= [SU]+
bool SILParser::parseSILDeclRef(SILDeclRef &Result,
SmallVectorImpl<ValueDecl *> &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> 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<AbstractStorageDecl>(values[srcI]))
if (auto accessor = storage->getOpaqueAccessor(*accessorKind))
values[destI++] = accessor;
}
values.resize(destI);
// Complain if none of the decls had a corresponding accessor.
if (destI == 0) {
P.diagnose(IdLoc, diag::referenced_value_no_accessor, 0);
return true;
}
Kind = SILDeclRef::Kind::Func;
VD = values[0];
ParseState = 1;
} else if (!ParseState && Id.str() == "allocator") {
Kind = SILDeclRef::Kind::Allocator;
ParseState = 1;
} else if (!ParseState && Id.str() == "initializer") {
Kind = SILDeclRef::Kind::Initializer;
ParseState = 1;
} else if (!ParseState && Id.str() == "enumelt") {
Kind = SILDeclRef::Kind::EnumElement;
ParseState = 1;
} else if (!ParseState && Id.str() == "destroyer") {
Kind = SILDeclRef::Kind::Destroyer;
ParseState = 1;
} else if (!ParseState && Id.str() == "deallocator") {
Kind = SILDeclRef::Kind::Deallocator;
ParseState = 1;
} else if (!ParseState && Id.str() == "globalaccessor") {
Kind = SILDeclRef::Kind::GlobalAccessor;
ParseState = 1;
} else if (!ParseState && Id.str() == "ivardestroyer") {
Kind = SILDeclRef::Kind::IVarDestroyer;
ParseState = 1;
} else if (!ParseState && Id.str() == "ivarinitializer") {
Kind = SILDeclRef::Kind::IVarInitializer;
ParseState = 1;
} else if (!ParseState && Id.str() == "defaultarg") {
Kind = SILDeclRef::Kind::IVarInitializer;
ParseState = 1;
} else if (!ParseState && Id.str() == "propertyinit") {
Kind = SILDeclRef::Kind::StoredPropertyInitializer;
ParseState = 1;
} else if (!ParseState && Id.str() == "backinginit") {
Kind = SILDeclRef::Kind::PropertyWrapperBackingInitializer;
ParseState = 1;
} else if (Id.str() == "foreign") {
IsObjC = true;
break;
} else if (Id.str() == "jvp" || Id.str() == "vjp") {
IndexSubset *parameterIndices = nullptr;
GenericSignature derivativeGenSig;
// Parse derivative function kind.
AutoDiffDerivativeFunctionKind derivativeKind(Id.str());
if (!P.consumeIf(tok::period)) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, ".");
return true;
}
// Parse parameter indices.
parameterIndices =
IndexSubset::getFromString(SILMod.getASTContext(), P.Tok.getText());
if (!parameterIndices) {
P.diagnose(P.Tok, diag::invalid_index_subset);
return true;
}
P.consumeToken();
// Parse derivative generic signature (optional).
if (P.Tok.is(tok::oper_binary_unspaced) && P.Tok.getText() == ".<") {
P.consumeStartingCharacterOfCurrentToken(tok::period);
// Create a new scope to avoid type redefinition errors.
auto *genericParams = P.maybeParseGenericParams().getPtrOrNull();
assert(genericParams);
auto *derivativeGenEnv = handleSILGenericParams(genericParams, &P.SF);
derivativeGenSig = derivativeGenEnv->getGenericSignature();
}
DerivativeId = AutoDiffDerivativeFunctionIdentifier::get(
derivativeKind, parameterIndices, derivativeGenSig,
SILMod.getASTContext());
break;
} else {
break;
}
} else
break;
} while (P.consumeIf(tok::period));
// Construct SILDeclRef.
Result = SILDeclRef(VD, Kind, IsObjC, DerivativeId);
return false;
}
/// parseValueName - Parse a value name without a type available yet.
///
/// sil-value-name:
/// sil-local-name
/// 'undef'
///
bool SILParser::parseValueName(UnresolvedValueName &Result) {
Result.Name = P.Tok.getText();
if (P.Tok.is(tok::kw_undef)) {
Result.NameLoc = P.consumeToken(tok::kw_undef);
return false;
}
// Parse the local-name.
if (P.parseToken(tok::sil_local_name, Result.NameLoc,
diag::expected_sil_value_name))
return true;
return false;
}
/// parseValueRef - Parse a value, given a contextual type.
///
/// sil-value-ref:
/// sil-local-name
///
bool SILParser::parseValueRef(SILValue &Result, SILType Ty,
SILLocation Loc, SILBuilder &B) {
UnresolvedValueName Name;
if (parseValueName(Name)) return true;
Result = getLocalValue(Name, Ty, Loc, B);
return false;
}
/// parseTypedValueRef - Parse a type/value reference pair.
///
/// sil-typed-valueref:
/// sil-value-ref ':' sil-type
///
bool SILParser::parseTypedValueRef(SILValue &Result, SourceLoc &Loc,
SILBuilder &B) {
Loc = P.Tok.getLoc();
UnresolvedValueName Name;
SILType Ty;
if (parseValueName(Name) ||
P.parseToken(tok::colon, diag::expected_sil_colon_value_ref) ||
parseSILType(Ty))
return true;
Result = getLocalValue(Name, Ty, RegularLocation(Loc), B);
return false;
}
/// Look up whether the given string corresponds to a SIL opcode.
static Optional<SILInstructionKind> getOpcodeByName(StringRef OpcodeName) {
return llvm::StringSwitch<Optional<SILInstructionKind>>(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<SILValue, 6> &Args,
SILBuilder &B) {
if (P.Tok.is(tok::l_paren)) {
SourceLoc LParenLoc = P.consumeToken(tok::l_paren);
SourceLoc RParenLoc;
bool HasError = false;
if (P.parseList(tok::r_paren, LParenLoc, RParenLoc,
/*AllowSepAfterLast=*/false,
diag::sil_basicblock_arg_rparen,
SyntaxKind::Unknown,
[&]() -> ParserStatus {
SILValue Arg;
SourceLoc ArgLoc;
if (parseTypedValueRef(Arg, ArgLoc, B)) {
HasError = true;
return makeParserError();
}
Args.push_back(Arg);
return makeParserSuccess();
}).isErrorOrHasCompletion() || HasError)
return true;
}
return false;
}
/// Parse the substitution list for an apply instruction or
/// specialized protocol conformance.
bool SILParser::parseSubstitutions(SmallVectorImpl<ParsedSubstitution> &parsed,
GenericEnvironment *GenericEnv,
GenericParamList *GenericParams) {
// Check for an opening '<' bracket.
if (!P.startsWithLess(P.Tok))
return false;
if (GenericEnv == nullptr)
GenericEnv = ContextGenericEnv;
if (GenericParams == nullptr)
GenericParams = ContextGenericParams;
P.consumeStartingLess();
// Parse a list of Substitutions.
do {
SourceLoc Loc = P.Tok.getLoc();
// Parse substitution as AST type.
ParserResult<TypeRepr> TyR = P.parseType();
if (TyR.isNull())
return true;
const auto Ty =
performTypeResolution(TyR.get(), /*IsSILType=*/false,
GenericEnv, GenericParams);
if (Ty->hasError())
return true;
parsed.push_back({Loc, Ty});
} while (P.consumeIf(tok::comma));
// Consume the closing '>'.
if (!P.startsWithGreater(P.Tok)) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, ">");
return true;
}
P.consumeStartingGreater();
return false;
}
/// Collect conformances by looking up the conformance from replacement
/// type and protocol decl.
static bool getConformancesForSubstitution(Parser &P,
ExistentialLayout::ProtocolTypeArrayRef protocols,
Type subReplacement,
SourceLoc loc,
SmallVectorImpl<ProtocolConformanceRef> &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<ParsedSubstitution> 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<GenericTypeParamType>(type);
if (!genericParam)
return nullptr;
auto index = genericSig->getGenericParamOrdinal(genericParam);
assert(index < genericSig->getGenericParams().size());
assert(index < parses.size());
// Provide the replacement type.
return parses[index].replacement;
},
[&](CanType dependentType, Type replacementType,
ProtocolDecl *proto) -> ProtocolConformanceRef {
auto M = SP.P.SF.getParentModule();
if (auto conformance = M->lookupConformance(replacementType, proto))
return conformance;
SP.P.diagnose(loc, diag::sil_substitution_mismatch, replacementType,
proto->getDeclaredInterfaceType());
failed = true;
return ProtocolConformanceRef(proto);
});
return failed ? SubstitutionMap() : subMap;
}
static ArrayRef<ProtocolConformanceRef>
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<ProtocolConformanceRef, 2> 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<LoadOwnershipQualifier>(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<StoreOwnershipQualifier>(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<AssignOwnershipQualifier>(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<unsigned> &indices,
const Diagnostic &parseIndexDiag) {
SourceLoc loc;
// Parse `[<label> <integer_literal>...]`.
if (P.parseToken(tok::l_square, diag::sil_autodiff_expected_lsquare,
"index list") ||
P.parseSpecificIdentifier(
label, diag::sil_autodiff_expected_index_list_label, label))
return true;
while (P.Tok.is(tok::integer_literal)) {
unsigned index;
if (P.parseUnsignedInteger(index, loc, parseIndexDiag))
return true;
indices.push_back(index);
}
if (P.parseToken(tok::r_square, diag::sil_autodiff_expected_rsquare,
"index list"))
return true;
return false;
};
/// sil-differentiability-witness-config-and-function ::=
/// '[' 'parameters' index-subset ']'
/// '[' 'results' index-subset ']'
/// ('<' 'where' derivative-generic-signature-requirements '>')?
/// sil-function-ref
///
/// e.g. parameters 0 1] [results 0] <T where T: Differentiable>
/// @foo : <T> $(T) -> T
static Optional<std::pair<AutoDiffConfig, SILFunction *>>
parseSILDifferentiabilityWitnessConfigAndFunction(Parser &P, SILParser &SP,
SILLocation L) {
// Parse parameter and result indices.
SmallVector<unsigned, 8> rawParameterIndices;
SmallVector<unsigned, 8> rawResultIndices;
if (parseIndexList(P, "parameters", rawParameterIndices,
diag::sil_autodiff_expected_parameter_index))
return {};
if (parseIndexList(P, "results", rawResultIndices,
diag::sil_autodiff_expected_result_index))
return {};
// Parse witness generic parameter clause.
GenericSignature witnessGenSig = GenericSignature();
SourceLoc witnessGenSigStartLoc = P.getEndOfPreviousLoc();
{
auto *genericParams = P.maybeParseGenericParams().getPtrOrNull();
if (genericParams) {
auto *witnessGenEnv = handleSILGenericParams(genericParams, &P.SF);
witnessGenSig = witnessGenEnv->getGenericSignature();
}
}
// Parse original function name and type.
SILFunction *originalFunction = nullptr;
if (SP.parseSILFunctionRef(L, originalFunction))
return {};
// Resolve parsed witness generic signature.
if (witnessGenSig) {
auto origGenSig =
originalFunction->getLoweredFunctionType()->getSubstGenericSignature();
// Check whether original function generic signature and parsed witness
// generic have the same generic parameters.
auto areGenericParametersConsistent = [&]() {
llvm::SmallDenseSet<GenericParamKey, 4> genericParamKeys;
for (auto *origGP : origGenSig->getGenericParams())
genericParamKeys.insert(GenericParamKey(origGP));
for (auto *witnessGP : witnessGenSig->getGenericParams())
if (!genericParamKeys.erase(GenericParamKey(witnessGP)))
return false;
return genericParamKeys.empty();
};
if (!areGenericParametersConsistent()) {
P.diagnose(witnessGenSigStartLoc,
diag::sil_diff_witness_invalid_generic_signature,
witnessGenSig->getAsString(), origGenSig->getAsString());
return {};
}
// Combine parsed witness requirements with original function generic
// signature requirements to form full witness generic signature.
SmallVector<Requirement, 4> witnessRequirements(
witnessGenSig->getRequirements().begin(),
witnessGenSig->getRequirements().end());
witnessGenSig = evaluateOrDefault(
P.Context.evaluator,
AbstractGenericSignatureRequest{origGenSig.getPointer(),
/*addedGenericParams=*/{},
std::move(witnessRequirements)},
nullptr);
}
auto origFnType = originalFunction->getLoweredFunctionType();
auto *parameterIndices = IndexSubset::get(
P.Context, origFnType->getNumParameters(), rawParameterIndices);
auto *resultIndices = IndexSubset::get(P.Context, origFnType->getNumResults(),
rawResultIndices);
AutoDiffConfig config(parameterIndices, resultIndices, witnessGenSig);
return std::make_pair(config, originalFunction);
}
bool SILParser::parseSILDeclRef(SILDeclRef &Member, bool FnTypeRequired) {
SourceLoc TyLoc;
SmallVector<ValueDecl *, 4> 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.startsWithLess(P.peekToken()))
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.
ParserResult<TypeRepr> TyR = P.parseType();
if (TyR.isNull())
return true;
bindSILGenericParams(TyR.get());
// The type can be polymorphic.
GenericEnvironment *genericEnv = nullptr;
GenericParamList *genericParams = nullptr;
if (auto *fnType = dyn_cast<FunctionTypeRepr>(TyR.get())) {
genericEnv = fnType->getGenericEnvironment();
genericParams = fnType->getGenericParams();
}
const auto Ty =
performTypeResolution(TyR.get(), /*IsSILType=*/false,
genericEnv, genericParams);
if (Ty->hasError())
return true;
// Pick the ValueDecl that has the right type.
ValueDecl *TheDecl = nullptr;
auto declTy = Ty->getCanonicalType();
for (unsigned I = 0, E = values.size(); I < E; ++I) {
auto *decl = values[I];
auto lookupTy =
decl->getInterfaceType()
->removeArgumentLabels(decl->getNumCurryLevels());
if (declTy == lookupTy->getCanonicalType()) {
TheDecl = decl;
// Update SILDeclRef to point to the right Decl.
Member.loc = decl;
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;
}
bool
SILParser::parseKeyPathPatternComponent(KeyPathPatternComponent &component,
SmallVectorImpl<SILType> &operandTypes,
SourceLoc componentLoc,
Identifier componentKind,
SILLocation InstLoc,
GenericEnvironment *patternEnv,
GenericParamList *patternParams) {
auto parseComponentIndices =
[&](SmallVectorImpl<KeyPathPatternComponent::Index> &indexes) -> bool {
while (true) {
unsigned index;
CanType formalTy;
SILType loweredTy;
if (P.parseToken(tok::oper_prefix,
diag::expected_tok_in_sil_instr, "%")
|| P.parseToken(tok::sil_dollar,
diag::expected_tok_in_sil_instr, "$"))
return true;
if (!P.Tok.is(tok::integer_literal)
|| parseIntegerLiteral(P.Tok.getText(), 0, index))
return true;
P.consumeToken(tok::integer_literal);
SourceLoc formalTyLoc;
SourceLoc loweredTyLoc;
GenericEnvironment *ignoredParsedEnv = nullptr;
GenericParamList *ignoredParsedParams = nullptr;
if (P.parseToken(tok::colon,
diag::expected_tok_in_sil_instr, ":")
|| P.parseToken(tok::sil_dollar,
diag::expected_tok_in_sil_instr, "$")
|| parseASTType(formalTy, formalTyLoc,
patternEnv, patternParams)
|| P.parseToken(tok::colon,
diag::expected_tok_in_sil_instr, ":")
|| parseSILType(loweredTy, loweredTyLoc,
ignoredParsedEnv, ignoredParsedParams,
patternEnv, patternParams))
return true;
if (patternEnv)
loweredTy = SILType::getPrimitiveType(
loweredTy.getASTType()->mapTypeOutOfContext()
->getCanonicalType(),
loweredTy.getCategory());
// Formal type must be hashable.
auto proto = P.Context.getProtocol(KnownProtocolKind::Hashable);
Type contextFormalTy = formalTy;
if (patternEnv)
contextFormalTy = patternEnv->mapTypeIntoContext(formalTy);
auto lookup = P.SF.getParentModule()->lookupConformance(
contextFormalTy, proto);
if (lookup.isInvalid()) {
P.diagnose(formalTyLoc,
diag::sil_keypath_index_not_hashable,
formalTy);
return true;
}
auto conformance = ProtocolConformanceRef(lookup);
indexes.push_back({index, formalTy, loweredTy, conformance});
if (operandTypes.size() <= index)
operandTypes.resize(index+1);
if (operandTypes[index] && operandTypes[index] != loweredTy) {
P.diagnose(loweredTyLoc,
diag::sil_keypath_index_operand_type_conflict,
index,
operandTypes[index].getASTType(),
loweredTy.getASTType());
return true;
}
operandTypes[index] = loweredTy;
if (P.consumeIf(tok::comma))
continue;
if (P.consumeIf(tok::r_square))
break;
return true;
}
return false;
};
if (componentKind.str() == "stored_property") {
ValueDecl *prop;
CanType ty;
if (parseSILDottedPath(prop)
|| P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":")
|| P.parseToken(tok::sil_dollar,
diag::expected_tok_in_sil_instr, "$")
|| parseASTType(ty, patternEnv, patternParams))
return true;
component =
KeyPathPatternComponent::forStoredProperty(cast<VarDecl>(prop), ty);
return false;
} else if (componentKind.str() == "gettable_property"
|| componentKind.str() == "settable_property") {
bool isSettable = componentKind.str()[0] == 's';
CanType componentTy;
if (P.parseToken(tok::sil_dollar,diag::expected_tok_in_sil_instr,"$")
|| parseASTType(componentTy, patternEnv, patternParams)
|| P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
return true;
SILFunction *idFn = nullptr;
SILDeclRef idDecl;
VarDecl *idProperty = nullptr;
SILFunction *getter = nullptr;
SILFunction *setter = nullptr;
SILFunction *equals = nullptr;
SILFunction *hash = nullptr;
AbstractStorageDecl *externalDecl = nullptr;
SubstitutionMap externalSubs;
SmallVector<KeyPathPatternComponent::Index, 4> indexes;
while (true) {
Identifier subKind;
SourceLoc subKindLoc;
if (parseSILIdentifier(subKind, subKindLoc,
diag::sil_keypath_expected_component_kind))
return true;
if (subKind.str() == "id") {
// The identifier can be either a function ref, a SILDeclRef
// to a class or protocol method, or a decl ref to a property:
// @static_fn_ref : $...
// #Type.method!whatever : (T) -> ...
// ##Type.property
if (P.Tok.is(tok::at_sign)) {
if (parseSILFunctionRef(InstLoc, idFn))
return true;
} else if (P.Tok.is(tok::pound)) {
if (P.peekToken().is(tok::pound)) {
ValueDecl *propertyValueDecl;
P.consumeToken(tok::pound);
if (parseSILDottedPath(propertyValueDecl))
return true;
idProperty = cast<VarDecl>(propertyValueDecl);
} else if (parseSILDeclRef(idDecl, /*fnType*/ true))
return true;
} else {
P.diagnose(subKindLoc, diag::expected_tok_in_sil_instr, "# or @");
return true;
}
} else if (subKind.str() == "getter" || subKind.str() == "setter") {
bool isSetter = subKind.str()[0] == 's';
if (parseSILFunctionRef(InstLoc, isSetter ? setter : getter))
return true;
} else if (subKind.str() == "indices") {
if (P.parseToken(tok::l_square,
diag::expected_tok_in_sil_instr, "[")
|| parseComponentIndices(indexes))
return true;
} else if (subKind.str() == "indices_equals") {
if (parseSILFunctionRef(InstLoc, equals))
return true;
} else if (subKind.str() == "indices_hash") {
if (parseSILFunctionRef(InstLoc, hash))
return true;
} else if (subKind.str() == "external") {
ValueDecl *parsedExternalDecl;
SmallVector<ParsedSubstitution, 4> parsedSubs;
if (parseSILDottedPath(parsedExternalDecl)
|| parseSubstitutions(parsedSubs, patternEnv, patternParams))
return true;
externalDecl = cast<AbstractStorageDecl>(parsedExternalDecl);
if (!parsedSubs.empty()) {
auto genericEnv = externalDecl->getInnermostDeclContext()
->getGenericEnvironmentOfContext();
if (!genericEnv) {
P.diagnose(P.Tok,
diag::sil_substitutions_on_non_polymorphic_type);
return true;
}
externalSubs = getApplySubstitutionsFromParsed(*this, genericEnv,
parsedSubs);
if (!externalSubs) return true;
// Map the substitutions out of the pattern context so that they
// use interface types.
externalSubs =
externalSubs.mapReplacementTypesOutOfContext().getCanonical();
}
} else {
P.diagnose(subKindLoc, diag::sil_keypath_unknown_component_kind,
subKind);
return true;
}
if (!P.consumeIf(tok::comma))
break;
}
if ((idFn == nullptr && idDecl.isNull() && idProperty == nullptr)
|| getter == nullptr
|| (isSettable && setter == nullptr)) {
P.diagnose(componentLoc,
diag::sil_keypath_computed_property_missing_part,
isSettable);
return true;
}
if ((idFn != nullptr) + (!idDecl.isNull()) + (idProperty != nullptr)
!= 1) {
P.diagnose(componentLoc,
diag::sil_keypath_computed_property_missing_part,
isSettable);
return true;
}
KeyPathPatternComponent::ComputedPropertyId id;
if (idFn)
id = idFn;
else if (!idDecl.isNull())
id = idDecl;
else if (idProperty)
id = idProperty;
else
llvm_unreachable("no id?!");
auto indexesCopy = P.Context.AllocateCopy(indexes);
if (!indexes.empty() && (!equals || !hash)) {
P.diagnose(componentLoc,
diag::sil_keypath_computed_property_missing_part,
isSettable);
}
if (isSettable) {
component = KeyPathPatternComponent::forComputedSettableProperty(
id, getter, setter,
indexesCopy, equals, hash,
externalDecl, externalSubs, componentTy);
} else {
component = KeyPathPatternComponent::forComputedGettableProperty(
id, getter,
indexesCopy, equals, hash,
externalDecl, externalSubs, componentTy);
}
return false;
} else if (componentKind.str() == "optional_wrap"
|| componentKind.str() == "optional_chain"
|| componentKind.str() == "optional_force") {
CanType ty;
if (P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":")
|| P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$")
|| parseASTType(ty, patternEnv, patternParams))
return true;
KeyPathPatternComponent::Kind kind;
if (componentKind.str() == "optional_wrap") {
kind = KeyPathPatternComponent::Kind::OptionalWrap;
} else if (componentKind.str() == "optional_chain") {
kind = KeyPathPatternComponent::Kind::OptionalChain;
} else if (componentKind.str() == "optional_force") {
kind = KeyPathPatternComponent::Kind::OptionalForce;
} else {
llvm_unreachable("unpossible");
}
component = KeyPathPatternComponent::forOptional(kind, ty);
return false;
} else if (componentKind.str() == "tuple_element") {
unsigned tupleIndex;
CanType ty;
if (P.parseToken(tok::pound, diag::expected_sil_constant)
|| parseInteger(tupleIndex, diag::expected_sil_tuple_index)
|| P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":")
|| P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$")
|| parseASTType(ty, patternEnv, patternParams))
return true;
component = KeyPathPatternComponent::forTupleElement(tupleIndex, ty);
return false;
} else {
P.diagnose(componentLoc, diag::sil_keypath_unknown_component_kind,
componentKind);
return true;
}
}
bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
SILInstructionKind Opcode,
SourceLoc OpcodeLoc,
StringRef OpcodeName,
SILInstruction *&ResultVal) {
SmallVector<SILValue, 4> OpList;
SILValue Val;
SILType Ty;
SILLocation InstLoc = RegularLocation(OpcodeLoc);
auto parseFormalTypeAndValue = [&](CanType &formalType,
SILValue &value) -> bool {
return (parseASTType(formalType) || parseVerbatim("in")
|| parseTypedValueRef(value, B));
};
OpenedExistentialAccess AccessKind;
auto parseOpenExistAddrKind = [&]() -> bool {
Identifier accessKindToken;
SourceLoc accessKindLoc;
if (parseSILIdentifier(accessKindToken, accessKindLoc,
diag::expected_tok_in_sil_instr,
"opened existential access kind")) {
return true;
}
auto kind =
llvm::StringSwitch<Optional<OpenedExistentialAccess>>(
accessKindToken.str())
.Case("mutable_access", OpenedExistentialAccess::Mutable)
.Case("immutable_access", OpenedExistentialAccess::Immutable)
.Default(None);
if (kind) {
AccessKind = kind.getValue();
return false;
}
P.diagnose(accessKindLoc, diag::expected_tok_in_sil_instr,
"opened existential access kind");
return true;
};
CanType SourceType, TargetType;
SILValue SourceAddr, DestAddr;
auto parseSourceAndDestAddress = [&] {
return parseFormalTypeAndValue(SourceType, SourceAddr) ||
parseVerbatim("to") || parseFormalTypeAndValue(TargetType, DestAddr);
};
Identifier SuccessBBName, FailureBBName;
SourceLoc SuccessBBLoc, FailureBBLoc;
auto parseConditionalBranchDestinations = [&] {
return 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);
};
// Validate the opcode name, and do opcode-specific parsing logic based on the
// opcode we find.
switch (Opcode) {
case SILInstructionKind::AllocBoxInst: {
bool hasDynamicLifetime = false;
if (parseSILOptional(hasDynamicLifetime, *this, "dynamic_lifetime"))
return true;
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<SILBoxType>(), VarInfo,
hasDynamicLifetime);
break;
}
case SILInstructionKind::ApplyInst:
case SILInstructionKind::BeginApplyInst:
case SILInstructionKind::PartialApplyInst:
case SILInstructionKind::TryApplyInst:
if (parseCallInstruction(InstLoc, Opcode, B, ResultVal))
return true;
break;
case SILInstructionKind::AbortApplyInst:
case SILInstructionKind::EndApplyInst: {
UnresolvedValueName argName;
if (parseValueName(argName))
return true;
if (parseSILDebugLocation(InstLoc, B))
return true;
SILType expectedTy = SILType::getSILTokenType(P.Context);
SILValue op = getLocalValue(argName, expectedTy, InstLoc, B);
if (Opcode == SILInstructionKind::AbortApplyInst) {
ResultVal = B.createAbortApply(InstLoc, op);
} else {
ResultVal = B.createEndApply(InstLoc, op);
}
break;
}
case SILInstructionKind::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<AnyBuiltinIntegerType>();
if (!intTy) {
P.diagnose(P.Tok, diag::sil_integer_literal_not_integer_type);
return true;
}
StringRef text = prepareIntegerLiteralForParsing(P.Tok.getText());
bool error;
APInt value = intTy->getWidth().parse(text, 0, Negative, &error);
if (error) {
P.diagnose(P.Tok, diag::sil_integer_literal_not_well_formed, intTy);
return true;
}
P.consumeToken(tok::integer_literal);
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createIntegerLiteral(InstLoc, Ty, value);
break;
}
case SILInstructionKind::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<BuiltinFloatType>();
if (!floatTy) {
P.diagnose(P.Tok, diag::sil_float_literal_not_float_type);
return true;
}
StringRef text = prepareIntegerLiteralForParsing(P.Tok.getText());
APInt bits(floatTy->getBitWidth(), 0);
bool error = text.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 SILInstructionKind::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() == "objc_selector") {
encoding = StringLiteralInst::Encoding::ObjCSelector;
} else if (P.Tok.getText() == "bytes") {
encoding = StringLiteralInst::Encoding::Bytes;
} 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;
}
// Parse the string.
SmallVector<Lexer::StringSegment, 1> segments;
P.L->getStringLiteralSegments(P.Tok, segments);
assert(segments.size() == 1);
P.consumeToken(tok::string_literal);
if (parseSILDebugLocation(InstLoc, B))
return true;
SmallVector<char, 128> stringBuffer;
if (encoding == StringLiteralInst::Encoding::Bytes) {
// Decode hex bytes.
CharSourceRange rawStringRange(segments.front().Loc,
segments.front().Length);
StringRef rawString = P.SourceMgr.extractText(rawStringRange);
if (rawString.size() & 1) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr,
"even number of hex bytes");
return true;
}
while (!rawString.empty()) {
unsigned byte1 = llvm::hexDigitValue(rawString[0]);
unsigned byte2 = llvm::hexDigitValue(rawString[1]);
if (byte1 == -1U || byte2 == -1U) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr,
"hex bytes should contain 0-9, a-f, A-F only");
return true;
}
stringBuffer.push_back((unsigned char)(byte1 << 4) | byte2);
rawString = rawString.drop_front(2);
}
ResultVal = B.createStringLiteral(InstLoc, stringBuffer, encoding);
break;
}
StringRef string =
P.L->getEncodedStringSegment(segments.front(), stringBuffer);
ResultVal = B.createStringLiteral(InstLoc, string, encoding);
break;
}
case SILInstructionKind::CondFailInst: {
if (parseTypedValueRef(Val, B))
return true;
SmallVector<char, 128> stringBuffer;
StringRef message;
if (P.consumeIf(tok::comma)) {
// Parse the string.
if (P.Tok.getKind() != tok::string_literal) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "string");
return true;
}
SmallVector<Lexer::StringSegment, 1> segments;
P.L->getStringLiteralSegments(P.Tok, segments);
assert(segments.size() == 1);
P.consumeToken(tok::string_literal);
message = P.L->getEncodedStringSegment(segments.front(), stringBuffer);
}
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createCondFail(InstLoc, Val, message);
break;
}
case SILInstructionKind::AllocValueBufferInst: {
SILType Ty;
if (parseSILType(Ty) || parseVerbatim("in") || parseTypedValueRef(Val, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createAllocValueBuffer(InstLoc, Ty, Val);
break;
}
case SILInstructionKind::ProjectValueBufferInst: {
SILType Ty;
if (parseSILType(Ty) || parseVerbatim("in") || parseTypedValueRef(Val, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createProjectValueBuffer(InstLoc, Ty, Val);
break;
}
case SILInstructionKind::DeallocValueBufferInst: {
SILType Ty;
if (parseSILType(Ty) || parseVerbatim("in") || parseTypedValueRef(Val, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDeallocValueBuffer(InstLoc, Ty, Val);
break;
}
case SILInstructionKind::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 = parseIntegerLiteral(P.Tok.getText(), 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 SILInstructionKind::ProjectExistentialBoxInst: {
SILType Ty;
if (parseSILType(Ty) || parseVerbatim("in") || parseTypedValueRef(Val, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createProjectExistentialBox(InstLoc, Ty, Val);
break;
}
case SILInstructionKind::FunctionRefInst: {
SILFunction *Fn;
if (parseSILFunctionRef(InstLoc, Fn) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createFunctionRef(InstLoc, Fn);
break;
}
case SILInstructionKind::DynamicFunctionRefInst: {
SILFunction *Fn;
if (parseSILFunctionRef(InstLoc, Fn) || parseSILDebugLocation(InstLoc, B))
return true;
// Set a forward reference's dynamic property for the first time.
if (!Fn->isDynamicallyReplaceable()) {
if (!Fn->empty()) {
P.diagnose(P.Tok, diag::expected_dynamic_func_attr);
return true;
}
Fn->setIsDynamic();
}
ResultVal = B.createDynamicFunctionRef(InstLoc, Fn);
break;
}
case SILInstructionKind::PreviousDynamicFunctionRefInst: {
SILFunction *Fn;
if (parseSILFunctionRef(InstLoc, Fn) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createPreviousDynamicFunctionRef(InstLoc, Fn);
break;
}
case SILInstructionKind::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<ValueDecl *, 2> 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<FuncDecl>(foundBuiltins[0]);
GenericEnvironment *genericEnv = builtinFunc->getGenericEnvironment();
SmallVector<ParsedSubstitution, 4> parsedSubs;
SubstitutionMap subMap;
if (parseSubstitutions(parsedSubs))
return true;
if (!parsedSubs.empty()) {
if (!genericEnv) {
P.diagnose(P.Tok, diag::sil_substitutions_on_non_polymorphic_type);
return true;
}
subMap = getApplySubstitutionsFromParsed(*this, genericEnv, parsedSubs);
if (!subMap)
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<SILValue, 4> 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, subMap, Args);
break;
}
case SILInstructionKind::OpenExistentialAddrInst:
if (parseOpenExistAddrKind() || parseTypedValueRef(Val, B) ||
parseVerbatim("to") || parseSILType(Ty) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createOpenExistentialAddr(InstLoc, Val, Ty, AccessKind);
break;
case SILInstructionKind::OpenExistentialBoxInst:
if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createOpenExistentialBox(InstLoc, Val, Ty);
break;
case SILInstructionKind::OpenExistentialBoxValueInst:
if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createOpenExistentialBoxValue(InstLoc, Val, Ty);
break;
case SILInstructionKind::OpenExistentialMetatypeInst:
if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createOpenExistentialMetatype(InstLoc, Val, Ty);
break;
case SILInstructionKind::OpenExistentialRefInst:
if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createOpenExistentialRef(InstLoc, Val, Ty);
break;
case SILInstructionKind::OpenExistentialValueInst:
if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createOpenExistentialValue(InstLoc, Val, Ty);
break;
#define UNARY_INSTRUCTION(ID) \
case SILInstructionKind::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 SILInstructionKind::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(ClassifyBridgeObject)
UNARY_INSTRUCTION(ValueToBridgeObject)
UNARY_INSTRUCTION(FixLifetime)
UNARY_INSTRUCTION(EndLifetime)
UNARY_INSTRUCTION(CopyBlock)
UNARY_INSTRUCTION(IsUnique)
UNARY_INSTRUCTION(DestroyAddr)
UNARY_INSTRUCTION(CopyValue)
UNARY_INSTRUCTION(DestroyValue)
UNARY_INSTRUCTION(EndBorrow)
UNARY_INSTRUCTION(DestructureStruct)
UNARY_INSTRUCTION(DestructureTuple)
UNARY_INSTRUCTION(HopToExecutor)
REFCOUNTING_INSTRUCTION(UnmanagedReleaseValue)
REFCOUNTING_INSTRUCTION(UnmanagedRetainValue)
REFCOUNTING_INSTRUCTION(UnmanagedAutoreleaseValue)
REFCOUNTING_INSTRUCTION(StrongRetain)
REFCOUNTING_INSTRUCTION(StrongRelease)
REFCOUNTING_INSTRUCTION(AutoreleaseValue)
REFCOUNTING_INSTRUCTION(SetDeallocating)
REFCOUNTING_INSTRUCTION(ReleaseValue)
REFCOUNTING_INSTRUCTION(RetainValue)
REFCOUNTING_INSTRUCTION(ReleaseValueAddr)
REFCOUNTING_INSTRUCTION(RetainValueAddr)
#define UNCHECKED_REF_STORAGE(Name, ...) \
UNARY_INSTRUCTION(StrongCopy##Name##Value)
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
REFCOUNTING_INSTRUCTION(StrongRetain##Name) \
REFCOUNTING_INSTRUCTION(Name##Retain) \
REFCOUNTING_INSTRUCTION(Name##Release) \
UNARY_INSTRUCTION(StrongCopy##Name##Value)
#include "swift/AST/ReferenceStorage.def"
#undef UNARY_INSTRUCTION
#undef REFCOUNTING_INSTRUCTION
case SILInstructionKind::BeginCOWMutationInst: {
bool native = false;
if (parseSILOptional(native, *this, "native") ||
parseTypedValueRef(Val, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createBeginCOWMutation(InstLoc, Val, native);
break;
}
case SILInstructionKind::EndCOWMutationInst: {
bool keepUnique = false;
if (parseSILOptional(keepUnique, *this, "keep_unique") ||
parseTypedValueRef(Val, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createEndCOWMutation(InstLoc, Val, keepUnique);
break;
}
case SILInstructionKind::IsEscapingClosureInst: {
bool IsObjcVerifcationType = false;
if (parseSILOptional(IsObjcVerifcationType, *this, "objc"))
return true;
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createIsEscapingClosure(
InstLoc, Val,
IsObjcVerifcationType ? IsEscapingClosureInst::ObjCEscaping
: IsEscapingClosureInst::WithoutActuallyEscaping);
break;
}
case SILInstructionKind::DebugValueInst:
case SILInstructionKind::DebugValueAddrInst: {
SILDebugVariable VarInfo;
if (parseTypedValueRef(Val, B) || parseSILDebugVar(VarInfo) ||
parseSILDebugLocation(InstLoc, B))
return true;
if (Opcode == SILInstructionKind::DebugValueInst)
ResultVal = B.createDebugValue(InstLoc, Val, VarInfo);
else
ResultVal = B.createDebugValueAddr(InstLoc, Val, VarInfo);
break;
}
// unchecked_ownership_conversion <reg> : <type>, <ownership> to <ownership>
case SILInstructionKind::UncheckedOwnershipConversionInst: {
ValueOwnershipKind LHSKind = OwnershipKind::None;
ValueOwnershipKind RHSKind = OwnershipKind::None;
SourceLoc Loc;
if (parseTypedValueRef(Val, Loc, B) ||
P.parseToken(tok::comma, diag::expected_sil_colon,
"unchecked_ownership_conversion value ownership kind "
"conversion specification") ||
parseSILOwnership(LHSKind) || parseVerbatim("to") ||
parseSILOwnership(RHSKind) || parseSILDebugLocation(InstLoc, B)) {
return true;
}
if (Val.getOwnershipKind() != LHSKind) {
return true;
}
ResultVal = B.createUncheckedOwnershipConversion(InstLoc, Val, RHSKind);
break;
}
case SILInstructionKind::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 SILInstructionKind::LoadBorrowInst: {
SourceLoc AddrLoc;
if (parseTypedValueRef(Val, AddrLoc, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createLoadBorrow(InstLoc, Val);
break;
}
case SILInstructionKind::BeginBorrowInst: {
SourceLoc AddrLoc;
if (parseTypedValueRef(Val, AddrLoc, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createBeginBorrow(InstLoc, Val);
break;
}
#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
case SILInstructionKind::Load##Name##Inst: { \
bool isTake = false; \
SourceLoc addrLoc; \
if (parseSILOptional(isTake, *this, "take") || \
parseTypedValueRef(Val, addrLoc, B) || \
parseSILDebugLocation(InstLoc, B)) \
return true; \
if (!Val->getType().is<Name##StorageType>()) { \
P.diagnose(addrLoc, diag::sil_operand_not_ref_storage_address, "source", \
OpcodeName, ReferenceOwnership::Name); \
} \
ResultVal = B.createLoad##Name(InstLoc, Val, IsTake_t(isTake)); \
break; \
}
#include "swift/AST/ReferenceStorage.def"
case SILInstructionKind::CopyBlockWithoutEscapingInst: {
SILValue Closure;
if (parseTypedValueRef(Val, B) || parseVerbatim("withoutEscaping") ||
parseTypedValueRef(Closure, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createCopyBlockWithoutEscaping(InstLoc, Val, Closure);
break;
}
case SILInstructionKind::MarkDependenceInst: {
SILValue Base;
if (parseTypedValueRef(Val, B) || parseVerbatim("on") ||
parseTypedValueRef(Base, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createMarkDependence(InstLoc, Val, Base);
break;
}
case SILInstructionKind::KeyPathInst: {
SmallVector<KeyPathPatternComponent, 4> components;
SILType Ty;
if (parseSILType(Ty) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
return true;
GenericParamList *patternParams = nullptr;
GenericEnvironment *patternEnv = nullptr;
CanType rootType;
StringRef objcString;
SmallVector<SILType, 4> operandTypes;
{
patternParams = P.maybeParseGenericParams().getPtrOrNull();
patternEnv = handleSILGenericParams(patternParams, &P.SF);
if (P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "("))
return true;
while (true) {
Identifier componentKind;
SourceLoc componentLoc;
if (parseSILIdentifier(componentKind, componentLoc,
diag::sil_keypath_expected_component_kind))
return true;
if (componentKind.str() == "root") {
if (P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr,
"$") ||
parseASTType(rootType, patternEnv, patternParams))
return true;
} else if (componentKind.str() == "objc") {
auto tok = P.Tok;
if (P.parseToken(tok::string_literal, diag::expected_tok_in_sil_instr,
"string literal"))
return true;
auto objcStringValue = tok.getText().drop_front().drop_back();
objcString =
StringRef(P.Context.AllocateCopy<char>(objcStringValue.begin(),
objcStringValue.end()),
objcStringValue.size());
} else {
KeyPathPatternComponent component;
if (parseKeyPathPatternComponent(component, operandTypes,
componentLoc, componentKind, InstLoc,
patternEnv, patternParams))
return true;
components.push_back(component);
}
if (!P.consumeIf(tok::semi))
break;
}
if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")") ||
parseSILDebugLocation(InstLoc, B))
return true;
}
if (rootType.isNull())
P.diagnose(InstLoc.getSourceLoc(), diag::sil_keypath_no_root);
SmallVector<ParsedSubstitution, 4> parsedSubs;
if (parseSubstitutions(parsedSubs, ContextGenericEnv, ContextGenericParams))
return true;
SubstitutionMap subMap;
if (!parsedSubs.empty()) {
if (!patternEnv) {
P.diagnose(InstLoc.getSourceLoc(),
diag::sil_substitutions_on_non_polymorphic_type);
return true;
}
subMap = getApplySubstitutionsFromParsed(*this, patternEnv, parsedSubs);
if (!subMap)
return true;
}
SmallVector<SILValue, 4> operands;
if (P.consumeIf(tok::l_paren)) {
while (true) {
SILValue v;
if (operands.size() >= operandTypes.size() ||
!operandTypes[operands.size()]) {
P.diagnose(P.Tok, diag::sil_keypath_no_use_of_operand_in_pattern,
operands.size());
return true;
}
auto ty = operandTypes[operands.size()].subst(SILMod, subMap);
if (parseValueRef(v, ty, RegularLocation(P.Tok.getLoc()), B))
return true;
operands.push_back(v);
if (P.consumeIf(tok::comma))
continue;
if (P.consumeIf(tok::r_paren))
break;
return true;
}
}
if (parseSILDebugLocation(InstLoc, B))
return true;
CanGenericSignature canSig;
if (patternEnv && patternEnv->getGenericSignature()) {
canSig = patternEnv->getGenericSignature().getCanonicalSignature();
}
CanType leafType;
if (!components.empty())
leafType = components.back().getComponentType();
else
leafType = rootType;
auto pattern = KeyPathPattern::get(B.getModule(), canSig, rootType,
leafType, components, objcString);
ResultVal = B.createKeyPath(InstLoc, pattern, subMap, operands, Ty);
break;
}
// Conversion instructions.
case SILInstructionKind::UncheckedRefCastInst:
case SILInstructionKind::UncheckedAddrCastInst:
case SILInstructionKind::UncheckedTrivialBitCastInst:
case SILInstructionKind::UncheckedBitwiseCastInst:
case SILInstructionKind::UncheckedValueCastInst:
case SILInstructionKind::UpcastInst:
case SILInstructionKind::AddressToPointerInst:
case SILInstructionKind::BridgeObjectToRefInst:
case SILInstructionKind::BridgeObjectToWordInst:
case SILInstructionKind::RefToRawPointerInst:
case SILInstructionKind::RawPointerToRefInst:
#define LOADABLE_REF_STORAGE(Name, ...) \
case SILInstructionKind::RefTo##Name##Inst: \
case SILInstructionKind::Name##ToRefInst:
#include "swift/AST/ReferenceStorage.def"
case SILInstructionKind::ThinFunctionToPointerInst:
case SILInstructionKind::PointerToThinFunctionInst:
case SILInstructionKind::ThinToThickFunctionInst:
case SILInstructionKind::ThickToObjCMetatypeInst:
case SILInstructionKind::ObjCToThickMetatypeInst:
case SILInstructionKind::ConvertFunctionInst:
case SILInstructionKind::ConvertEscapeToNoEscapeInst:
case SILInstructionKind::ObjCExistentialMetatypeToObjectInst:
case SILInstructionKind::ObjCMetatypeToObjectInst: {
SILType Ty;
Identifier ToToken;
SourceLoc ToLoc;
bool not_guaranteed = false;
bool without_actually_escaping = false;
if (Opcode == SILInstructionKind::ConvertEscapeToNoEscapeInst) {
StringRef attrName;
if (parseSILOptional(attrName, *this)) {
if (attrName.equals("not_guaranteed"))
not_guaranteed = true;
else
return true;
}
}
if (parseTypedValueRef(Val, B) ||
parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr,
"to"))
return true;
if (ToToken.str() != "to") {
P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to");
return true;
}
if (Opcode == SILInstructionKind::ConvertFunctionInst) {
StringRef attrName;
if (parseSILOptional(attrName, *this)) {
if (attrName.equals("without_actually_escaping"))
without_actually_escaping = true;
else
return true;
}
}
if (parseSILType(Ty) || parseSILDebugLocation(InstLoc, B))
return true;
switch (Opcode) {
default:
llvm_unreachable("Out of sync with parent switch");
case SILInstructionKind::UncheckedRefCastInst:
ResultVal = B.createUncheckedRefCast(InstLoc, Val, Ty);
break;
case SILInstructionKind::UncheckedAddrCastInst:
ResultVal = B.createUncheckedAddrCast(InstLoc, Val, Ty);
break;
case SILInstructionKind::UncheckedTrivialBitCastInst:
ResultVal = B.createUncheckedTrivialBitCast(InstLoc, Val, Ty);
break;
case SILInstructionKind::UncheckedBitwiseCastInst:
ResultVal = B.createUncheckedBitwiseCast(InstLoc, Val, Ty);
break;
case SILInstructionKind::UncheckedValueCastInst:
ResultVal = B.createUncheckedValueCast(InstLoc, Val, Ty);
break;
case SILInstructionKind::UpcastInst:
ResultVal = B.createUpcast(InstLoc, Val, Ty);
break;
case SILInstructionKind::ConvertFunctionInst:
ResultVal =
B.createConvertFunction(InstLoc, Val, Ty, without_actually_escaping);
break;
case SILInstructionKind::ConvertEscapeToNoEscapeInst:
ResultVal =
B.createConvertEscapeToNoEscape(InstLoc, Val, Ty, !not_guaranteed);
break;
case SILInstructionKind::AddressToPointerInst:
ResultVal = B.createAddressToPointer(InstLoc, Val, Ty);
break;
case SILInstructionKind::BridgeObjectToRefInst:
ResultVal = B.createBridgeObjectToRef(InstLoc, Val, Ty);
break;
case SILInstructionKind::BridgeObjectToWordInst:
ResultVal = B.createBridgeObjectToWord(InstLoc, Val);
break;
case SILInstructionKind::RefToRawPointerInst:
ResultVal = B.createRefToRawPointer(InstLoc, Val, Ty);
break;
case SILInstructionKind::RawPointerToRefInst:
ResultVal = B.createRawPointerToRef(InstLoc, Val, Ty);
break;
#define LOADABLE_REF_STORAGE(Name, ...) \
case SILInstructionKind::RefTo##Name##Inst: \
ResultVal = B.createRefTo##Name(InstLoc, Val, Ty); \
break; \
case SILInstructionKind::Name##ToRefInst: \
ResultVal = B.create##Name##ToRef(InstLoc, Val, Ty); \
break;
#include "swift/AST/ReferenceStorage.def"
case SILInstructionKind::ThinFunctionToPointerInst:
ResultVal = B.createThinFunctionToPointer(InstLoc, Val, Ty);
break;
case SILInstructionKind::PointerToThinFunctionInst:
ResultVal = B.createPointerToThinFunction(InstLoc, Val, Ty);
break;
case SILInstructionKind::ThinToThickFunctionInst:
ResultVal = B.createThinToThickFunction(InstLoc, Val, Ty);
break;
case SILInstructionKind::ThickToObjCMetatypeInst:
ResultVal = B.createThickToObjCMetatype(InstLoc, Val, Ty);
break;
case SILInstructionKind::ObjCToThickMetatypeInst:
ResultVal = B.createObjCToThickMetatype(InstLoc, Val, Ty);
break;
case SILInstructionKind::ObjCMetatypeToObjectInst:
ResultVal = B.createObjCMetatypeToObject(InstLoc, Val, Ty);
break;
case SILInstructionKind::ObjCExistentialMetatypeToObjectInst:
ResultVal = B.createObjCExistentialMetatypeToObject(InstLoc, Val, Ty);
break;
}
break;
}
case SILInstructionKind::PointerToAddressInst: {
SILType Ty;
Identifier ToToken;
SourceLoc ToLoc;
StringRef attr;
if (parseTypedValueRef(Val, B) ||
parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr,
"to"))
return true;
if (parseSILOptional(attr, *this) && attr.empty())
return true;
if (parseSILType(Ty) || parseSILDebugLocation(InstLoc, B))
return true;
bool isStrict = attr.equals("strict");
bool isInvariant = attr.equals("invariant");
if (ToToken.str() != "to") {
P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to");
return true;
}
ResultVal =
B.createPointerToAddress(InstLoc, Val, Ty, isStrict, isInvariant);
break;
}
case SILInstructionKind::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;
}
case SILInstructionKind::CheckedCastAddrBranchInst: {
Identifier consumptionKindToken;
SourceLoc consumptionKindLoc;
if (parseSILIdentifier(consumptionKindToken, consumptionKindLoc,
diag::expected_tok_in_sil_instr,
"cast consumption kind")) {
return true;
}
// NOTE: BorrowAlways is not a supported cast kind for address types, so we
// purposely do not parse it here.
auto kind = llvm::StringSwitch<Optional<CastConsumptionKind>>(
consumptionKindToken.str())
.Case("take_always", CastConsumptionKind::TakeAlways)
.Case("take_on_success", CastConsumptionKind::TakeOnSuccess)
.Case("copy_on_success", CastConsumptionKind::CopyOnSuccess)
.Default(None);
if (!kind) {
P.diagnose(consumptionKindLoc, diag::expected_tok_in_sil_instr,
"cast consumption kind");
return true;
}
auto consumptionKind = kind.getValue();
if (parseSourceAndDestAddress() || parseConditionalBranchDestinations() ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createCheckedCastAddrBranch(
InstLoc, consumptionKind, SourceAddr, SourceType, DestAddr, TargetType,
getBBForReference(SuccessBBName, SuccessBBLoc),
getBBForReference(FailureBBName, FailureBBLoc));
break;
}
case SILInstructionKind::UncheckedRefCastAddrInst:
if (parseSourceAndDestAddress() || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createUncheckedRefCastAddr(InstLoc, SourceAddr, SourceType,
DestAddr, TargetType);
break;
case SILInstructionKind::UnconditionalCheckedCastAddrInst:
if (parseSourceAndDestAddress() || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createUnconditionalCheckedCastAddr(
InstLoc, SourceAddr, SourceType, DestAddr, TargetType);
break;
case SILInstructionKind::UnconditionalCheckedCastValueInst: {
if (parseASTType(SourceType) || parseVerbatim("in") ||
parseTypedValueRef(Val, B) || parseVerbatim("to") ||
parseASTType(TargetType) || parseSILDebugLocation(InstLoc, B))
return true;
auto opaque = Lowering::AbstractionPattern::getOpaque();
ResultVal = B.createUnconditionalCheckedCastValue(
InstLoc, Val, SourceType, F->getLoweredType(opaque, TargetType),
TargetType);
break;
}
case SILInstructionKind::UnconditionalCheckedCastInst: {
if (parseTypedValueRef(Val, B) || parseVerbatim("to") ||
parseASTType(TargetType))
return true;
if (parseSILDebugLocation(InstLoc, B))
return true;
auto opaque = Lowering::AbstractionPattern::getOpaque();
ResultVal = B.createUnconditionalCheckedCast(
InstLoc, Val, F->getLoweredType(opaque, TargetType), TargetType);
break;
}
case SILInstructionKind::CheckedCastBranchInst: {
bool isExact = false;
if (Opcode == SILInstructionKind::CheckedCastBranchInst &&
parseSILOptional(isExact, *this, "exact"))
return true;
if (parseTypedValueRef(Val, B) || parseVerbatim("to") ||
parseASTType(TargetType) || parseConditionalBranchDestinations())
return true;
auto opaque = Lowering::AbstractionPattern::getOpaque();
ResultVal = B.createCheckedCastBranch(
InstLoc, isExact, Val, F->getLoweredType(opaque, TargetType),
TargetType, getBBForReference(SuccessBBName, SuccessBBLoc),
getBBForReference(FailureBBName, FailureBBLoc));
break;
}
case SILInstructionKind::CheckedCastValueBranchInst: {
if (parseASTType(SourceType) || parseVerbatim("in") ||
parseTypedValueRef(Val, B) || parseVerbatim("to") ||
parseASTType(TargetType) || parseConditionalBranchDestinations())
return true;
auto opaque = Lowering::AbstractionPattern::getOpaque();
ResultVal = B.createCheckedCastValueBranch(
InstLoc, Val, SourceType, F->getLoweredType(opaque, TargetType),
TargetType, getBBForReference(SuccessBBName, SuccessBBLoc),
getBBForReference(FailureBBName, FailureBBLoc));
break;
}
case SILInstructionKind::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, /*diagnoseDollarPrefix=*/false,
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() == "crossmodulerootself")
Kind = MarkUninitializedInst::CrossModuleRootSelf;
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 if (KindId.str() == "delegatingselfallocated")
Kind = MarkUninitializedInst::DelegatingSelfAllocated;
else {
P.diagnose(KindLoc, diag::expected_tok_in_sil_instr,
"var, rootself, crossmodulerootself, derivedself, "
"derivedselfonly, delegatingself, or delegatingselfallocated");
return true;
}
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createMarkUninitialized(InstLoc, Val, Kind);
break;
}
case SILInstructionKind::MarkFunctionEscapeInst: {
SmallVector<SILValue, 4> 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 SILInstructionKind::AssignInst:
case SILInstructionKind::StoreInst: {
UnresolvedValueName From;
SourceLoc ToLoc, AddrLoc;
Identifier ToToken;
SILValue AddrVal;
StoreOwnershipQualifier StoreQualifier;
AssignOwnershipQualifier AssignQualifier;
bool IsStore = Opcode == SILInstructionKind::StoreInst;
bool IsAssign = Opcode == SILInstructionKind::AssignInst;
if (parseValueName(From) ||
parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr,
"to"))
return true;
if (IsStore && parseStoreOwnershipQualifier(StoreQualifier, *this))
return true;
if (IsAssign && parseAssignOwnershipQualifier(AssignQualifier, *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();
if (IsStore) {
ResultVal =
B.createStore(InstLoc, getLocalValue(From, ValType, InstLoc, B),
AddrVal, StoreQualifier);
} else {
assert(IsAssign);
ResultVal =
B.createAssign(InstLoc, getLocalValue(From, ValType, InstLoc, B),
AddrVal, AssignQualifier);
}
break;
}
case SILInstructionKind::AssignByWrapperInst: {
SILValue Src, DestAddr, InitFn, SetFn;
SourceLoc DestLoc;
AssignOwnershipQualifier AssignQualifier;
if (parseTypedValueRef(Src, B) || parseVerbatim("to") ||
parseAssignOwnershipQualifier(AssignQualifier, *this) ||
parseTypedValueRef(DestAddr, DestLoc, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseVerbatim("init") || parseTypedValueRef(InitFn, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseVerbatim("set") || parseTypedValueRef(SetFn, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
if (!DestAddr->getType().isAddress()) {
P.diagnose(DestLoc, diag::sil_operand_not_address, "destination",
OpcodeName);
return true;
}
ResultVal = B.createAssignByWrapper(InstLoc, Src, DestAddr, InitFn, SetFn,
AssignQualifier);
break;
}
case SILInstructionKind::BeginAccessInst:
case SILInstructionKind::BeginUnpairedAccessInst:
case SILInstructionKind::EndAccessInst:
case SILInstructionKind::EndUnpairedAccessInst: {
ParsedEnum<SILAccessKind> kind;
ParsedEnum<SILAccessEnforcement> enforcement;
ParsedEnum<bool> aborting;
ParsedEnum<bool> noNestedConflict;
ParsedEnum<bool> fromBuiltin;
bool isBeginAccess =
(Opcode == SILInstructionKind::BeginAccessInst ||
Opcode == SILInstructionKind::BeginUnpairedAccessInst);
bool wantsEnforcement =
(isBeginAccess || Opcode == SILInstructionKind::EndUnpairedAccessInst);
while (P.consumeIf(tok::l_square)) {
Identifier ident;
SourceLoc identLoc;
if (parseSILIdentifier(ident, identLoc,
diag::expected_in_attribute_list)) {
if (P.consumeIf(tok::r_square)) {
continue;
} else {
return true;
}
}
StringRef attr = ident.str();
auto setEnforcement = [&](SILAccessEnforcement value) {
maybeSetEnum(wantsEnforcement, enforcement, value, attr, identLoc);
};
auto setKind = [&](SILAccessKind value) {
maybeSetEnum(isBeginAccess, kind, value, attr, identLoc);
};
auto setAborting = [&](bool value) {
maybeSetEnum(!isBeginAccess, aborting, value, attr, identLoc);
};
auto setNoNestedConflict = [&](bool value) {
maybeSetEnum(isBeginAccess, noNestedConflict, value, attr, identLoc);
};
auto setFromBuiltin = [&](bool value) {
maybeSetEnum(Opcode != SILInstructionKind::EndAccessInst, fromBuiltin,
value, attr, identLoc);
};
if (attr == "unknown") {
setEnforcement(SILAccessEnforcement::Unknown);
} else if (attr == "static") {
setEnforcement(SILAccessEnforcement::Static);
} else if (attr == "dynamic") {
setEnforcement(SILAccessEnforcement::Dynamic);
} else if (attr == "unsafe") {
setEnforcement(SILAccessEnforcement::Unsafe);
} else if (attr == "init") {
setKind(SILAccessKind::Init);
} else if (attr == "read") {
setKind(SILAccessKind::Read);
} else if (attr == "modify") {
setKind(SILAccessKind::Modify);
} else if (attr == "deinit") {
setKind(SILAccessKind::Deinit);
} else if (attr == "abort") {
setAborting(true);
} else if (attr == "no_nested_conflict") {
setNoNestedConflict(true);
} else if (attr == "builtin") {
setFromBuiltin(true);
} else {
P.diagnose(identLoc, diag::unknown_attribute, attr);
}
if (!P.consumeIf(tok::r_square))
return true;
}
if (isBeginAccess && !kind.isSet()) {
P.diagnose(OpcodeLoc, diag::sil_expected_access_kind, OpcodeName);
kind.Value = SILAccessKind::Read;
}
if (wantsEnforcement && !enforcement.isSet()) {
P.diagnose(OpcodeLoc, diag::sil_expected_access_enforcement, OpcodeName);
enforcement.Value = SILAccessEnforcement::Unsafe;
}
if (!isBeginAccess && !aborting.isSet())
aborting.Value = false;
if (isBeginAccess && !noNestedConflict.isSet())
noNestedConflict.Value = false;
if (!fromBuiltin.isSet())
fromBuiltin.Value = false;
SILValue addrVal;
SourceLoc addrLoc;
if (parseTypedValueRef(addrVal, addrLoc, B))
return true;
SILValue bufferVal;
SourceLoc bufferLoc;
if (Opcode == SILInstructionKind::BeginUnpairedAccessInst &&
(P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseTypedValueRef(bufferVal, bufferLoc, B)))
return true;
if (parseSILDebugLocation(InstLoc, B))
return true;
if (!addrVal->getType().isAddress()) {
P.diagnose(addrLoc, diag::sil_operand_not_address, "operand", OpcodeName);
return true;
}
if (Opcode == SILInstructionKind::BeginAccessInst) {
ResultVal = B.createBeginAccess(InstLoc, addrVal, *kind, *enforcement,
*noNestedConflict, *fromBuiltin);
} else if (Opcode == SILInstructionKind::EndAccessInst) {
ResultVal = B.createEndAccess(InstLoc, addrVal, *aborting);
} else if (Opcode == SILInstructionKind::BeginUnpairedAccessInst) {
ResultVal = B.createBeginUnpairedAccess(InstLoc, addrVal, bufferVal,
*kind, *enforcement,
*noNestedConflict, *fromBuiltin);
} else {
ResultVal = B.createEndUnpairedAccess(InstLoc, addrVal, *enforcement,
*aborting, *fromBuiltin);
}
break;
}
#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
case SILInstructionKind::Store##Name##Inst:
#include "swift/AST/ReferenceStorage.def"
case SILInstructionKind::StoreBorrowInst: {
UnresolvedValueName from;
bool isRefStorage = false;
#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
isRefStorage |= Opcode == SILInstructionKind::Store##Name##Inst;
#include "swift/AST/ReferenceStorage.def"
SourceLoc toLoc, addrLoc;
Identifier toToken;
SILValue addrVal;
bool isInit = false;
if (parseValueName(from) ||
parseSILIdentifier(toToken, toLoc, diag::expected_tok_in_sil_instr,
"to") ||
(isRefStorage && 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 == SILInstructionKind::StoreBorrowInst) {
SILType valueTy = addrVal->getType().getObjectType();
ResultVal = B.createStoreBorrow(
InstLoc, getLocalValue(from, valueTy, InstLoc, B), addrVal);
break;
}
#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
if (Opcode == SILInstructionKind::Store##Name##Inst) { \
auto refType = addrVal->getType().getAs<Name##StorageType>(); \
if (!refType) { \
P.diagnose(addrLoc, diag::sil_operand_not_ref_storage_address, \
"destination", OpcodeName, ReferenceOwnership::Name); \
return true; \
} \
auto valueTy = SILType::getPrimitiveObjectType(refType.getReferentType()); \
ResultVal = \
B.createStore##Name(InstLoc, getLocalValue(from, valueTy, InstLoc, B), \
addrVal, IsInitialization_t(isInit)); \
break; \
}
#include "swift/AST/ReferenceStorage.def"
break;
}
case SILInstructionKind::AllocStackInst:
case SILInstructionKind::MetatypeInst: {
bool hasDynamicLifetime = false;
if (Opcode == SILInstructionKind::AllocStackInst &&
parseSILOptional(hasDynamicLifetime, *this, "dynamic_lifetime"))
return true;
SILType Ty;
if (parseSILType(Ty))
return true;
if (Opcode == SILInstructionKind::AllocStackInst) {
SILDebugVariable VarInfo;
if (parseSILDebugVar(VarInfo) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createAllocStack(InstLoc, Ty, VarInfo, hasDynamicLifetime);
} else {
assert(Opcode == SILInstructionKind::MetatypeInst);
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createMetatype(InstLoc, Ty);
}
break;
}
case SILInstructionKind::AllocRefInst:
case SILInstructionKind::AllocRefDynamicInst: {
bool IsObjC = false;
bool OnStack = false;
SmallVector<SILType, 2> ElementTypes;
SmallVector<SILValue, 2> ElementCounts;
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 == SILInstructionKind::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.empty()) {
P.diagnose(P.Tok, diag::sil_objc_with_tail_elements);
return true;
}
if (Opcode == SILInstructionKind::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 SILInstructionKind::DeallocStackInst:
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDeallocStack(InstLoc, Val);
break;
case SILInstructionKind::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 SILInstructionKind::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 SILInstructionKind::DeallocBoxInst:
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDeallocBox(InstLoc, Val);
break;
case SILInstructionKind::ValueMetatypeInst:
case SILInstructionKind::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 SILInstructionKind::ValueMetatypeInst:
ResultVal = B.createValueMetatype(InstLoc, Ty, Val);
break;
case SILInstructionKind::ExistentialMetatypeInst:
ResultVal = B.createExistentialMetatype(InstLoc, Ty, Val);
break;
case SILInstructionKind::DeallocBoxInst:
ResultVal = B.createDeallocBox(InstLoc, Val);
break;
}
break;
}
case SILInstructionKind::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 SILInstructionKind::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<TupleTypeElt, 4> TypeElts;
if (P.Tok.isNot(tok::r_paren)) {
do {
if (parseTypedValueRef(Val, B))
return true;
OpList.push_back(Val);
TypeElts.push_back(Val->getType().getASTType());
} 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<TupleType>();
if (TT == nullptr) {
P.diagnose(OpcodeLoc, diag::expected_tuple_type_in_tuple);
return true;
}
SmallVector<TupleTypeElt, 4> 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().getASTType());
} 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 SILInstructionKind::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<EnumElementDecl>(Elt.getDecl()), Ty);
break;
}
case SILInstructionKind::InitEnumDataAddrInst:
case SILInstructionKind::UncheckedEnumDataInst:
case SILInstructionKind::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<EnumElementDecl>(EltRef.getDecl());
auto ResultTy = Operand->getType().getEnumElementType(
Elt, SILMod, B.getTypeExpansionContext());
switch (Opcode) {
case swift::SILInstructionKind::InitEnumDataAddrInst:
ResultVal = B.createInitEnumDataAddr(InstLoc, Operand, Elt, ResultTy);
break;
case swift::SILInstructionKind::UncheckedTakeEnumDataAddrInst:
ResultVal =
B.createUncheckedTakeEnumDataAddr(InstLoc, Operand, Elt, ResultTy);
break;
case swift::SILInstructionKind::UncheckedEnumDataInst:
ResultVal = B.createUncheckedEnumData(InstLoc, Operand, Elt, ResultTy);
break;
default:
llvm_unreachable("switch out of sync");
}
break;
}
case SILInstructionKind::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<EnumElementDecl>(EltRef.getDecl());
ResultVal = B.createInjectEnumAddr(InstLoc, Operand, Elt);
break;
}
case SILInstructionKind::TupleElementAddrInst:
case SILInstructionKind::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<TupleType>();
if (P.Tok.isNot(tok::integer_literal) ||
parseIntegerLiteral(P.Tok.getText(), 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 == SILInstructionKind::TupleElementAddrInst)
ResultVal = B.createTupleElementAddr(
InstLoc, Val, Field, SILType::getPrimitiveAddressType(ResultTy));
else
ResultVal = B.createTupleExtract(
InstLoc, Val, Field, SILType::getPrimitiveObjectType(ResultTy));
break;
}
case SILInstructionKind::ReturnInst: {
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createReturn(InstLoc, Val);
break;
}
case SILInstructionKind::ThrowInst: {
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createThrow(InstLoc, Val);
break;
}
case SILInstructionKind::UnwindInst: {
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createUnwind(InstLoc);
break;
}
case SILInstructionKind::YieldInst: {
SmallVector<SILValue, 6> values;
// Parse a parenthesized (unless length-1), comma-separated list
// of yielded values.
if (P.consumeIf(tok::l_paren)) {
if (!P.Tok.is(tok::r_paren)) {
do {
if (parseTypedValueRef(Val, B))
return true;
values.push_back(Val);
} while (P.consumeIf(tok::comma));
}
if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")"))
return true;
} else {
if (parseTypedValueRef(Val, B))
return true;
values.push_back(Val);
}
Identifier resumeName, unwindName;
SourceLoc resumeLoc, unwindLoc;
if (P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseVerbatim("resume") ||
parseSILIdentifier(resumeName, resumeLoc,
diag::expected_sil_block_name) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseVerbatim("unwind") ||
parseSILIdentifier(unwindName, unwindLoc,
diag::expected_sil_block_name) ||
parseSILDebugLocation(InstLoc, B))
return true;
auto resumeBB = getBBForReference(resumeName, resumeLoc);
auto unwindBB = getBBForReference(unwindName, unwindLoc);
ResultVal = B.createYield(InstLoc, values, resumeBB, unwindBB);
break;
}
case SILInstructionKind::BranchInst: {
Identifier BBName;
SourceLoc NameLoc;
if (parseSILIdentifier(BBName, NameLoc, diag::expected_sil_block_name))
return true;
SmallVector<SILValue, 6> 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 SILInstructionKind::CondBranchInst: {
UnresolvedValueName Cond;
Identifier BBName, BBName2;
SourceLoc NameLoc, NameLoc2;
SmallVector<SILValue, 6> 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, SILMod.getASTContext());
SILValue CondVal = getLocalValue(Cond, I1Ty, InstLoc, B);
ResultVal = B.createCondBranch(
InstLoc, CondVal, getBBForReference(BBName, NameLoc), Args,
getBBForReference(BBName2, NameLoc2), Args2);
break;
}
case SILInstructionKind::UnreachableInst:
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createUnreachable(InstLoc);
break;
case SILInstructionKind::ClassMethodInst:
case SILInstructionKind::SuperMethodInst:
case SILInstructionKind::ObjCMethodInst:
case SILInstructionKind::ObjCSuperMethodInst: {
SILDeclRef Member;
SILType MethodTy;
SourceLoc TyLoc;
SmallVector<ValueDecl *, 4> 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 SILInstructionKind::ClassMethodInst:
ResultVal = B.createClassMethod(InstLoc, Val, Member, MethodTy);
break;
case SILInstructionKind::SuperMethodInst:
ResultVal = B.createSuperMethod(InstLoc, Val, Member, MethodTy);
break;
case SILInstructionKind::ObjCMethodInst:
ResultVal = B.createObjCMethod(InstLoc, Val, Member, MethodTy);
break;
case SILInstructionKind::ObjCSuperMethodInst:
ResultVal = B.createObjCSuperMethod(InstLoc, Val, Member, MethodTy);
break;
}
break;
}
case SILInstructionKind::WitnessMethodInst: {
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<ProtocolDecl>(Member.getDecl()->getDeclContext());
if (!proto) {
P.diagnose(TyLoc, diag::sil_witness_method_not_protocol);
return true;
}
auto conformance =
P.SF.getParentModule()->lookupConformance(LookupTy, proto);
if (conformance.isInvalid()) {
P.diagnose(TyLoc, diag::sil_witness_method_type_does_not_conform);
return true;
}
ResultVal = B.createWitnessMethod(InstLoc, LookupTy, conformance, Member,
MethodTy);
break;
}
case SILInstructionKind::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 SILInstructionKind::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 SILInstructionKind::ObjectInst:
case SILInstructionKind::StructInst: {
SILType Ty;
if (parseSILType(Ty) ||
P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "("))
return true;
// Parse a list of SILValue.
bool OpsAreTailElems = false;
unsigned NumBaseElems = 0;
if (P.Tok.isNot(tok::r_paren)) {
do {
if (Opcode == SILInstructionKind::ObjectInst) {
if (parseSILOptional(OpsAreTailElems, *this, "tail_elems"))
return true;
}
if (parseTypedValueRef(Val, B))
return true;
OpList.push_back(Val);
if (!OpsAreTailElems)
NumBaseElems = OpList.size();
} while (P.consumeIf(tok::comma));
}
if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")") ||
parseSILDebugLocation(InstLoc, B))
return true;
if (Opcode == SILInstructionKind::StructInst) {
ResultVal = B.createStruct(InstLoc, Ty, OpList);
} else {
ResultVal = B.createObject(InstLoc, Ty, OpList, NumBaseElems);
}
break;
}
case SILInstructionKind::StructElementAddrInst:
case SILInstructionKind::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<VarDecl>(FieldV)) {
P.diagnose(NameLoc, diag::sil_struct_inst_wrong_field);
return true;
}
VarDecl *Field = cast<VarDecl>(FieldV);
// FIXME: substitution means this type should be explicit to improve
// performance.
auto ResultTy = Val->getType().getFieldType(Field, SILMod,
B.getTypeExpansionContext());
if (Opcode == SILInstructionKind::StructElementAddrInst)
ResultVal = B.createStructElementAddr(InstLoc, Val, Field,
ResultTy.getAddressType());
else
ResultVal = B.createStructExtract(InstLoc, Val, Field,
ResultTy.getObjectType());
break;
}
case SILInstructionKind::RefElementAddrInst: {
ValueDecl *FieldV;
SourceLoc NameLoc;
bool IsImmutable = false;
if (parseSILOptional(IsImmutable, *this, "immutable") ||
parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILDottedPath(FieldV) || parseSILDebugLocation(InstLoc, B))
return true;
if (!FieldV || !isa<VarDecl>(FieldV)) {
P.diagnose(NameLoc, diag::sil_ref_inst_wrong_field);
return true;
}
VarDecl *Field = cast<VarDecl>(FieldV);
auto ResultTy = Val->getType().getFieldType(Field, SILMod,
B.getTypeExpansionContext());
ResultVal = B.createRefElementAddr(InstLoc, Val, Field, ResultTy,
IsImmutable);
break;
}
case SILInstructionKind::RefTailAddrInst: {
SourceLoc NameLoc;
SILType ResultObjTy;
bool IsImmutable = false;
if (parseSILOptional(IsImmutable, *this, "immutable") ||
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, IsImmutable);
break;
}
case SILInstructionKind::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 SILInstructionKind::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 SILInstructionKind::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 SILInstructionKind::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<ValueDecl *, 4> CurModuleResults;
// Perform a module level lookup on the first component of the
// fully-qualified name.
P.SF.getParentModule()->lookupValue(
ProtocolName, NLKind::UnqualifiedLookup, CurModuleResults);
assert(CurModuleResults.size() == 1);
VD = CurModuleResults[0];
ResultVal = B.createObjCProtocol(InstLoc, cast<ProtocolDecl>(VD), Ty);
break;
}
case SILInstructionKind::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 SILInstructionKind::GlobalAddrInst:
case SILInstructionKind::GlobalValueInst: {
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;
}
SILType expectedType = (Opcode == SILInstructionKind::GlobalAddrInst
? global->getLoweredType().getAddressType()
: global->getLoweredType());
if (expectedType != Ty) {
P.diagnose(IdLoc, diag::sil_value_use_type_mismatch, GlobalName.str(),
global->getLoweredType().getASTType(), Ty.getASTType());
return true;
}
if (Opcode == SILInstructionKind::GlobalAddrInst) {
ResultVal = B.createGlobalAddr(InstLoc, global);
} else {
ResultVal = B.createGlobalValue(InstLoc, global);
}
break;
}
case SILInstructionKind::BaseAddrForOffsetInst: {
SILType Ty;
if (parseSILType(Ty))
return true;
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createBaseAddrForOffset(InstLoc, Ty);
break;
}
case SILInstructionKind::SelectEnumInst:
case SILInstructionKind::SelectEnumAddrInst: {
if (parseTypedValueRef(Val, B))
return true;
SmallVector<std::pair<EnumElementDecl *, UnresolvedValueName>, 4>
CaseValueNames;
Optional<UnresolvedValueName> 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<EnumElementDecl>(ElemRef.getDecl()));
P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":");
parseValueName(tmp);
CaseValueNames.push_back(
std::make_pair(cast<EnumElementDecl>(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<std::pair<EnumElementDecl *, SILValue>, 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 == SILInstructionKind::SelectEnumInst)
ResultVal = B.createSelectEnum(InstLoc, Val, ResultType, DefaultValue,
CaseValues);
else
ResultVal = B.createSelectEnumAddr(InstLoc, Val, ResultType,
DefaultValue, CaseValues);
break;
}
case SILInstructionKind::SwitchEnumInst:
case SILInstructionKind::SwitchEnumAddrInst: {
if (parseTypedValueRef(Val, B))
return true;
SmallVector<std::pair<EnumElementDecl *, SILBasicBlock *>, 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<EnumElementDecl>(ElemRef.getDecl()));
P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":");
parseSILIdentifier(BBName, BBLoc, diag::expected_sil_block_name);
CaseBBs.push_back({cast<EnumElementDecl>(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 == SILInstructionKind::SwitchEnumInst)
ResultVal = B.createSwitchEnum(InstLoc, Val, DefaultBB, CaseBBs);
else
ResultVal = B.createSwitchEnumAddr(InstLoc, Val, DefaultBB, CaseBBs);
break;
}
case SILInstructionKind::SwitchValueInst: {
if (parseTypedValueRef(Val, B))
return true;
SmallVector<std::pair<SILValue, SILBasicBlock *>, 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<BuiltinIntegerType>();
auto functionTy = Val->getType().getAs<SILFunctionType>();
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<SILUndef>(CaseVal)) {
auto *IL = dyn_cast<IntegerLiteralInst>(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<SILUndef>(CaseVal)) {
auto *FR = dyn_cast<FunctionRefInst>(CaseVal);
if (!FR) {
if (auto *CF = dyn_cast<ConvertFunctionInst>(CaseVal)) {
FR = dyn_cast<FunctionRefInst>(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 SILInstructionKind::SelectValueInst: {
if (parseTypedValueRef(Val, B))
return true;
SmallVector<std::pair<UnresolvedValueName, UnresolvedValueName>, 4>
CaseValueAndResultNames;
Optional<UnresolvedValueName> 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<std::pair<SILValue, SILValue>, 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 SILInstructionKind::DeinitExistentialAddrInst: {
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDeinitExistentialAddr(InstLoc, Val);
break;
}
case SILInstructionKind::DeinitExistentialValueInst: {
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDeinitExistentialValue(InstLoc, Val);
break;
}
case SILInstructionKind::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 = OpenedArchetypeType::get(Val->getType().getASTType())
->getCanonicalType();
auto &F = B.getFunction();
SILType LoweredTy =
F.getLoweredType(Lowering::AbstractionPattern(archetype), Ty)
.getAddressType();
// Collect conformances for the type.
ArrayRef<ProtocolConformanceRef> conformances =
collectExistentialConformances(P, Ty, TyLoc,
Val->getType().getASTType());
ResultVal = B.createInitExistentialAddr(InstLoc, Val, Ty, LoweredTy,
conformances);
break;
}
case SILInstructionKind::InitExistentialValueInst: {
CanType FormalConcreteTy;
SILType ExistentialTy;
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(FormalConcreteTy, TyLoc) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILType(ExistentialTy) || parseSILDebugLocation(InstLoc, B))
return true;
ArrayRef<ProtocolConformanceRef> conformances =
collectExistentialConformances(P, FormalConcreteTy, TyLoc,
ExistentialTy.getASTType());
ResultVal = B.createInitExistentialValue(
InstLoc, ExistentialTy, FormalConcreteTy, Val, conformances);
break;
}
case SILInstructionKind::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<ProtocolConformanceRef> conformances =
collectExistentialConformances(P, ConcreteFormalTy, TyLoc,
ExistentialTy.getASTType());
ResultVal = B.createAllocExistentialBox(InstLoc, ExistentialTy,
ConcreteFormalTy, conformances);
break;
}
case SILInstructionKind::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<ProtocolConformanceRef> conformances =
collectExistentialConformances(P, FormalConcreteTy, TyLoc,
ExistentialTy.getASTType());
// FIXME: Conformances in InitExistentialRefInst is currently not included
// in SIL.rst.
ResultVal = B.createInitExistentialRef(
InstLoc, ExistentialTy, FormalConcreteTy, Val, conformances);
break;
}
case SILInstructionKind::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.getASTType();
auto formalConcreteType = Val->getType().getASTType();
while (auto instExType = dyn_cast<ExistentialMetatypeType>(baseExType)) {
baseExType = instExType.getInstanceType();
formalConcreteType =
cast<MetatypeType>(formalConcreteType).getInstanceType();
}
ArrayRef<ProtocolConformanceRef> conformances =
collectExistentialConformances(P, formalConcreteType, TyLoc,
baseExType);
ResultVal = B.createInitExistentialMetatype(InstLoc, Val, ExistentialTy,
conformances);
break;
}
case SILInstructionKind::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 SILInstructionKind::ProjectBlockStorageInst: {
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createProjectBlockStorage(InstLoc, Val);
break;
}
case SILInstructionKind::InitBlockStorageHeaderInst: {
Identifier invoke, type;
SourceLoc invokeLoc, typeLoc;
UnresolvedValueName invokeName;
SILType invokeTy;
GenericEnvironment *invokeGenericEnv = nullptr;
GenericParamList *invokeGenericParams = nullptr;
SILType blockType;
SmallVector<ParsedSubstitution, 4> 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, invokeGenericParams) ||
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);
SubstitutionMap subMap;
if (!parsedSubs.empty()) {
if (!invokeGenericEnv) {
P.diagnose(typeLoc, diag::sil_substitutions_on_non_polymorphic_type);
return true;
}
subMap = getApplySubstitutionsFromParsed(*this, invokeGenericEnv,
parsedSubs);
if (!subMap)
return true;
}
ResultVal = B.createInitBlockStorageHeader(InstLoc, Val, invokeVal,
blockType, subMap);
break;
}
case SILInstructionKind::DifferentiableFunctionInst: {
// e.g. differentiable_function [parameters 0 1 2] [results 0] %0 : $T
//
// e.g. differentiable_function [parameters 0 1 2] [results 0] %0 : $T
// with_derivative {%1 : $T, %2 : $T}
// ^~ jvp ^~ vjp
// Parse `[parameters <integer_literal>...]`.
SmallVector<unsigned, 8> rawParameterIndices;
if (parseIndexList(P, "parameters", rawParameterIndices,
diag::sil_autodiff_expected_parameter_index))
return true;
SmallVector<unsigned, 2> rawResultIndices;
if (parseIndexList(P, "results", rawResultIndices,
diag::sil_autodiff_expected_result_index))
return true;
// Parse the original function value.
SILValue original;
SourceLoc originalOperandLoc;
if (parseTypedValueRef(original, originalOperandLoc, B))
return true;
auto fnType = original->getType().getAs<SILFunctionType>();
if (!fnType) {
P.diagnose(originalOperandLoc,
diag::sil_inst_autodiff_expected_function_type_operand);
return true;
}
Optional<std::pair<SILValue, SILValue>> derivativeFunctions = None;
// Parse an optional operand list
// `with_derivative { <operand> , <operand> }`.
if (P.Tok.is(tok::identifier) && P.Tok.getText() == "with_derivative") {
P.consumeToken(tok::identifier);
// Parse derivative function values as an operand list.
// FIXME(rxwei): Change this to *not* require a type signature once
// we can infer derivative function types.
derivativeFunctions = std::make_pair(SILValue(), SILValue());
if (P.parseToken(
tok::l_brace,
diag::sil_inst_autodiff_operand_list_expected_lbrace) ||
parseTypedValueRef(derivativeFunctions->first, B) ||
P.parseToken(tok::comma,
diag::sil_inst_autodiff_operand_list_expected_comma) ||
parseTypedValueRef(derivativeFunctions->second, B) ||
P.parseToken(tok::r_brace,
diag::sil_inst_autodiff_operand_list_expected_rbrace))
return true;
}
if (parseSILDebugLocation(InstLoc, B))
return true;
auto *parameterIndices = IndexSubset::get(
P.Context, fnType->getNumParameters(), rawParameterIndices);
auto *resultIndices = IndexSubset::get(
P.Context,
fnType->getNumResults() + fnType->getNumIndirectMutatingParameters(),
rawResultIndices);
ResultVal = B.createDifferentiableFunction(InstLoc, parameterIndices,
resultIndices, original,
derivativeFunctions);
break;
}
case SILInstructionKind::LinearFunctionInst: {
// e.g. linear_function [parameters 0 1 2] %0 : $T
// e.g. linear_function [parameters 0 1 2] %0 : $T with_transpose %1 : $T
// Parse `[parameters <integer_literal>...]`.
SmallVector<unsigned, 8> rawParameterIndices;
if (parseIndexList(P, "parameters", rawParameterIndices,
diag::sil_autodiff_expected_parameter_index))
return true;
// Parse the original function value.
SILValue original;
SourceLoc originalOperandLoc;
if (parseTypedValueRef(original, originalOperandLoc, B))
return true;
auto fnType = original->getType().getAs<SILFunctionType>();
if (!fnType) {
P.diagnose(originalOperandLoc,
diag::sil_inst_autodiff_expected_function_type_operand);
return true;
}
// Parse an optional transpose function.
Optional<SILValue> transpose = None;
if (P.Tok.is(tok::identifier) && P.Tok.getText() == "with_transpose") {
P.consumeToken(tok::identifier);
transpose = SILValue();
if (parseTypedValueRef(*transpose, B))
return true;
}
if (parseSILDebugLocation(InstLoc, B))
return true;
auto *parameterIndicesSubset = IndexSubset::get(
P.Context, fnType->getNumParameters(), rawParameterIndices);
ResultVal = B.createLinearFunction(
InstLoc, parameterIndicesSubset, original, transpose);
break;
}
case SILInstructionKind::DifferentiableFunctionExtractInst: {
// Parse the rest of the instruction: an extractee, a differentiable
// function operand, an optional explicit extractee type, and a debug
// location.
NormalDifferentiableFunctionTypeComponent extractee;
StringRef extracteeNames[3] = {"original", "jvp", "vjp"};
SILValue functionOperand;
SourceLoc lastLoc;
if (P.parseToken(
tok::l_square,
diag::sil_inst_autodiff_expected_differentiable_extractee_kind) ||
parseSILIdentifierSwitch(
extractee, extracteeNames,
diag::sil_inst_autodiff_expected_differentiable_extractee_kind) ||
P.parseToken(tok::r_square, diag::sil_autodiff_expected_rsquare,
"extractee kind"))
return true;
if (parseTypedValueRef(functionOperand, B))
return true;
// Parse an optional explicit extractee type.
Optional<SILType> extracteeType = None;
if (P.consumeIf(tok::kw_as)) {
extracteeType = SILType();
if (parseSILType(*extracteeType))
return true;
}
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDifferentiableFunctionExtract(
InstLoc, extractee, functionOperand, extracteeType);
break;
}
case SILInstructionKind::LinearFunctionExtractInst: {
// Parse the rest of the instruction: an extractee, a linear function
// operand, and a debug location.
LinearDifferentiableFunctionTypeComponent extractee;
StringRef extracteeNames[2] = {"original", "transpose"};
SILValue functionOperand;
SourceLoc lastLoc;
if (P.parseToken(tok::l_square,
diag::sil_inst_autodiff_expected_linear_extractee_kind) ||
parseSILIdentifierSwitch(extractee, extracteeNames,
diag::sil_inst_autodiff_expected_linear_extractee_kind) ||
P.parseToken(tok::r_square, diag::sil_autodiff_expected_rsquare,
"extractee kind"))
return true;
if (parseTypedValueRef(functionOperand, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createLinearFunctionExtract(
InstLoc, extractee, functionOperand);
break;
}
case SILInstructionKind::DifferentiabilityWitnessFunctionInst: {
// e.g. differentiability_witness_function
// [jvp] [parameters 0 1] [results 0] <T where T: Differentiable>
// @foo : <T> $(T) -> T
DifferentiabilityWitnessFunctionKind witnessKind;
StringRef witnessKindNames[3] = {"jvp", "vjp", "transpose"};
if (P.parseToken(
tok::l_square,
diag::
sil_inst_autodiff_expected_differentiability_witness_kind) ||
parseSILIdentifierSwitch(
witnessKind, witnessKindNames,
diag::
sil_inst_autodiff_expected_differentiability_witness_kind) ||
P.parseToken(tok::r_square, diag::sil_autodiff_expected_rsquare,
"differentiability witness function kind"))
return true;
SourceLoc keyStartLoc = P.Tok.getLoc();
auto configAndFn =
parseSILDifferentiabilityWitnessConfigAndFunction(P, *this, InstLoc);
if (!configAndFn)
return true;
auto config = configAndFn->first;
auto originalFn = configAndFn->second;
auto *witness = SILMod.lookUpDifferentiabilityWitness(
{originalFn->getName(), config});
if (!witness) {
P.diagnose(keyStartLoc, diag::sil_diff_witness_undefined);
return true;
}
// Parse an optional explicit function type.
Optional<SILType> functionType = None;
if (P.consumeIf(tok::kw_as)) {
functionType = SILType();
if (parseSILType(*functionType))
return true;
}
ResultVal = B.createDifferentiabilityWitnessFunction(
InstLoc, witnessKind, witness, functionType);
break;
}
case SILInstructionKind::AwaitAsyncContinuationInst: {
// 'await_async_continuation' operand, 'resume' bb, 'error' bb
Identifier ResumeBBName, ErrorBBName{};
SourceLoc ResumeNameLoc, ErrorNameLoc{};
if (parseTypedValueRef(Val, B)
|| P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",")
|| P.parseSpecificIdentifier("resume", diag::expected_tok_in_sil_instr, "resume")
|| parseSILIdentifier(ResumeBBName, ResumeNameLoc, diag::expected_sil_block_name)) {
return true;
}
if (P.consumeIf(tok::comma)) {
if (P.parseSpecificIdentifier("error", diag::expected_tok_in_sil_instr, "error")
|| parseSILIdentifier(ErrorBBName, ErrorNameLoc, diag::expected_sil_block_name)
|| parseSILDebugLocation(InstLoc, B)) {
return true;
}
}
SILBasicBlock *resumeBB, *errorBB = nullptr;
resumeBB = getBBForReference(ResumeBBName, ResumeNameLoc);
if (!ErrorBBName.empty()) {
errorBB = getBBForReference(ErrorBBName, ErrorNameLoc);
}
ResultVal = B.createAwaitAsyncContinuation(InstLoc, Val, resumeBB, errorBB);
break;
}
case SILInstructionKind::GetAsyncContinuationInst:
case SILInstructionKind::GetAsyncContinuationAddrInst: {
// 'get_async_continuation' '[throws]'? type
// 'get_async_continuation_addr' '[throws]'? type ',' operand
bool throws = false;
if (P.consumeIf(tok::l_square)) {
if (P.parseToken(tok::kw_throws, diag::expected_tok_in_sil_instr, "throws")
|| P.parseToken(tok::r_square, diag::expected_tok_in_sil_instr, "]"))
return true;
throws = true;
}
CanType resumeTy;
if (parseASTType(resumeTy)) {
return true;
}
SILValue resumeBuffer;
if (Opcode == SILInstructionKind::GetAsyncContinuationAddrInst) {
if (P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",")
|| parseTypedValueRef(resumeBuffer, B)) {
return true;
}
}
if (parseSILDebugLocation(InstLoc, B))
return true;
if (Opcode == SILInstructionKind::GetAsyncContinuationAddrInst) {
ResultVal = B.createGetAsyncContinuationAddr(InstLoc, resumeBuffer,
resumeTy, throws);
} else {
ResultVal = B.createGetAsyncContinuation(InstLoc, resumeTy, throws);
}
break;
}
}
return false;
}
/// sil-instruction-result ::= sil-value-name '='
/// sil-instruction-result ::= '(' sil-value-name? ')'
/// sil-instruction-result ::= '(' sil-value-name (',' sil-value-name)* ')'
/// sil-instruction-source-info ::= (',' sil-scope-ref)? (',' sil-loc)?
/// sil-instruction-def ::=
/// (sil-instruction-result '=')? sil-instruction sil-instruction-source-info
bool SILParser::parseSILInstruction(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;
}
if (!B.hasValidInsertionPoint()) {
P.diagnose(P.Tok, diag::expected_sil_block_name);
return true;
}
SmallVector<Located<StringRef>, 4> resultNames;
SourceLoc resultClauseBegin;
// If the instruction has a name '%foo =', parse it.
if (P.Tok.is(tok::sil_local_name)) {
resultClauseBegin = P.Tok.getLoc();
resultNames.push_back({P.Tok.getText(), P.Tok.getLoc()});
P.consumeToken(tok::sil_local_name);
// If the instruction has a '(%foo, %bar) = ', parse it.
} else if (P.consumeIf(tok::l_paren)) {
resultClauseBegin = P.PreviousLoc;
if (!P.consumeIf(tok::r_paren)) {
while (true) {
if (!P.Tok.is(tok::sil_local_name)) {
P.diagnose(P.Tok, diag::expected_sil_value_name);
return true;
}
resultNames.push_back({P.Tok.getText(), P.Tok.getLoc()});
P.consumeToken(tok::sil_local_name);
if (P.consumeIf(tok::comma))
continue;
if (P.consumeIf(tok::r_paren))
break;
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, ",");
return true;
}
}
}
if (resultClauseBegin.isValid()) {
if (P.parseToken(tok::equal, diag::expected_equal_in_sil_instr))
return true;
}
SILInstructionKind Opcode;
SourceLoc OpcodeLoc;
StringRef OpcodeName;
// Parse the opcode name.
if (parseSILOpcode(Opcode, OpcodeLoc, OpcodeName))
return true;
// Perform opcode specific parsing.
SILInstruction *ResultVal;
if (parseSpecificSILInstruction(B, Opcode, OpcodeLoc, OpcodeName, ResultVal))
return true;
// Match the results clause if we had one.
if (resultClauseBegin.isValid()) {
auto results = ResultVal->getResults();
if (results.size() != resultNames.size()) {
P.diagnose(resultClauseBegin, diag::wrong_result_count_in_sil_instr,
results.size());
} else {
for (size_t i : indices(results)) {
setLocalValue(results[i], resultNames[i].Item, resultNames[i].Loc);
}
}
}
return false;
}
bool SILParser::parseCallInstruction(SILLocation InstLoc,
SILInstructionKind Opcode, SILBuilder &B,
SILInstruction *&ResultVal) {
UnresolvedValueName FnName;
SmallVector<UnresolvedValueName, 4> ArgNames;
auto PartialApplyConvention = ParameterConvention::Direct_Owned;
bool IsNonThrowingApply = false;
bool IsNoEscape = false;
StringRef AttrName;
while (parseSILOptional(AttrName, *this)) {
if (AttrName.equals("nothrow"))
IsNonThrowingApply = true;
else if (AttrName.equals("callee_guaranteed"))
PartialApplyConvention = ParameterConvention::Direct_Guaranteed;
else if (AttrName.equals("on_stack"))
IsNoEscape = true;
else
return true;
}
if (parseValueName(FnName))
return true;
SmallVector<ParsedSubstitution, 4> 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;
GenericParamList *GenericParams = 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, GenericParams))
return true;
auto FTI = Ty.getAs<SILFunctionType>();
if (!FTI) {
P.diagnose(TypeLoc, diag::expected_sil_type_kind, "be a function");
return true;
}
SubstitutionMap subs;
if (!parsedSubs.empty()) {
if (!GenericEnv) {
P.diagnose(TypeLoc, diag::sil_substitutions_on_non_polymorphic_type);
return true;
}
subs = getApplySubstitutionsFromParsed(*this, GenericEnv, parsedSubs);
if (!subs)
return true;
}
SILValue FnVal = getLocalValue(FnName, Ty, InstLoc, B);
SILType FnTy = FnVal->getType();
CanSILFunctionType substFTI = FTI;
if (!subs.empty()) {
auto silFnTy = FnTy.castTo<SILFunctionType>();
substFTI =
silFnTy->substGenericArgs(SILMod, subs, B.getTypeExpansionContext());
FnTy = SILType::getPrimitiveObjectType(substFTI);
}
SILFunctionConventions substConv(substFTI, B.getModule());
// Validate the operand count.
if (substConv.getNumSILArguments() != ArgNames.size() &&
Opcode != SILInstructionKind::PartialApplyInst) {
P.diagnose(TypeLoc, diag::expected_sil_type_kind,
"to have the same number of arg names as arg types");
return true;
}
// Validate the coroutine kind.
if (Opcode == SILInstructionKind::ApplyInst ||
Opcode == SILInstructionKind::TryApplyInst) {
if (FTI->getCoroutineKind() != SILCoroutineKind::None) {
P.diagnose(TypeLoc, diag::expected_sil_type_kind,
"to not be a coroutine");
return true;
}
} else if (Opcode == SILInstructionKind::BeginApplyInst) {
if (FTI->getCoroutineKind() != SILCoroutineKind::YieldOnce) {
P.diagnose(TypeLoc, diag::expected_sil_type_kind,
"to be a yield_once coroutine");
return true;
}
} else {
assert(Opcode == SILInstructionKind::PartialApplyInst);
// partial_apply accepts all kinds of function
}
switch (Opcode) {
default: llvm_unreachable("Unexpected case");
case SILInstructionKind::ApplyInst : {
if (parseSILDebugLocation(InstLoc, B))
return true;
unsigned ArgNo = 0;
SmallVector<SILValue, 4> Args;
for (auto &ArgName : ArgNames) {
SILType expectedTy =
substConv.getSILArgumentType(ArgNo++, B.getTypeExpansionContext());
Args.push_back(getLocalValue(ArgName, expectedTy, InstLoc, B));
}
ResultVal = B.createApply(InstLoc, FnVal, subs, Args, IsNonThrowingApply);
break;
}
case SILInstructionKind::BeginApplyInst: {
if (parseSILDebugLocation(InstLoc, B))
return true;
unsigned ArgNo = 0;
SmallVector<SILValue, 4> Args;
for (auto &ArgName : ArgNames) {
SILType expectedTy =
substConv.getSILArgumentType(ArgNo++, B.getTypeExpansionContext());
Args.push_back(getLocalValue(ArgName, expectedTy, InstLoc, B));
}
ResultVal =
B.createBeginApply(InstLoc, FnVal, subs, Args, IsNonThrowingApply);
break;
}
case SILInstructionKind::PartialApplyInst: {
if (parseSILDebugLocation(InstLoc, B))
return true;
// Compute the result type of the partial_apply, based on which arguments
// are getting applied.
SmallVector<SILValue, 4> Args;
unsigned ArgNo = substConv.getNumSILArguments() - ArgNames.size();
for (auto &ArgName : ArgNames) {
SILType expectedTy =
substConv.getSILArgumentType(ArgNo++, B.getTypeExpansionContext());
Args.push_back(getLocalValue(ArgName, expectedTy, InstLoc, B));
}
// FIXME: Why the arbitrary order difference in IRBuilder type argument?
ResultVal = B.createPartialApply(
InstLoc, FnVal, subs, Args, PartialApplyConvention,
IsNoEscape ? PartialApplyInst::OnStackKind::OnStack
: PartialApplyInst::OnStackKind::NotOnStack);
break;
}
case SILInstructionKind::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;
unsigned argNo = 0;
SmallVector<SILValue, 4> args;
for (auto &argName : ArgNames) {
SILType expectedTy =
substConv.getSILArgumentType(argNo++, B.getTypeExpansionContext());
args.push_back(getLocalValue(argName, expectedTy, InstLoc, B));
}
SILBasicBlock *normalBB = getBBForReference(normalBBName, normalBBLoc);
SILBasicBlock *errorBB = getBBForReference(errorBBName, errorBBLoc);
ResultVal = B.createTryApply(InstLoc, FnVal, subs, args, normalBB, errorBB);
break;
}
}
return false;
}
bool SILParser::parseSILFunctionRef(SILLocation InstLoc,
SILFunction *&ResultFn) {
Identifier Name;
SILType Ty;
SourceLoc Loc = P.Tok.getLoc();
if (parseGlobalName(Name) ||
P.parseToken(tok::colon, diag::expected_sil_colon_value_ref) ||
parseSILType(Ty))
return true;
auto FnTy = Ty.getAs<SILFunctionType>();
if (!FnTy || !Ty.isObject()) {
P.diagnose(Loc, diag::expected_sil_function_type);
return true;
}
ResultFn = getGlobalNameForReference(Name, FnTy, Loc);
return false;
}
/// True if the current token sequence looks like the start of a SIL
/// instruction. This can be one of:
///
/// 1. %name
/// 2. ()
/// 3. (%name1
/// 4. identifier | keyword
/// where the identifier is not followed by a ':' or '(', or it is
/// followed by '(' and is an instruction name. The exceptions here
/// are for recognizing block names.
bool SILParser::isStartOfSILInstruction() {
if (P.Tok.is(tok::sil_local_name))
return true;
if (P.Tok.is(tok::l_paren) &&
(P.peekToken().is(tok::sil_local_name) || P.peekToken().is(tok::r_paren)))
return true;
if (P.Tok.is(tok::identifier) || P.Tok.isKeyword()) {
auto &peek = P.peekToken();
if (peek.is(tok::l_paren))
return getOpcodeByName(P.Tok.getText()).hasValue();
return !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
// OwnershipKind::None, 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;
ValueOwnershipKind OwnershipKind = OwnershipKind::None;
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->hasOwnership() &&
parseSILOwnership(OwnershipKind))
return true;
if (parseSILType(Ty))
return true;
SILArgument *Arg;
if (IsEntry) {
Arg = BB->createFunctionArgument(Ty);
// Today, we construct the ownership kind straight from the function
// type. Make sure they are in sync, otherwise bail. We want this to
// be an exact check rather than a compatibility check since we do not
// want incompatibilities in between @any and other types of ownership
// to be ignored.
if (F->hasOwnership() && Arg->getOwnershipKind() != OwnershipKind) {
auto diagID =
diag::silfunc_and_silarg_have_incompatible_sil_value_ownership;
P.diagnose(NameLoc, diagID, Arg->getOwnershipKind().asString(),
OwnershipKind.asString());
return true;
}
} else {
Arg = BB->createPhiArgument(Ty, OwnershipKind);
}
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);
B.setInsertionPoint(BB);
do {
if (parseSILInstruction(B))
return true;
} 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 SILParserState::parseDeclSIL(Parser &P) {
// 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(*P.L);
P.consumeToken(tok::kw_sil);
SILParser FunctionState(P);
Optional<SILLinkage> FnLinkage;
Identifier FnName;
SILType FnType;
SourceLoc FnNameLoc;
bool isTransparent = false;
IsSerialized_t isSerialized = IsNotSerialized;
bool isCanonical = false;
IsDynamicallyReplaceable_t isDynamic = IsNotDynamic;
IsExactSelfClass_t isExactSelfClass = IsNotExactSelfClass;
bool hasOwnershipSSA = false;
IsThunk_t isThunk = IsNotThunk;
SILFunction::Purpose specialPurpose = SILFunction::Purpose::None;
bool isWeakImported = false;
AvailabilityContext availability = AvailabilityContext::alwaysAvailable();
bool isWithoutActuallyEscapingThunk = false;
Inline_t inlineStrategy = InlineDefault;
OptimizationMode optimizationMode = OptimizationMode::NotSet;
SmallVector<std::string, 1> Semantics;
SmallVector<ParsedSpecAttr, 4> SpecAttrs;
ValueDecl *ClangDecl = nullptr;
EffectsKind MRK = EffectsKind::Unspecified;
SILFunction *DynamicallyReplacedFunction = nullptr;
Identifier objCReplacementFor;
if (parseSILLinkage(FnLinkage, P) ||
parseDeclSILOptional(
&isTransparent, &isSerialized, &isCanonical, &hasOwnershipSSA,
&isThunk, &isDynamic, &isExactSelfClass, &DynamicallyReplacedFunction,
&objCReplacementFor, &specialPurpose, &inlineStrategy,
&optimizationMode, nullptr, &isWeakImported, &availability,
&isWithoutActuallyEscapingThunk, &Semantics,
&SpecAttrs, &ClangDecl, &MRK, FunctionState, M) ||
P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
P.parseIdentifier(FnName, FnNameLoc, /*diagnoseDollarPrefix=*/false,
diag::expected_sil_function_name) ||
P.parseToken(tok::colon, diag::expected_sil_type))
return true;
{
// Construct a Scope for the function body so TypeAliasDecl can be added to
// the scope.
GenericEnvironment *GenericEnv = nullptr;
GenericParamList *GenericParams = nullptr;
if (FunctionState.parseSILType(FnType, GenericEnv, GenericParams,
true /*IsFuncDecl*/))
return true;
auto SILFnType = FnType.getAs<SILFunctionType>();
if (!SILFnType || !FnType.isObject()) {
P.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->setSerialized(IsSerialized_t(isSerialized));
FunctionState.F->setWasDeserializedCanonical(isCanonical);
if (!hasOwnershipSSA)
FunctionState.F->setOwnershipEliminated();
FunctionState.F->setThunk(IsThunk_t(isThunk));
FunctionState.F->setIsDynamic(isDynamic);
FunctionState.F->setIsExactSelfClass(isExactSelfClass);
FunctionState.F->setDynamicallyReplacedFunction(
DynamicallyReplacedFunction);
if (!objCReplacementFor.empty())
FunctionState.F->setObjCReplacement(objCReplacementFor);
FunctionState.F->setSpecialPurpose(specialPurpose);
FunctionState.F->setAlwaysWeakImported(isWeakImported);
FunctionState.F->setAvailabilityForLinkage(availability);
FunctionState.F->setWithoutActuallyEscapingThunk(
isWithoutActuallyEscapingThunk);
FunctionState.F->setInlineStrategy(inlineStrategy);
FunctionState.F->setOptimizationMode(optimizationMode);
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 = P.Tok.getLoc();
if (P.consumeIf(tok::l_brace)) {
isDefinition = true;
FunctionState.ContextGenericEnv = GenericEnv;
FunctionState.ContextGenericParams = GenericParams;
FunctionState.F->setGenericEnvironment(GenericEnv);
if (GenericEnv && !SpecAttrs.empty()) {
for (auto &Attr : SpecAttrs) {
SmallVector<Requirement, 2> requirements;
// Resolve types and convert requirements.
FunctionState.convertRequirements(Attr.requirements, requirements);
auto *fenv = FunctionState.F->getGenericEnvironment();
auto genericSig = evaluateOrDefault(
P.Context.evaluator,
AbstractGenericSignatureRequest{
fenv->getGenericSignature().getPointer(),
/*addedGenericParams=*/{ },
std::move(requirements)},
GenericSignature());
FunctionState.F->addSpecializeAttr(SILSpecializeAttr::create(
FunctionState.F->getModule(), genericSig, Attr.exported,
Attr.kind, Attr.target, Attr.spiGroupID, Attr.spiModule));
}
}
// Parse the basic block list.
SILOpenedArchetypesTracker OpenedArchetypesTracker(FunctionState.F);
SILBuilder B(*FunctionState.F);
// 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](Type ty) {
OpenedArchetypesTracker.registerUsedOpenedArchetypes(
ty->getCanonicalType());
};
do {
if (FunctionState.parseSILBasicBlock(B))
return true;
} while (P.Tok.isNot(tok::r_brace) && P.Tok.isNot(tok::eof));
SourceLoc RBraceLoc;
P.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 (!P.Diags.hadAnyError())
FunctionState.F->verify();
return false;
}
/// decl-sil-stage: [[only in SIL mode]]
/// 'sil_stage' ('raw' | 'canonical')
bool SILParserState::parseDeclSILStage(Parser &P) {
SourceLoc stageLoc = P.consumeToken(tok::kw_sil_stage);
if (!P.Tok.is(tok::identifier)) {
P.diagnose(P.Tok, diag::expected_sil_stage_name);
return true;
}
SILStage stage;
if (P.Tok.isContextualKeyword("raw")) {
stage = SILStage::Raw;
P.consumeToken();
} else if (P.Tok.isContextualKeyword("canonical")) {
stage = SILStage::Canonical;
P.consumeToken();
} else if (P.Tok.isContextualKeyword("lowered")) {
stage = SILStage::Lowered;
P.consumeToken();
} else {
P.diagnose(P.Tok, diag::expected_sil_stage_name);
P.consumeToken();
return true;
}
if (DidParseSILStage) {
P.diagnose(stageLoc, diag::multiple_sil_stage_decls);
return false;
}
M.setStage(stage);
DidParseSILStage = true;
return false;
}
/// Lookup a global variable declaration from its demangled name.
///
/// A variable declaration exists for all sil_global variables defined in
/// Swift. A Swift global defined outside this module will be exposed
/// via an addressor rather than as a sil_global. Globals imported
/// from clang will produce a sil_global but will not have any corresponding
/// VarDecl.
///
/// FIXME: lookupGlobalDecl() can handle collisions between private or
/// fileprivate global variables in the same SIL Module, but the typechecker
/// will still incorrectly diagnose this as an "invalid redeclaration" and give
/// all but the first declaration an error type.
static Optional<VarDecl *> lookupGlobalDecl(Identifier GlobalName,
SILLinkage GlobalLinkage,
SILType GlobalType, Parser &P) {
// Create a set of DemangleOptions to produce the global variable's
// identifier, which is used as a search key in the declaration context.
Demangle::DemangleOptions demangleOpts;
demangleOpts.QualifyEntities = false;
demangleOpts.ShowPrivateDiscriminators = false;
demangleOpts.DisplayEntityTypes = false;
std::string GlobalDeclName = Demangle::demangleSymbolAsString(
GlobalName.str(), demangleOpts);
SmallVector<ValueDecl *, 4> CurModuleResults;
P.SF.getParentModule()->lookupValue(
P.Context.getIdentifier(GlobalDeclName), NLKind::UnqualifiedLookup,
CurModuleResults);
// Bail-out on clang-imported globals.
if (CurModuleResults.empty())
return nullptr;
// private and fileprivate globals of the same name may be merged into a
// single SIL module. Find the declaration with the correct type and
// linkage. (If multiple globals have the same type and linkage then it
// doesn't matter which declaration we use).
for (ValueDecl *ValDecl : CurModuleResults) {
auto *VD = cast<VarDecl>(ValDecl);
CanType DeclTy = VD->getType()->getCanonicalType();
if (DeclTy == GlobalType.getASTType()
&& getDeclSILLinkage(VD) == GlobalLinkage) {
return VD;
}
}
return None;
}
/// decl-sil-global: [[only in SIL mode]]
/// 'sil_global' sil-linkage @name : sil-type [external]
bool SILParserState::parseSILGlobal(Parser &P) {
// Inform the lexer that we're lexing the body of the SIL declaration.
Lexer::SILBodyRAII Tmp(*P.L);
P.consumeToken(tok::kw_sil_global);
Optional<SILLinkage> GlobalLinkage;
Identifier GlobalName;
SILType GlobalType;
SourceLoc NameLoc;
IsSerialized_t isSerialized = IsNotSerialized;
bool isLet = false;
SILParser State(P);
if (parseSILLinkage(GlobalLinkage, P) ||
parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr,
&isLet, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, State, M) ||
P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
P.parseIdentifier(GlobalName, NameLoc, /*diagnoseDollarPrefix=*/false,
diag::expected_sil_value_name) ||
P.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;
// Lookup the global variable declaration for this sil_global.
auto VD =
lookupGlobalDecl(GlobalName, GlobalLinkage.getValue(), GlobalType, P);
if (!VD) {
P.diagnose(NameLoc, diag::sil_global_variable_not_found, GlobalName);
return true;
}
auto *GV = SILGlobalVariable::create(
M, GlobalLinkage.getValue(), isSerialized, GlobalName.str(), GlobalType,
RegularLocation(NameLoc), VD.getValue());
GV->setLet(isLet);
// Parse static initializer if exists.
if (State.P.consumeIf(tok::equal) && State.P.consumeIf(tok::l_brace)) {
SILBuilder B(GV);
do {
State.parseSILInstruction(B);
} while (! State.P.consumeIf(tok::r_brace));
}
return false;
}
/// decl-sil-property: [[only in SIL mode]]
/// 'sil_property' sil-decl-ref '(' sil-key-path-pattern-component ')'
bool SILParserState::parseSILProperty(Parser &P) {
Lexer::SILBodyRAII Tmp(*P.L);
auto loc = P.consumeToken(tok::kw_sil_property);
auto InstLoc = RegularLocation(loc);
SILParser SP(P);
IsSerialized_t Serialized = IsNotSerialized;
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, SP, M))
return true;
ValueDecl *VD;
if (SP.parseSILDottedPath(VD))
return true;
GenericParamList *patternParams;
GenericEnvironment *patternEnv;
patternParams = P.maybeParseGenericParams().getPtrOrNull();
patternEnv = handleSILGenericParams(patternParams, &P.SF);
if (patternEnv) {
if (patternEnv->getGenericSignature().getCanonicalSignature() !=
VD->getInnermostDeclContext()
->getGenericSignatureOfContext()
.getCanonicalSignature()) {
P.diagnose(loc, diag::sil_property_generic_signature_mismatch);
return true;
}
} else {
if (VD->getInnermostDeclContext()->getGenericSignatureOfContext()) {
P.diagnose(loc, diag::sil_property_generic_signature_mismatch);
return true;
}
}
Identifier ComponentKind;
Optional<KeyPathPatternComponent> Component;
SourceLoc ComponentLoc;
SmallVector<SILType, 4> OperandTypes;
if (P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "("))
return true;
if (!P.consumeIf(tok::r_paren)) {
KeyPathPatternComponent parsedComponent;
if (P.parseIdentifier(ComponentKind, ComponentLoc,
/*diagnoseDollarPrefix=*/false,
diag::expected_tok_in_sil_instr, "component kind")
|| SP.parseKeyPathPatternComponent(parsedComponent, OperandTypes,
ComponentLoc, ComponentKind, InstLoc,
patternEnv, patternParams)
|| P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")"))
return true;
Component = std::move(parsedComponent);
}
SILProperty::create(M, Serialized,
cast<AbstractStorageDecl>(VD), Component);
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 SILParserState::parseSILVTable(Parser &P) {
P.consumeToken(tok::kw_sil_vtable);
SILParser VTableState(P);
IsSerialized_t Serialized = IsNotSerialized;
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr,
VTableState, M))
return true;
// 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<ValueDecl*, ModuleDecl *> Res =
lookupTopDecl(P, Name, /*typeLookup=*/true);
assert(Res.is<ValueDecl*>() && "Class look-up should return a Decl");
ValueDecl *VD = Res.get<ValueDecl*>();
if (!VD) {
P.diagnose(Loc, diag::sil_vtable_class_not_found, Name);
return true;
}
auto *theClass = dyn_cast<ClassDecl>(VD);
if (!theClass) {
P.diagnose(Loc, diag::sil_vtable_class_not_found, Name);
return true;
}
SourceLoc LBraceLoc = P.Tok.getLoc();
P.consumeToken(tok::l_brace);
// We need to turn on InSILBody to parse SILDeclRef.
Lexer::SILBodyRAII Tmp(*P.L);
// Parse the entry list.
std::vector<SILVTable::Entry> vtableEntries;
if (P.Tok.isNot(tok::r_brace)) {
do {
SILDeclRef Ref;
Identifier FuncName;
SourceLoc FuncLoc;
if (VTableState.parseSILDeclRef(Ref, true))
return true;
SILFunction *Func = nullptr;
if (P.Tok.is(tok::kw_nil)) {
P.consumeToken();
} else {
if (P.parseToken(tok::colon, diag::expected_sil_vtable_colon) ||
P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
VTableState.parseSILIdentifier(FuncName, FuncLoc,
diag::expected_sil_value_name))
return true;
Func = M.lookUpFunction(FuncName.str());
if (!Func) {
P.diagnose(FuncLoc, diag::sil_vtable_func_not_found, FuncName);
return true;
}
}
auto Kind = SILVTable::Entry::Kind::Normal;
bool NonOverridden = false;
while (P.Tok.is(tok::l_square)) {
P.consumeToken(tok::l_square);
if (P.Tok.isNot(tok::identifier)) {
P.diagnose(P.Tok.getLoc(), diag::sil_vtable_bad_entry_kind);
return true;
}
if (P.Tok.getText() == "override") {
P.consumeToken();
Kind = SILVTable::Entry::Kind::Override;
} else if (P.Tok.getText() == "inherited") {
P.consumeToken();
Kind = SILVTable::Entry::Kind::Inherited;
} else if (P.Tok.getText() == "nonoverridden") {
P.consumeToken();
NonOverridden = true;
} else {
P.diagnose(P.Tok.getLoc(), diag::sil_vtable_bad_entry_kind);
return true;
}
if (P.parseToken(tok::r_square, diag::sil_vtable_expect_rsquare))
return true;
}
vtableEntries.emplace_back(Ref, Func, Kind, NonOverridden);
} while (P.Tok.isNot(tok::r_brace) && P.Tok.isNot(tok::eof));
}
SourceLoc RBraceLoc;
P.parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace,
LBraceLoc);
SILVTable::create(M, theClass, Serialized, 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<ValueDecl*, ModuleDecl *> Res =
lookupTopDecl(P, DeclName, /*typeLookup=*/true);
assert(Res.is<ValueDecl*>() && "Protocol look-up should return a Decl");
ValueDecl *VD = Res.get<ValueDecl*>();
if (!VD) {
P.diagnose(DeclLoc, diag::sil_witness_protocol_not_found, DeclName);
return nullptr;
}
auto *proto = dyn_cast<ProtocolDecl>(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<ValueDecl *, 4> 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<AssociatedTypeDecl>(VD);
}
static bool parseAssociatedTypePath(SILParser &SP,
SmallVectorImpl<Identifier> &path) {
do {
Identifier name;
SourceLoc loc;
if (SP.parseSILIdentifier(name, loc, diag::expected_sil_value_name))
return false;
path.push_back(name);
} while (SP.P.consumeIf(tok::period));
return true;
}
static bool matchesAssociatedTypePath(CanType assocType,
ArrayRef<Identifier> path) {
if (auto memberType = dyn_cast<DependentMemberType>(assocType)) {
return (!path.empty() &&
memberType->getName() == path.back() &&
matchesAssociatedTypePath(memberType.getBase(), path.drop_back()));
} else {
assert(isa<GenericTypeParamType>(assocType));
return path.empty();
}
}
static CanType parseAssociatedTypePath(Parser &P, SILParser &SP,
ProtocolDecl *proto) {
SourceLoc loc = SP.P.Tok.getLoc();
SmallVector<Identifier, 4> path;
if (!parseAssociatedTypePath(SP, path))
return CanType();
// This is only used for parsing associated conformances, so we can
// go ahead and just search the requirement signature for something that
// matches the path.
for (auto &reqt : proto->getRequirementSignature()) {
if (reqt.getKind() != RequirementKind::Conformance)
continue;
CanType assocType = reqt.getFirstType()->getCanonicalType();
if (matchesAssociatedTypePath(assocType, path))
return assocType;
}
SmallString<128> name;
name += path[0].str();
for (auto elt : makeArrayRef(path).slice(1)) {
name += '.';
name += elt.str();
}
P.diagnose(loc, diag::sil_witness_assoc_conf_not_found, name);
return CanType();
}
static ProtocolConformanceRef
parseRootProtocolConformance(Parser &P, SILParser &SP, Type ConformingTy,
ProtocolDecl *&proto) {
const StringRef ModuleKeyword = "module";
Identifier ModuleName;
SourceLoc Loc, KeywordLoc;
proto = parseProtocolDecl(P, SP);
if (!proto)
return ProtocolConformanceRef();
if (P.parseSpecificIdentifier(
ModuleKeyword, KeywordLoc,
Diagnostic(diag::expected_tok_in_sil_instr, ModuleKeyword)) ||
SP.parseSILIdentifier(ModuleName, Loc, diag::expected_sil_value_name))
return ProtocolConformanceRef();
// 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<BoundGenericType>())
lookupTy = bound->getDecl()->getDeclaredType();
auto lookup = P.SF.getParentModule()->lookupConformance(lookupTy, proto);
if (lookup.isInvalid()) {
P.diagnose(KeywordLoc, diag::sil_witness_protocol_conformance_not_found);
return ProtocolConformanceRef();
}
return lookup;
}
/// 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.
ProtocolConformanceRef SILParser::parseProtocolConformance(
ProtocolDecl *&proto,
GenericEnvironment *&genericEnv,
GenericParamList *&genericParams) {
// Make sure we don't leave it uninitialized in the caller
genericEnv = nullptr;
genericParams = P.maybeParseGenericParams().getPtrOrNull();
if (genericParams) {
genericEnv = handleSILGenericParams(genericParams, &P.SF);
}
return parseProtocolConformanceHelper(proto, genericEnv, genericParams);
}
ProtocolConformanceRef SILParser::parseProtocolConformanceHelper(
ProtocolDecl *&proto,
GenericEnvironment *witnessEnv,
GenericParamList *witnessParams) {
// Parse AST type.
ParserResult<TypeRepr> TyR = P.parseType();
if (TyR.isNull())
return ProtocolConformanceRef();
if (witnessEnv == nullptr)
witnessEnv = ContextGenericEnv;
if (witnessParams == nullptr)
witnessParams = ContextGenericParams;
const auto ConformingTy =
performTypeResolution(TyR.get(), /*IsSILType=*/false,
witnessEnv, witnessParams);
if (ConformingTy->hasError())
return ProtocolConformanceRef();
if (P.parseToken(tok::colon, diag::expected_sil_witness_colon))
return ProtocolConformanceRef();
if (P.Tok.is(tok::identifier) && P.Tok.getText() == "specialize") {
P.consumeToken();
// Parse substitutions for specialized conformance.
SmallVector<ParsedSubstitution, 4> parsedSubs;
if (parseSubstitutions(parsedSubs, witnessEnv, witnessParams))
return ProtocolConformanceRef();
if (P.parseToken(tok::l_paren, diag::expected_sil_witness_lparen))
return ProtocolConformanceRef();
ProtocolDecl *dummy;
GenericEnvironment *specializedEnv = nullptr;
GenericParamList *specializedParams = nullptr;
auto genericConform =
parseProtocolConformance(dummy, specializedEnv, specializedParams);
if (genericConform.isInvalid() || !genericConform.isConcrete())
return ProtocolConformanceRef();
if (P.parseToken(tok::r_paren, diag::expected_sil_witness_rparen))
return ProtocolConformanceRef();
SubstitutionMap subMap =
getApplySubstitutionsFromParsed(*this, specializedEnv, parsedSubs);
if (!subMap)
return ProtocolConformanceRef();
auto result = P.Context.getSpecializedConformance(
ConformingTy, genericConform.getConcrete(), subMap);
return ProtocolConformanceRef(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 ProtocolConformanceRef();
auto baseConform = parseProtocolConformance();
if (baseConform.isInvalid() || !baseConform.isConcrete())
return ProtocolConformanceRef();
if (P.parseToken(tok::r_paren, diag::expected_sil_witness_rparen))
return ProtocolConformanceRef();
auto result = P.Context.getInheritedConformance(ConformingTy,
baseConform.getConcrete());
return ProtocolConformanceRef(result);
}
auto retVal =
parseRootProtocolConformance(P, *this, ConformingTy, proto);
return retVal;
}
/// Parser a single SIL vtable entry and add it to either \p witnessEntries
/// or \c conditionalConformances.
static bool parseSILWitnessTableEntry(
Parser &P,
SILModule &M,
ProtocolDecl *proto,
GenericEnvironment *witnessEnv,
GenericParamList *witnessParams,
SILParser &witnessState,
std::vector<SILWitnessTable::Entry> &witnessEntries,
std::vector<SILWitnessTable::ConditionalConformance>
&conditionalConformances) {
Identifier EntryKeyword;
SourceLoc KeywordLoc;
if (P.parseIdentifier(EntryKeyword, KeywordLoc,
/*diagnoseDollarPrefix=*/false,
diag::expected_tok_in_sil_instr,
"method, associated_type, associated_type_protocol"
", base_protocol, no_default"))
return true;
if (EntryKeyword.str() == "no_default") {
witnessEntries.push_back(SILDefaultWitnessTable::Entry());
return false;
}
if (EntryKeyword.str() == "base_protocol") {
ProtocolDecl *proto = parseProtocolDecl(P, witnessState);
if (!proto)
return true;
if (P.parseToken(tok::colon, diag::expected_sil_witness_colon))
return true;
auto conform =
witnessState.parseProtocolConformance();
// Ignore invalid and abstract witness entries.
if (conform.isInvalid() || !conform.isConcrete())
return false;
witnessEntries.push_back(
SILWitnessTable::BaseProtocolWitness{proto, conform.getConcrete()});
return false;
}
if (EntryKeyword.str() == "associated_type_protocol" ||
EntryKeyword.str() == "conditional_conformance") {
if (P.parseToken(tok::l_paren, diag::expected_sil_witness_lparen))
return true;
CanType assocOrSubject;
if (EntryKeyword.str() == "associated_type_protocol") {
assocOrSubject = parseAssociatedTypePath(P, witnessState, proto);
} else {
// Parse AST type.
ParserResult<TypeRepr> TyR = P.parseType();
if (TyR.isNull())
return true;
const auto Ty =
swift::performTypeResolution(TyR.get(), P.Context,
/*isSILMode=*/false,
/*isSILType=*/false,
witnessEnv,
witnessParams,
&P.SF);
if (Ty->hasError())
return true;
assocOrSubject = Ty->getCanonicalType();
}
if (!assocOrSubject)
return true;
if (P.parseToken(tok::colon, diag::expected_sil_witness_colon))
return true;
ProtocolDecl *proto = parseProtocolDecl(P, witnessState);
if (!proto)
return true;
if (P.parseToken(tok::r_paren, diag::expected_sil_witness_rparen) ||
P.parseToken(tok::colon, diag::expected_sil_witness_colon))
return true;
ProtocolConformanceRef conformance(proto);
if (P.Tok.getText() != "dependent") {
auto concrete =
witnessState.parseProtocolConformance();
// Ignore invalid and abstract witness entries.
if (concrete.isInvalid() || !concrete.isConcrete())
return false;
conformance = concrete;
} else {
P.consumeToken();
}
if (EntryKeyword.str() == "associated_type_protocol")
witnessEntries.push_back(
SILWitnessTable::AssociatedTypeProtocolWitness{assocOrSubject,
proto,
conformance});
else
conditionalConformances.push_back(
SILWitnessTable::ConditionalConformance{assocOrSubject,
conformance});
return false;
}
if (EntryKeyword.str() == "associated_type") {
AssociatedTypeDecl *assoc = parseAssociatedTypeDecl(P, witnessState,
proto);
if (!assoc)
return true;
if (P.parseToken(tok::colon, diag::expected_sil_witness_colon))
return true;
// Parse AST type.
ParserResult<TypeRepr> TyR = P.parseType();
if (TyR.isNull())
return true;
const auto Ty =
swift::performTypeResolution(TyR.get(), P.Context,
/*isSILMode=*/false,
/*isSILType=*/false,
witnessEnv, witnessParams,
&P.SF);
if (Ty->hasError())
return true;
witnessEntries.push_back(
SILWitnessTable::AssociatedTypeWitness{assoc, Ty->getCanonicalType()});
return false;
}
if (EntryKeyword.str() != "method") {
P.diagnose(KeywordLoc, diag::expected_tok_in_sil_instr, "method");
return true;
}
SILDeclRef Ref;
Identifier FuncName;
SourceLoc FuncLoc;
if (witnessState.parseSILDeclRef(Ref, true) ||
P.parseToken(tok::colon, diag::expected_sil_witness_colon))
return true;
SILFunction *Func = nullptr;
if (P.Tok.is(tok::kw_nil)) {
P.consumeToken();
} else {
if (P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
witnessState.parseSILIdentifier(FuncName, FuncLoc,
diag::expected_sil_value_name))
return true;
Func = M.lookUpFunction(FuncName.str());
if (!Func) {
P.diagnose(FuncLoc, diag::sil_witness_func_not_found, FuncName);
return true;
}
}
witnessEntries.push_back(SILWitnessTable::MethodWitness{
Ref, Func
});
return false;
}
/// 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 SILParserState::parseSILWitnessTable(Parser &P) {
P.consumeToken(tok::kw_sil_witness_table);
SILParser WitnessState(P);
// Parse the linkage.
Optional<SILLinkage> Linkage;
parseSILLinkage(Linkage, P);
IsSerialized_t isSerialized = IsNotSerialized;
if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr,
WitnessState, M))
return true;
// Parse the protocol conformance.
ProtocolDecl *proto;
GenericEnvironment *witnessEnv = nullptr;
GenericParamList *witnessParams = nullptr;
auto conf = WitnessState.parseProtocolConformance(proto,
witnessEnv,
witnessParams);
WitnessState.ContextGenericEnv = witnessEnv;
WitnessState.ContextGenericParams = witnessParams;
// FIXME: should we really allow a specialized or inherited conformance here?
RootProtocolConformance *theConformance = nullptr;
if (conf.isConcrete())
theConformance = conf.getConcrete()->getRootConformance();
SILWitnessTable *wt = nullptr;
if (theConformance) {
wt = 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 (P.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(M, *Linkage, theConformance);
return false;
}
if (!theConformance) {
P.diagnose(P.Tok, diag::sil_witness_protocol_conformance_not_found);
return true;
}
SourceLoc LBraceLoc = P.Tok.getLoc();
P.consumeToken(tok::l_brace);
// We need to turn on InSILBody to parse SILDeclRef.
Lexer::SILBodyRAII Tmp(*P.L);
// Parse the entry list.
std::vector<SILWitnessTable::Entry> witnessEntries;
std::vector<SILWitnessTable::ConditionalConformance> conditionalConformances;
if (P.Tok.isNot(tok::r_brace)) {
do {
if (parseSILWitnessTableEntry(P, M, proto, witnessEnv, witnessParams,
WitnessState, witnessEntries,
conditionalConformances))
return true;
} while (P.Tok.isNot(tok::r_brace) && P.Tok.isNot(tok::eof));
}
SourceLoc RBraceLoc;
P.parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace,
LBraceLoc);
// Default to public linkage.
if (!Linkage)
Linkage = SILLinkage::Public;
if (!wt)
wt = SILWitnessTable::create(M, *Linkage, theConformance);
else
wt->setLinkage(*Linkage);
wt->convertToDefinition(witnessEntries, conditionalConformances,
isSerialized);
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:
/// sil-witness-entry
/// 'no_default'
bool SILParserState::parseSILDefaultWitnessTable(Parser &P) {
P.consumeToken(tok::kw_sil_default_witness_table);
SILParser WitnessState(P);
// Parse the linkage.
Optional<SILLinkage> Linkage;
parseSILLinkage(Linkage, P);
// Parse the protocol.
ProtocolDecl *protocol = parseProtocolDecl(P, WitnessState);
if (!protocol)
return true;
WitnessState.ContextGenericEnv = protocol->getGenericEnvironment();
WitnessState.ContextGenericParams = protocol->getGenericParams();
// Parse the body.
SourceLoc LBraceLoc = P.Tok.getLoc();
P.consumeToken(tok::l_brace);
// We need to turn on InSILBody to parse SILDeclRef.
Lexer::SILBodyRAII Tmp(*P.L);
// Parse the entry list.
std::vector<SILWitnessTable::Entry> witnessEntries;
std::vector<SILWitnessTable::ConditionalConformance> conditionalConformances;
if (P.Tok.isNot(tok::r_brace)) {
do {
if (parseSILWitnessTableEntry(P, M, protocol,
protocol->getGenericEnvironment(),
protocol->getGenericParams(),
WitnessState, witnessEntries,
conditionalConformances))
return true;
} while (P.Tok.isNot(tok::r_brace) && P.Tok.isNot(tok::eof));
}
SourceLoc RBraceLoc;
P.parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace,
LBraceLoc);
// Default to public linkage.
if (!Linkage)
Linkage = SILLinkage::Public;
SILDefaultWitnessTable::create(M, *Linkage, protocol, witnessEntries);
return false;
}
/// decl-sil-differentiability-witness ::=
/// 'sil_differentiability_witness'
/// ('[' 'serialized' ']')?
/// sil-linkage?
/// sil-differentiability-witness-config-and-function
/// decl-sil-differentiability-witness-body?
///
/// decl-sil-differentiability-witness-body ::=
/// '{'
/// ('jvp' sil-function-name ':' sil-type)?
/// ('vjp' sil-function-name ':' sil-type)?
/// '}'
///
/// index-subset ::=
/// [0-9]+ (' ' [0-9]+)*
bool SILParserState::parseSILDifferentiabilityWitness(Parser &P) {
auto loc = P.consumeToken(tok::kw_sil_differentiability_witness);
auto silLoc = RegularLocation(loc);
SILParser State(P);
// Parse the linkage.
Optional<SILLinkage> linkage;
if (parseSILLinkage(linkage, P))
return true;
// Parse '[serialized]' flag (optional).
bool isSerialized = false;
SourceLoc serializedTokLoc;
if (P.Tok.is(tok::l_square) && P.isIdentifier(P.peekToken(), "serialized")) {
isSerialized = true;
serializedTokLoc = P.Tok.getLoc();
P.consumeToken(tok::l_square);
P.consumeToken(tok::identifier);
if (P.parseToken(tok::r_square, diag::sil_diff_witness_expected_token, "]"))
return true;
}
// We need to turn on InSILBody to parse the function references.
Lexer::SILBodyRAII tmp(*P.L);
auto configAndFn =
parseSILDifferentiabilityWitnessConfigAndFunction(P, State, silLoc);
if (!configAndFn) {
return true;
}
auto config = configAndFn->first;
auto originalFn = configAndFn->second;
// If this is just a declaration, create the declaration now and return.
if (!P.Tok.is(tok::l_brace)) {
if (isSerialized) {
P.diagnose(serializedTokLoc,
diag::sil_diff_witness_serialized_declaration);
return true;
}
SILDifferentiabilityWitness::createDeclaration(
M, linkage ? *linkage : SILLinkage::DefaultForDeclaration, originalFn,
config.parameterIndices, config.resultIndices,
config.derivativeGenericSignature);
return false;
}
// This is a definition, so parse differentiability witness body.
SILFunction *jvp = nullptr;
SILFunction *vjp = nullptr;
if (P.Tok.is(tok::l_brace)) {
// Parse '{'.
SourceLoc lBraceLoc;
P.consumeIf(tok::l_brace, lBraceLoc);
// Parse JVP (optional).
if (P.isIdentifier(P.Tok, "jvp")) {
P.consumeToken(tok::identifier);
if (P.parseToken(tok::colon, diag::sil_diff_witness_expected_token, ":"))
return true;
if (State.parseSILFunctionRef(silLoc, jvp))
return true;
}
// Parse VJP (optional).
if (P.isIdentifier(P.Tok, "vjp")) {
P.consumeToken(tok::identifier);
if (P.parseToken(tok::colon, diag::sil_diff_witness_expected_token, ":"))
return true;
if (State.parseSILFunctionRef(silLoc, vjp))
return true;
}
// Parse '}'.
SourceLoc rBraceLoc;
if (P.parseMatchingToken(tok::r_brace, rBraceLoc, diag::expected_sil_rbrace,
lBraceLoc))
return true;
}
SILDifferentiabilityWitness::createDefinition(
M, linkage ? *linkage : SILLinkage::DefaultForDefinition, originalFn,
config.parameterIndices, config.resultIndices,
config.derivativeGenericSignature, jvp, vjp, isSerialized);
return false;
}
llvm::Optional<llvm::coverage::Counter> 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;
const Identifier Operator = P.Context.getIdentifier(P.Tok.getText());
const SourceLoc Loc = P.consumeToken();
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 PGOFuncName 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 SILParserState::parseSILCoverageMap(Parser &P) {
P.consumeToken(tok::kw_sil_coverage_map);
SILParser State(P);
// Parse the filename.
Identifier Filename;
SourceLoc FileLoc;
if (State.parseSILIdentifier(Filename, FileLoc,
diag::expected_sil_value_name))
return true;
// Parse the covered name.
if (!P.Tok.is(tok::string_literal)) {
P.diagnose(P.Tok, diag::sil_coverage_expected_quote);
return true;
}
StringRef FuncName = P.Tok.getText().drop_front().drop_back();
P.consumeToken();
// Parse the PGO func name.
if (!P.Tok.is(tok::string_literal)) {
P.diagnose(P.Tok, diag::sil_coverage_expected_quote);
return true;
}
StringRef PGOFuncName = P.Tok.getText().drop_front().drop_back();
P.consumeToken();
uint64_t Hash;
if (State.parseInteger(Hash, diag::sil_coverage_invalid_hash))
return true;
if (!P.Tok.is(tok::l_brace)) {
P.diagnose(P.Tok, diag::sil_coverage_expected_lbrace);
return true;
}
SourceLoc LBraceLoc = P.Tok.getLoc();
P.consumeToken(tok::l_brace);
llvm::coverage::CounterExpressionBuilder Builder;
std::vector<SILCoverageMap::MappedRegion> Regions;
bool BodyHasError = false;
if (P.Tok.isNot(tok::r_brace)) {
do {
unsigned StartLine, StartCol, EndLine, EndCol;
if (State.parseInteger(StartLine, diag::sil_coverage_expected_loc) ||
P.parseToken(tok::colon, diag::sil_coverage_expected_loc) ||
State.parseInteger(StartCol, diag::sil_coverage_expected_loc) ||
P.parseToken(tok::arrow, diag::sil_coverage_expected_arrow) ||
State.parseInteger(EndLine, diag::sil_coverage_expected_loc) ||
P.parseToken(tok::colon, diag::sil_coverage_expected_loc) ||
State.parseInteger(EndCol, diag::sil_coverage_expected_loc)) {
BodyHasError = true;
break;
}
if (P.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 (P.Tok.isNot(tok::r_brace) && P.Tok.isNot(tok::eof));
}
if (BodyHasError)
P.skipUntilDeclRBrace();
SourceLoc RBraceLoc;
P.parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace,
LBraceLoc);
if (!BodyHasError)
SILCoverageMap::create(M, Filename.str(), FuncName.str(), PGOFuncName.str(),
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 SILParserState::parseSILScope(Parser &P) {
P.consumeToken(tok::kw_sil_scope);
SILParser ScopeState(P);
SourceLoc SlotLoc = P.Tok.getLoc();
unsigned Slot;
if (ScopeState.parseInteger(Slot, diag::sil_invalid_scope_slot))
return true;
SourceLoc LBraceLoc = P.Tok.getLoc();
P.consumeToken(tok::l_brace);
StringRef Key = P.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 (P.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 = P.Tok.getLoc();
// We need to turn on InSILBody to parse the function reference.
Lexer::SILBodyRAII Tmp(*P.L);
GenericEnvironment *IgnoredEnv = nullptr;
GenericParamList *IgnoredParams = nullptr;
if ((ScopeState.parseGlobalName(FnName)) ||
P.parseToken(tok::colon, diag::expected_sil_colon_value_ref) ||
ScopeState.parseSILType(Ty, IgnoredEnv, IgnoredParams, true))
return true;
// The function doesn't exist yet. Create a zombie forward declaration.
auto FnTy = Ty.getAs<SILFunctionType>();
if (!FnTy || !Ty.isObject()) {
P.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 (P.Tok.getText() == "inlined_at") {
P.consumeToken();
if (ScopeState.parseScopeRef(InlinedAt))
return true;
}
SourceLoc RBraceLoc;
P.parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace,
LBraceLoc);
auto &Scope = ScopeSlots[Slot];
if (Scope) {
P.diagnose(SlotLoc, diag::sil_scope_redefined, Slot);
return true;
}
Scope = new (M) SILDebugScope(Loc, ParentFn, Parent, InlinedAt);
return false;
}