static uint32_t getPicFlags(ArrayRef<FileFlags> Files) { // Check PIC/non-PIC compatibility. bool IsPic = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); for (const FileFlags &F : Files.slice(1)) { bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); if (IsPic && !IsPic2) warn(toString(F.File) + ": linking non-abicalls code with abicalls code " + toString(Files[0].File)); if (!IsPic && IsPic2) warn(toString(F.File) + ": linking abicalls code with non-abicalls code " + toString(Files[0].File)); } // Compute the result PIC/non-PIC flag. uint32_t Ret = Files[0].Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); for (const FileFlags &F : Files.slice(1)) Ret &= F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); // PIC code is inherently CPIC and may not set CPIC flag explicitly. if (Ret & EF_MIPS_PIC) Ret |= EF_MIPS_CPIC; return Ret; }
static void copyOrInitValuesInto(Initialization *init, ArrayRef<ManagedValue> &values, CanType type, SILLocation loc, SILGenFunction &gen) { static_assert(KIND == ImplodeKind::Forward || KIND == ImplodeKind::Copy, "Not handled by init"); bool isInit = (KIND == ImplodeKind::Forward); // If the element has non-tuple type, just serve it up to the initialization. auto tupleType = dyn_cast<TupleType>(type); if (!tupleType) { // We take the first value. ManagedValue result = values[0]; values = values.slice(1); init->copyOrInitValueInto(gen, loc, result, isInit); init->finishInitialization(gen); return; } bool implodeTuple = false; if (auto Address = init->getAddressOrNull()) { if (isa<GlobalAddrInst>(Address) && gen.getTypeLowering(type).getLoweredType().isTrivial(gen.SGM.M)) { // Implode tuples in initialization of globals if they are // of trivial types. implodeTuple = true; } } // If we can satisfy the tuple type by breaking up the aggregate // initialization, do so. if (!implodeTuple && init->canSplitIntoTupleElements()) { SmallVector<InitializationPtr, 4> subInitBuf; auto subInits = init->splitIntoTupleElements(gen, loc, type, subInitBuf); assert(subInits.size() == tupleType->getNumElements() && "initialization does not match tuple?!"); for (unsigned i = 0, e = subInits.size(); i < e; ++i) copyOrInitValuesInto<KIND>(subInits[i].get(), values, tupleType.getElementType(i), loc, gen); init->finishInitialization(gen); return; } // Otherwise, process this by turning the values corresponding to the tuple // into a single value (through an implosion) and then binding that value to // our initialization. SILValue scalar = implodeTupleValues<KIND>(values, gen, type, loc); // This will have just used up the first values in the list, pop them off. values = values.slice(getRValueSize(type)); init->copyOrInitValueInto(gen, loc, ManagedValue::forUnmanaged(scalar), isInit); init->finishInitialization(gen); }
std::pair<ArrayRef<Value *>, ArrayRef<Value *>> Vectorizer::splitOddVectorElts(ArrayRef<Value *> Chain, unsigned ElementSizeBits) { unsigned ElemSizeInBytes = ElementSizeBits / 8; unsigned SizeInBytes = ElemSizeInBytes * Chain.size(); unsigned NumRight = (SizeInBytes % 4) / ElemSizeInBytes; unsigned NumLeft = Chain.size() - NumRight; return std::make_pair(Chain.slice(0, NumLeft), Chain.slice(NumLeft)); }
static int ExecuteCC1Tool(ArrayRef<const char *> argv, StringRef Tool) { void *GetExecutablePathVP = (void *)(intptr_t) GetExecutablePath; if (Tool == "") return cc1_main(argv.slice(2), argv[0], GetExecutablePathVP); if (Tool == "as") return cc1as_main(argv.slice(2), argv[0], GetExecutablePathVP); // Reject unknown tools. llvm::errs() << "error: unknown integrated tool '" << Tool << "'\n"; return 1; }
DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes_, uint64_t Address, raw_ostream &WS, raw_ostream &CS) const { CommentStream = &CS; // ToDo: AMDGPUDisassembler supports only VI ISA. assert(AMDGPU::isVI(STI) && "Can disassemble only VI ISA."); const unsigned MaxInstBytesNum = (std::min)((size_t)8, Bytes_.size()); Bytes = Bytes_.slice(0, MaxInstBytesNum); DecodeStatus Res = MCDisassembler::Fail; do { // ToDo: better to switch encoding length using some bit predicate // but it is unknown yet, so try all we can // Try to decode DPP and SDWA first to solve conflict with VOP1 and VOP2 // encodings if (Bytes.size() >= 8) { const uint64_t QW = eatBytes<uint64_t>(Bytes); Res = tryDecodeInst(DecoderTableDPP64, MI, QW, Address); if (Res) break; Res = tryDecodeInst(DecoderTableSDWA64, MI, QW, Address); if (Res) break; } // Reinitialize Bytes as DPP64 could have eaten too much Bytes = Bytes_.slice(0, MaxInstBytesNum); // Try decode 32-bit instruction if (Bytes.size() < 4) break; const uint32_t DW = eatBytes<uint32_t>(Bytes); Res = tryDecodeInst(DecoderTableVI32, MI, DW, Address); if (Res) break; Res = tryDecodeInst(DecoderTableAMDGPU32, MI, DW, Address); if (Res) break; if (Bytes.size() < 4) break; const uint64_t QW = ((uint64_t)eatBytes<uint32_t>(Bytes) << 32) | DW; Res = tryDecodeInst(DecoderTableVI64, MI, QW, Address); if (Res) break; Res = tryDecodeInst(DecoderTableAMDGPU64, MI, QW, Address); } while (false); Size = Res ? (MaxInstBytesNum - Bytes.size()) : 0; return Res; }
void EhInputSection<ELFT>::split(ArrayRef<RelTy> Rels) { ArrayRef<uint8_t> Data = this->getSectionData(); unsigned RelI = 0; for (size_t Off = 0, End = Data.size(); Off != End;) { size_t Size = readEhRecordSize<ELFT>(Data.slice(Off)); this->Pieces.emplace_back(Off, Data.slice(Off, Size), getReloc(Off, Size, Rels, RelI)); // The empty record is the end marker. if (Size == 4) break; Off += Size; } }
template <class ELFT> uint8_t getFdeEncoding(ArrayRef<uint8_t> D) { if (D.size() < 8) fatal("CIE too small"); D = D.slice(8); uint8_t Version = readByte(D); if (Version != 1 && Version != 3) fatal("FDE version 1 or 3 expected, but got " + Twine((unsigned)Version)); const unsigned char *AugEnd = std::find(D.begin(), D.end(), '\0'); if (AugEnd == D.end()) fatal("corrupted CIE"); StringRef Aug(reinterpret_cast<const char *>(D.begin()), AugEnd - D.begin()); D = D.slice(Aug.size() + 1); // Code alignment factor should always be 1 for .eh_frame. if (readByte(D) != 1) fatal("CIE code alignment must be 1"); // Skip data alignment factor. skipLeb128(D); // Skip the return address register. In CIE version 1 this is a single // byte. In CIE version 3 this is an unsigned LEB128. if (Version == 1) readByte(D); else skipLeb128(D); // We only care about an 'R' value, but other records may precede an 'R' // record. Unfortunately records are not in TLV (type-length-value) format, // so we need to teach the linker how to skip records for each type. for (char C : Aug) { if (C == 'R') return readByte(D); if (C == 'z') { skipLeb128(D); continue; } if (C == 'P') { skipAugP<ELFT>(D); continue; } if (C == 'L') { readByte(D); continue; } fatal("unknown .eh_frame augmentation string: " + Aug); } return DW_EH_PE_absptr; }
static InitializationPtr prepareIndirectResultInit(SILGenFunction &gen, CanType resultType, ArrayRef<SILResultInfo> &allResults, MutableArrayRef<SILValue> &directResults, ArrayRef<SILArgument*> &indirectResultAddrs, SmallVectorImpl<CleanupHandle> &cleanups) { // Recursively decompose tuple types. if (auto resultTupleType = dyn_cast<TupleType>(resultType)) { auto tupleInit = new TupleInitialization(); tupleInit->SubInitializations.reserve(resultTupleType->getNumElements()); for (auto resultEltType : resultTupleType.getElementTypes()) { auto eltInit = prepareIndirectResultInit(gen, resultEltType, allResults, directResults, indirectResultAddrs, cleanups); tupleInit->SubInitializations.push_back(std::move(eltInit)); } return InitializationPtr(tupleInit); } // Okay, pull the next result off the list of results. auto result = allResults[0]; allResults = allResults.slice(1); // If it's indirect, we should be emitting into an argument. if (result.isIndirect()) { // Pull off the next indirect result argument. SILValue addr = indirectResultAddrs.front(); indirectResultAddrs = indirectResultAddrs.slice(1); // Create an initialization which will initialize it. auto &resultTL = gen.getTypeLowering(addr->getType()); auto temporary = gen.useBufferAsTemporary(addr, resultTL); // Remember the cleanup that will be activated. auto cleanup = temporary->getInitializedCleanup(); if (cleanup.isValid()) cleanups.push_back(cleanup); return InitializationPtr(temporary.release()); } // Otherwise, make an Initialization that stores the value in the // next element of the directResults array. auto init = new StoreResultInitialization(directResults[0], cleanups); directResults = directResults.slice(1); return InitializationPtr(init); }
// Split SHF_STRINGS section. Such section is a sequence of // null-terminated strings. static std::vector<SectionPiece> splitStrings(ArrayRef<uint8_t> Data, size_t EntSize) { std::vector<SectionPiece> V; size_t Off = 0; while (!Data.empty()) { size_t End = findNull(Data, EntSize); if (End == StringRef::npos) fatal("string is not null terminated"); size_t Size = End + EntSize; V.emplace_back(Off, Data.slice(0, Size)); Data = Data.slice(Size); Off += Size; } return V; }
std::pair<ArrayRef<Instruction *>, ArrayRef<Instruction *>> Vectorizer::splitOddVectorElts(ArrayRef<Instruction *> Chain, unsigned ElementSizeBits) { unsigned ElementSizeBytes = ElementSizeBits / 8; unsigned SizeBytes = ElementSizeBytes * Chain.size(); unsigned NumLeft = (SizeBytes - (SizeBytes % 4)) / ElementSizeBytes; if (NumLeft == Chain.size()) { if ((NumLeft & 1) == 0) NumLeft /= 2; // Split even in half else --NumLeft; // Split off last element } else if (NumLeft == 0) NumLeft = 1; return std::make_pair(Chain.slice(0, NumLeft), Chain.slice(NumLeft)); }
static ManagedValue emitBuiltinAssign(SILGenFunction &gen, SILLocation loc, SubstitutionList substitutions, ArrayRef<ManagedValue> args, CanFunctionType formalApplyType, SGFContext C) { assert(args.size() >= 2 && "assign should have two arguments"); assert(substitutions.size() == 1 && "assign should have a single substitution"); // The substitution determines the type of the thing we're destroying. CanType assignFormalType = substitutions[0].getReplacement()->getCanonicalType(); SILType assignType = gen.getLoweredType(assignFormalType); // Convert the destination pointer argument to a SIL address. SILValue addr = gen.B.createPointerToAddress(loc, args.back().getUnmanagedValue(), assignType.getAddressType(), /*isStrict*/ true); // Build the value to be assigned, reconstructing tuples if needed. auto src = RValue::withPreExplodedElements(args.slice(0, args.size() - 1), assignFormalType); std::move(src).assignInto(gen, loc, addr); return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); }
static void addParameters(ArrayRef<Identifier> &ArgNames, const ParameterList *paramList, TextEntity &Ent, SourceManager &SM, unsigned BufferID) { for (auto ¶m : *paramList) { StringRef Arg; if (!ArgNames.empty()) { Identifier Id = ArgNames.front(); Arg = Id.empty() ? "_" : Id.str(); ArgNames = ArgNames.slice(1); } if (auto typeRepr = param->getTypeLoc().getTypeRepr()) { SourceRange TypeRange = param->getTypeLoc().getSourceRange(); if (auto InOutTyR = dyn_cast_or_null<InOutTypeRepr>(typeRepr)) TypeRange = InOutTyR->getBase()->getSourceRange(); if (TypeRange.isInvalid()) continue; unsigned StartOffs = SM.getLocOffsetInBuffer(TypeRange.Start, BufferID); unsigned EndOffs = SM.getLocOffsetInBuffer(Lexer::getLocForEndOfToken(SM, TypeRange.End), BufferID); TextRange TR{ StartOffs, EndOffs-StartOffs }; TextEntity Param(param, Arg, TR, StartOffs); Ent.SubEntities.push_back(std::move(Param)); } } }
TypeSubstitutionMap GenericSignature::getSubstitutionMap(ArrayRef<Substitution> args) const { TypeSubstitutionMap subs; // An empty parameter list gives an empty map. if (getGenericParams().empty()) { assert(args.empty() && "substitutions but no generic params?!"); return subs; } // Seed the type map with pre-existing substitutions. for (auto depTy : getAllDependentTypes()) { auto replacement = args.front().getReplacement(); args = args.slice(1); if (auto subTy = depTy->getAs<SubstitutableType>()) { subs[subTy->getCanonicalType().getPointer()] = replacement; } else if (auto dTy = depTy->getAs<DependentMemberType>()) { subs[dTy->getCanonicalType().getPointer()] = replacement; } } assert(args.empty() && "did not use all substitutions?!"); return subs; }
// Read a byte and advance D by one byte. static uint8_t readByte(ArrayRef<uint8_t> &D) { if (D.empty()) fatal("corrupted or unsupported CIE information"); uint8_t B = D.front(); D = D.slice(1); return B; }
static ManagedValue emitBuiltinAssign(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C) { assert(args.size() >= 2 && "assign should have two arguments"); assert(substitutions.getReplacementTypes().size() == 1 && "assign should have a single substitution"); // The substitution determines the type of the thing we're destroying. CanType assignFormalType = substitutions.getReplacementTypes()[0]->getCanonicalType(); SILType assignType = SGF.getLoweredType(assignFormalType); // Convert the destination pointer argument to a SIL address. SILValue addr = SGF.B.createPointerToAddress(loc, args.back().getUnmanagedValue(), assignType.getAddressType(), /*isStrict*/ true, /*isInvariant*/ false); // Build the value to be assigned, reconstructing tuples if needed. auto src = RValue(SGF, args.slice(0, args.size() - 1), assignFormalType); std::move(src).ensurePlusOne(SGF, loc).assignInto(SGF, loc, addr); return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); }
std::error_code IndexedInstrProfReader::readNextRecord(InstrProfRecord &Record) { // Are we out of records? if (RecordIterator == Index->data_end()) return error(instrprof_error::eof); // Record the current function name. Record.Name = (*RecordIterator).Name; ArrayRef<uint64_t> Data = (*RecordIterator).Data; // Valid data starts with a hash and either a count or the number of counts. if (CurrentOffset + 1 > Data.size()) return error(instrprof_error::malformed); // First we have a function hash. Record.Hash = Data[CurrentOffset++]; // In version 1 we knew the number of counters implicitly, but in newer // versions we store the number of counters next. uint64_t NumCounts = FormatVersion == 1 ? Data.size() - CurrentOffset : Data[CurrentOffset++]; if (CurrentOffset + NumCounts > Data.size()) return error(instrprof_error::malformed); // And finally the counts themselves. Record.Counts = Data.slice(CurrentOffset, NumCounts); // If we've exhausted this function's data, increment the record. CurrentOffset += NumCounts; if (CurrentOffset == Data.size()) { ++RecordIterator; CurrentOffset = 0; } return success(); }
std::error_code IndexedInstrProfReader::getFunctionCounts( StringRef FuncName, uint64_t FuncHash, std::vector<uint64_t> &Counts) { auto Iter = Index->find(FuncName); if (Iter == Index->end()) return error(instrprof_error::unknown_function); // Found it. Look for counters with the right hash. ArrayRef<uint64_t> Data = (*Iter).Data; uint64_t NumCounts; for (uint64_t I = 0, E = Data.size(); I != E; I += NumCounts) { // The function hash comes first. uint64_t FoundHash = Data[I++]; // In v1, we have at least one count. Later, we have the number of counts. if (I == E) return error(instrprof_error::malformed); NumCounts = FormatVersion == 1 ? E - I : Data[I++]; // If we have more counts than data, this is bogus. if (I + NumCounts > E) return error(instrprof_error::malformed); // Check for a match and fill the vector if there is one. if (FoundHash == FuncHash) { Counts = Data.slice(I, NumCounts); return success(); } } return error(instrprof_error::hash_mismatch); }
ErrorOr<const typename MipsELFFile<ELFT>::Elf_Mips_RegInfo *> MipsELFFile<ELFT>::findRegInfoSec() const { using namespace llvm::ELF; if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_OPTIONS)) { auto contents = this->getSectionContents(sec); if (std::error_code ec = contents.getError()) return ec; ArrayRef<uint8_t> raw = contents.get(); while (!raw.empty()) { if (raw.size() < sizeof(Elf_Mips_Options)) return make_dynamic_error_code( StringRef("Invalid size of MIPS_OPTIONS section")); const auto *opt = reinterpret_cast<const Elf_Mips_Options *>(raw.data()); if (opt->kind == ODK_REGINFO) return &opt->getRegInfo(); raw = raw.slice(opt->size); } } else if (const Elf_Shdr *sec = findSectionByType(SHT_MIPS_REGINFO)) { auto contents = this->getSectionContents(sec); if (std::error_code ec = contents.getError()) return ec; ArrayRef<uint8_t> raw = contents.get(); if (raw.size() != sizeof(Elf_Mips_RegInfo)) return make_dynamic_error_code( StringRef("Invalid size of MIPS_REGINFO section")); return reinterpret_cast<const Elf_Mips_RegInfo *>(raw.data()); } return nullptr; }
static std::error_code getSymbolAuxData(const COFFObjectFile *Obj, COFFSymbolRef Symbol, uint8_t AuxSymbolIdx, const T *&Aux) { ArrayRef<uint8_t> AuxData = Obj->getSymbolAuxData(Symbol); AuxData = AuxData.slice(AuxSymbolIdx * Obj->getSymbolTableEntrySize()); Aux = reinterpret_cast<const T*>(AuxData.data()); return readobj_error::success; }
static ArrayRef<uint8_t> consumeDebugMagic(ArrayRef<uint8_t> Data, StringRef SecName) { // First 4 bytes are section magic. if (Data.size() < 4) fatal(SecName + " too short"); if (support::endian::read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC) fatal(SecName + " has an invalid magic"); return Data.slice(4); }
// Skip an integer encoded in the LEB128 format. // Actual number is not of interest because only the runtime needs it. // But we need to be at least able to skip it so that we can read // the field that follows a LEB128 number. static void skipLeb128(ArrayRef<uint8_t> &D) { while (!D.empty()) { uint8_t Val = D.front(); D = D.slice(1); if ((Val & 0x80) == 0) return; } fatal("corrupted or unsupported CIE information"); }
ArrayRef<typename elf::ObjectFile<ELFT>::Elf_Word> elf::ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) { const ELFFile<ELFT> &Obj = this->ELFObj; ArrayRef<Elf_Word> Entries = check(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec)); if (Entries.empty() || Entries[0] != GRP_COMDAT) fatal("unsupported SHT_GROUP format"); return Entries.slice(1); }
template <class ELFT> static void skipAugP(ArrayRef<uint8_t> &D) { uint8_t Enc = readByte(D); if ((Enc & 0xf0) == DW_EH_PE_aligned) fatal("DW_EH_PE_aligned encoding is not supported"); size_t Size = getAugPSize<ELFT>(Enc); if (Size >= D.size()) fatal("corrupted CIE"); D = D.slice(Size); }
// Split non-SHF_STRINGS section. Such section is a sequence of // fixed size records. static std::vector<SectionPiece> splitNonStrings(ArrayRef<uint8_t> Data, size_t EntSize) { std::vector<SectionPiece> V; size_t Size = Data.size(); assert((Size % EntSize) == 0); for (unsigned I = 0, N = Size; I != N; I += EntSize) V.emplace_back(I, Data.slice(I, EntSize)); return V; }
// Split non-SHF_STRINGS section. Such section is a sequence of // fixed size records. void MergeInputSection::splitNonStrings(ArrayRef<uint8_t> Data, size_t EntSize) { size_t Size = Data.size(); assert((Size % EntSize) == 0); bool IsAlloc = Flags & SHF_ALLOC; for (size_t I = 0; I != Size; I += EntSize) Pieces.emplace_back(I, xxHash64(toStringRef(Data.slice(I, EntSize))), !IsAlloc); }
void CorDisasm::printInstruction(const MCInst *MI, size_t Address, size_t InstSize, ArrayRef<uint8_t> Bytes) const { outs() << format("%8" PRIx64 ":", Address); outs() << "\t"; dumpBytes(Bytes.slice(0, InstSize), outs()); IP->printInst(MI, outs(), "", *STI); outs() << "\n"; }
void GenericEnvironment:: getSubstitutionMap(ModuleDecl *mod, GenericSignature *sig, ArrayRef<Substitution> subs, SubstitutionMap &result) const { for (auto depTy : sig->getAllDependentTypes()) { // Map the interface type to a context type. auto contextTy = depTy.subst(mod, InterfaceToArchetypeMap, SubstOptions()); auto *archetype = contextTy->castTo<ArchetypeType>(); auto sub = subs.front(); subs = subs.slice(1); // Record the replacement type and its conformances. result.addSubstitution(CanType(archetype), sub.getReplacement()); result.addConformances(CanType(archetype), sub.getConformances()); } for (auto reqt : sig->getRequirements()) { if (reqt.getKind() != RequirementKind::SameType) continue; auto first = reqt.getFirstType()->getAs<DependentMemberType>(); auto second = reqt.getSecondType()->getAs<DependentMemberType>(); if (!first || !second) continue; auto archetype = mapTypeIntoContext(mod, first)->getAs<ArchetypeType>(); if (!archetype) continue; auto firstBase = first->getBase(); auto secondBase = second->getBase(); auto firstBaseArchetype = mapTypeIntoContext(mod, firstBase)->getAs<ArchetypeType>(); auto secondBaseArchetype = mapTypeIntoContext(mod, secondBase)->getAs<ArchetypeType>(); if (!firstBaseArchetype || !secondBaseArchetype) continue; if (archetype->getParent() != firstBaseArchetype) result.addParent(CanType(archetype), CanType(firstBaseArchetype), first->getAssocType()); if (archetype->getParent() != secondBaseArchetype) result.addParent(CanType(archetype), CanType(secondBaseArchetype), second->getAssocType()); } assert(subs.empty() && "did not use all substitutions?!"); }
// The length of the header data is always going to be 4 + 4 + 4*NumAtoms. DwarfAccelTable::DwarfAccelTable(ArrayRef<DwarfAccelTable::Atom> atomList, bool UseDieOffsets, bool UseStringOffsets) : Header(8 + (atomList.size() * 4)), HeaderData(atomList), Entries(Allocator), AtomsSize(0), UseDieOffsets(UseDieOffsets), UseStringOffsets(UseStringOffsets) { assert((atomList[0].type == dwarf::DW_ATOM_ext_types || atomList[0].type == dwarf::DW_ATOM_die_offset) && atomList[0].form == dwarf::DW_FORM_data4); for (const auto &Atom : atomList.slice(1)) AtomsSize += getSizeForForm(Atom.form); }
static void getWitnessMethodSubstitutions(ApplySite AI, SILFunction *F, ArrayRef<Substitution> Subs, SmallVectorImpl<Substitution> &NewSubs) { auto &Module = AI.getModule(); auto CalleeCanType = F->getLoweredFunctionType(); ProtocolDecl *proto = nullptr; if (CalleeCanType->getRepresentation() == SILFunctionTypeRepresentation::WitnessMethod) { proto = CalleeCanType->getDefaultWitnessMethodProtocol( *Module.getSwiftModule()); } ArrayRef<Substitution> origSubs = AI.getSubstitutions(); if (proto != nullptr) { // If the callee is a default witness method thunk, preserve substitutions // from the call site. NewSubs.append(origSubs.begin(), origSubs.end()); return; } // If the callee is a concrete witness method thunk, apply substitutions // from the conformance, and drop any substitutions derived from the Self // type. NewSubs.append(Subs.begin(), Subs.end()); if (auto generics = AI.getOrigCalleeType()->getGenericSignature()) { for (auto genericParam : generics->getAllDependentTypes()) { auto origSub = origSubs.front(); origSubs = origSubs.slice(1); // If the callee is a concrete witness method thunk, we ignore // generic parameters derived from 'self', the generic parameter at // depth 0, index 0. auto type = genericParam->getCanonicalType(); while (auto memberType = dyn_cast<DependentMemberType>(type)) { type = memberType.getBase(); } auto paramType = cast<GenericTypeParamType>(type); if (paramType->getDepth() == 0) { // There shouldn't be any other parameters at this depth. assert(paramType->getIndex() == 0); continue; } // Okay, remember this substitution. NewSubs.push_back(origSub); } } assert(origSubs.empty() && "subs not parallel to dependent types"); }
Expr *TypeChecker::foldSequence(SequenceExpr *expr, DeclContext *dc) { ArrayRef<Expr*> Elts = expr->getElements(); assert(Elts.size() > 1 && "inadequate number of elements in sequence"); assert((Elts.size() & 1) == 1 && "even number of elements in sequence"); Expr *LHS = Elts[0]; Elts = Elts.slice(1); Expr *Result = ::foldSequence(*this, dc, LHS, Elts, /*min precedence*/ 0); assert(Elts.empty()); return Result; }