Optional<T> SubstitutionMap::forEachParent( CanType type, llvm::SmallPtrSetImpl<CanType> &visitedParents, llvm::function_ref<Optional<T>(CanType, AssociatedTypeDecl *)> fn) const { // If we've already visited the parents of this type, stop. if (!visitedParents.insert(type).second) return None; auto foundParents = parentMap.find(type.getPointer()); if (foundParents != parentMap.end()) { for (auto parent : foundParents->second) { if (auto result = fn(parent.first, parent.second)) return result; } } if (auto archetypeType = dyn_cast<ArchetypeType>(type)) if (auto *parent = archetypeType->getParent()) return fn(CanType(parent), archetypeType->getAssocType()); if (auto memberType = dyn_cast<DependentMemberType>(type)) return fn(CanType(memberType->getBase()), memberType->getAssocType()); return None; }
static void getModuleFileAncestors( ModuleFile *F, llvm::SmallPtrSetImpl<ModuleFile *> &Ancestors) { Ancestors.insert(F); for (ModuleFile *Importer : F->ImportedBy) getModuleFileAncestors(Importer, Ancestors); }
void findExtensionsFromConformingProtocols(Decl *D, llvm::SmallPtrSetImpl<ExtensionDecl*> &Results) { NominalTypeDecl* NTD = dyn_cast<NominalTypeDecl>(D); if (!NTD || NTD->getKind() == DeclKind::Protocol) return; std::vector<NominalTypeDecl*> Unhandled; auto addTypeLocNominal = [&](TypeLoc TL){ if (TL.getType()) { if (auto D = TL.getType()->getAnyNominal()) { Unhandled.push_back(D); } } }; for (auto TL : NTD->getInherited()) { addTypeLocNominal(TL); } while(!Unhandled.empty()) { NominalTypeDecl* Back = Unhandled.back(); Unhandled.pop_back(); for (ExtensionDecl *E : Back->getExtensions()) { if(E->isConstrainedExtension()) Results.insert(E); for (auto TL : Back->getInherited()) { addTypeLocNominal(TL); } } } }
// Propagate liveness backwards from an initial set of blocks in our // LiveIn set. static void propagateLiveness(llvm::SmallPtrSetImpl<SILBasicBlock *> &LiveIn, SILBasicBlock *DefBB) { // First populate a worklist of predecessors. llvm::SmallVector<SILBasicBlock *, 64> Worklist; for (auto *BB : LiveIn) for (auto Pred : BB->getPreds()) Worklist.push_back(Pred); // Now propagate liveness backwards until we hit the alloc_box. while (!Worklist.empty()) { auto *BB = Worklist.pop_back_val(); // If it's already in the set, then we've already queued and/or // processed the predecessors. if (BB == DefBB || !LiveIn.insert(BB).second) continue; for (auto Pred : BB->getPreds()) Worklist.push_back(Pred); } }
/// \brief Issue an "unreachable code" diagnostic if the blocks contains or /// leads to another block that contains user code. /// /// Note, we rely on SILLocation information to determine if SILInstructions /// correspond to user code. static bool diagnoseUnreachableBlock(const SILBasicBlock &B, SILModule &M, const SILBasicBlockSet &Reachable, UnreachableUserCodeReportingState *State, const SILBasicBlock *TopLevelB, llvm::SmallPtrSetImpl<const SILBasicBlock*> &Visited){ if (Visited.count(&B)) return false; Visited.insert(&B); assert(State); for (auto I = B.begin(), E = B.end(); I != E; ++I) { SILLocation Loc = I->getLoc(); // If we've reached an implicit return, we have not found any user code and // can stop searching for it. if (Loc.is<ImplicitReturnLocation>() || Loc.isAutoGenerated()) return false; // Check if the instruction corresponds to user-written code, also make // sure we don't report an error twice for the same instruction. if (isUserCode(&*I) && !State->BlocksWithErrors.count(&B)) { // Emit the diagnostic. auto BrInfoIter = State->MetaMap.find(TopLevelB); assert(BrInfoIter != State->MetaMap.end()); auto BrInfo = BrInfoIter->second; switch (BrInfo.Kind) { case (UnreachableKind::FoldedBranch): // Emit the diagnostic on the unreachable block and emit the // note on the branch responsible for the unreachable code. diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::unreachable_code); diagnose(M.getASTContext(), BrInfo.Loc.getSourceLoc(), diag::unreachable_code_branch, BrInfo.CondIsAlwaysTrue); break; case (UnreachableKind::FoldedSwitchEnum): { // If we are warning about a switch condition being a constant, the main // emphasis should be on the condition (to ensure we have a single // message per switch). const SwitchStmt *SS = BrInfo.Loc.getAsASTNode<SwitchStmt>(); if (!SS) break; assert(SS); const Expr *SE = SS->getSubjectExpr(); diagnose(M.getASTContext(), SE->getLoc(), diag::switch_on_a_constant); diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::unreachable_code_note); break; } case (UnreachableKind::NoreturnCall): { // Specialcase when we are warning about unreachable code after a call // to a noreturn function. if (!BrInfo.Loc.isASTNode<ExplicitCastExpr>()) { assert(BrInfo.Loc.isASTNode<ApplyExpr>()); diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::unreachable_code); diagnose(M.getASTContext(), BrInfo.Loc.getSourceLoc(), diag::call_to_noreturn_note); } break; } } // Record that we've reported this unreachable block to avoid duplicates // in the future. State->BlocksWithErrors.insert(&B); return true; } } // This block could be empty if it's terminator has been folded. if (B.empty()) return false; // If we have not found user code in this block, inspect it's successors. // Check if at least one of the successors contains user code. for (auto I = B.succ_begin(), E = B.succ_end(); I != E; ++I) { SILBasicBlock *SB = *I; bool HasReachablePred = false; for (auto PI = SB->pred_begin(), PE = SB->pred_end(); PI != PE; ++PI) { if (Reachable.count(*PI)) HasReachablePred = true; } // If all of the predecessors of this successor are unreachable, check if // it contains user code. if (!HasReachablePred && diagnoseUnreachableBlock(*SB, M, Reachable, State, TopLevelB, Visited)) return true; } return false; }