blob: 304bfc585748cfbfc27c9ee857e10ebb9c89672f [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.