//===--- Module.cpp - Swift Language Module Implementation ----------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements the Module class and subclasses. // //===----------------------------------------------------------------------===// #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/LinkLibrary.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" #include "swift/AST/NameLookup.h" #include "swift/AST/AST.h" #include "swift/AST/PrintOptions.h" #include "swift/Basic/SourceManager.h" #include "clang/Basic/Module.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/SaveAndRestore.h" using namespace swift; //===----------------------------------------------------------------------===// // Builtin Module Name lookup //===----------------------------------------------------------------------===// class BuiltinUnit::LookupCache { /// The cache of identifiers we've already looked up. We use a /// single hashtable for both types and values as a minor /// optimization; this prevents us from having both a builtin type /// and a builtin value with the same name, but that's okay. llvm::DenseMap Cache; public: void lookupValue(Identifier Name, NLKind LookupKind, const BuiltinUnit &M, SmallVectorImpl &Result); }; BuiltinUnit::LookupCache &BuiltinUnit::getCache() const { // FIXME: This leaks. Sticking this into ASTContext isn't enough because then // the DenseMap will leak. if (!Cache) const_cast(this)->Cache.reset(new LookupCache()); return *Cache; } void BuiltinUnit::LookupCache::lookupValue(Identifier Name, NLKind LookupKind, const BuiltinUnit &M, SmallVectorImpl &Result) { // Only qualified lookup ever finds anything in the builtin module. if (LookupKind != NLKind::QualifiedLookup) return; ValueDecl *&Entry = Cache[Name]; ASTContext &Ctx = M.getParentModule()->Ctx; if (Entry == 0) if (Type Ty = getBuiltinType(Ctx, Name.str())) Entry = new (Ctx) TypeAliasDecl(SourceLoc(), Name, SourceLoc(), TypeLoc::withoutLoc(Ty), const_cast(&M)); if (Entry == 0) Entry = getBuiltinValueDecl(Ctx, Name); if (Entry) Result.push_back(Entry); } // Out-of-line because std::unique_ptr wants LookupCache to be complete. BuiltinUnit::BuiltinUnit(Module &M) : FileUnit(FileUnitKind::Builtin, M) { } //===----------------------------------------------------------------------===// // Normal Module Name Lookup //===----------------------------------------------------------------------===// class SourceFile::LookupCache { llvm::DenseMap> TopLevelValues; llvm::DenseMap> ClassMembers; bool MemberCachePopulated = false; void doPopulateCache(ArrayRef decls, bool onlyOperators); void addToMemberCache(ArrayRef decls); void populateMemberCache(const SourceFile &SF); public: typedef Module::AccessPathTy AccessPathTy; LookupCache(const SourceFile &SF); void lookupValue(AccessPathTy AccessPath, Identifier Name, NLKind LookupKind, SmallVectorImpl &Result); void lookupVisibleDecls(AccessPathTy AccessPath, VisibleDeclConsumer &Consumer, NLKind LookupKind); void lookupClassMembers(AccessPathTy AccessPath, VisibleDeclConsumer &consumer, const SourceFile &SF); void lookupClassMember(AccessPathTy accessPath, Identifier name, SmallVectorImpl &results, const SourceFile &SF); SmallVector AllVisibleValues; }; using SourceLookupCache = SourceFile::LookupCache; SourceLookupCache &SourceFile::getCache() const { // FIXME: This leaks. Sticking this into ASTContext isn't enough because then // the DenseMap will leak. if (!Cache) const_cast(this)->Cache.reset(new SourceLookupCache(*this)); return *Cache; } void SourceLookupCache::doPopulateCache(ArrayRef decls, bool onlyOperators) { for (Decl *D : decls) { if (ValueDecl *VD = dyn_cast(D)) if (onlyOperators ? VD->getName().isOperator() : !VD->getName().empty()) TopLevelValues[VD->getName()].push_back(VD); if (NominalTypeDecl *NTD = dyn_cast(D)) doPopulateCache(NTD->getMembers(), true); if (ExtensionDecl *ED = dyn_cast(D)) doPopulateCache(ED->getMembers(), true); } } void SourceLookupCache::populateMemberCache(const SourceFile &SF) { for (const Decl *D : SF.Decls) { if (const NominalTypeDecl *NTD = dyn_cast(D)) { addToMemberCache(NTD->getMembers()); } else if (const ExtensionDecl *ED = dyn_cast(D)) { addToMemberCache(ED->getMembers()); } } } void SourceLookupCache::addToMemberCache(ArrayRef decls) { for (Decl *D : decls) { auto VD = dyn_cast(D); if (!VD) continue; if (auto NTD = dyn_cast(VD)) { assert(!VD->canBeAccessedByDynamicLookup() && "inner types cannot be accessed by dynamic lookup"); addToMemberCache(NTD->getMembers()); } else if (VD->canBeAccessedByDynamicLookup()) { ClassMembers[VD->getName()].push_back(VD); } } } /// Populate our cache on the first name lookup. SourceLookupCache::LookupCache(const SourceFile &SF) { doPopulateCache(SF.Decls, false); } void SourceLookupCache::lookupValue(AccessPathTy AccessPath, Identifier Name, NLKind LookupKind, SmallVectorImpl &Result) { assert(AccessPath.size() <= 1 && "can only refer to top-level decls"); // If this import is specific to some named type or decl ("import swift.int") // then filter out any lookups that don't match. if (AccessPath.size() == 1 && AccessPath.front().first != Name) return; auto I = TopLevelValues.find(Name); if (I == TopLevelValues.end()) return; Result.reserve(I->second.size()); for (ValueDecl *Elt : I->second) Result.push_back(Elt); } void SourceLookupCache::lookupVisibleDecls(AccessPathTy AccessPath, VisibleDeclConsumer &Consumer, NLKind LookupKind) { assert(AccessPath.size() <= 1 && "can only refer to top-level decls"); if (!AccessPath.empty()) { auto I = TopLevelValues.find(AccessPath.front().first); if (I == TopLevelValues.end()) return; for (auto vd : I->second) Consumer.foundDecl(vd, DeclVisibilityKind::VisibleAtTopLevel); return; } for (auto &tlv : TopLevelValues) { for (ValueDecl *vd : tlv.second) Consumer.foundDecl(vd, DeclVisibilityKind::VisibleAtTopLevel); } } void SourceLookupCache::lookupClassMembers(AccessPathTy accessPath, VisibleDeclConsumer &consumer, const SourceFile &SF) { if (!MemberCachePopulated) populateMemberCache(SF); assert(accessPath.size() <= 1 && "can only refer to top-level decls"); if (!accessPath.empty()) { for (auto &member : ClassMembers) { for (ValueDecl *vd : member.second) { Type ty = vd->getDeclContext()->getDeclaredTypeOfContext(); if (auto nominal = ty->getAnyNominal()) if (nominal->getName() == accessPath.front().first) consumer.foundDecl(vd, DeclVisibilityKind::DynamicLookup); } } return; } for (auto &member : ClassMembers) { for (ValueDecl *vd : member.second) consumer.foundDecl(vd, DeclVisibilityKind::DynamicLookup); } } void SourceLookupCache::lookupClassMember(AccessPathTy accessPath, Identifier name, SmallVectorImpl &results, const SourceFile &SF) { if (!MemberCachePopulated) populateMemberCache(SF); assert(accessPath.size() <= 1 && "can only refer to top-level decls"); auto iter = ClassMembers.find(name); if (iter == ClassMembers.end()) return; if (!accessPath.empty()) { for (ValueDecl *vd : iter->second) { Type ty = vd->getDeclContext()->getDeclaredTypeOfContext(); if (auto nominal = ty->getAnyNominal()) if (nominal->getName() == accessPath.front().first) results.push_back(vd); } return; } results.append(iter->second.begin(), iter->second.end()); } //===----------------------------------------------------------------------===// // Module Implementation //===----------------------------------------------------------------------===// void Module::addFile(FileUnit &newFile) { // Require Main and REPL files to be the first file added. assert(Files.empty() || !isa(newFile) || cast(newFile).Kind == SourceFileKind::Library || cast(newFile).Kind == SourceFileKind::SIL); Files.push_back(&newFile); } void Module::removeFile(FileUnit &existingFile) { // Do a reverse search; usually the file to be deleted will be at the end. std::reverse_iterator I(Files.end()), E(Files.begin()); I = std::find(I, E, &existingFile); assert(I != E); // Adjust for the std::reverse_iterator offset. ++I; Files.erase(I.base()); } #define FORWARD(name, args) \ for (const FileUnit *file : getFiles()) \ file->name args; void Module::lookupValue(AccessPathTy AccessPath, Identifier Name, NLKind LookupKind, SmallVectorImpl &Result) const { FORWARD(lookupValue, (AccessPath, Name, LookupKind, Result)); } void BuiltinUnit::lookupValue(Module::AccessPathTy accessPath, Identifier name, NLKind lookupKind, SmallVectorImpl &result) const { getCache().lookupValue(name, lookupKind, *this, result); } void SourceFile::lookupValue(Module::AccessPathTy accessPath, Identifier name, NLKind lookupKind, SmallVectorImpl &result) const { getCache().lookupValue(accessPath, name, lookupKind, result); } void Module::lookupVisibleDecls(AccessPathTy AccessPath, VisibleDeclConsumer &Consumer, NLKind LookupKind) const { FORWARD(lookupVisibleDecls, (AccessPath, Consumer, LookupKind)); } void SourceFile::lookupVisibleDecls(Module::AccessPathTy AccessPath, VisibleDeclConsumer &Consumer, NLKind LookupKind) const { getCache().lookupVisibleDecls(AccessPath, Consumer, LookupKind); } void Module::lookupClassMembers(AccessPathTy accessPath, VisibleDeclConsumer &consumer) const { FORWARD(lookupClassMembers, (accessPath, consumer)); } void SourceFile::lookupClassMembers(Module::AccessPathTy accessPath, VisibleDeclConsumer &consumer) const { getCache().lookupClassMembers(accessPath, consumer, *this); } void Module::lookupClassMember(AccessPathTy accessPath, Identifier name, SmallVectorImpl &results) const { FORWARD(lookupClassMember, (accessPath, name, results)); } void SourceFile::lookupClassMember(Module::AccessPathTy accessPath, Identifier name, SmallVectorImpl &results) const { getCache().lookupClassMember(accessPath, name, results, *this); } void Module::getTopLevelDecls(SmallVectorImpl &Results) const { FORWARD(getTopLevelDecls, (Results)); } void SourceFile::getTopLevelDecls(SmallVectorImpl &Results) const { Results.append(Decls.begin(), Decls.end()); } void Module::getDisplayDecls(SmallVectorImpl &Results) const { // FIXME: Should this do extra access control filtering? FORWARD(getDisplayDecls, (Results)); } ArrayRef BoundGenericType::getSubstitutions( Module *module, LazyResolver *resolver) { // FIXME: If there is no module, infer one. This is a hack for callers that // don't have access to the module. It will have to go away once we're // properly differentiating bound generic types based on the protocol // conformances visible from a given module. if (!module) { module = getDecl()->getParentModule(); } // If we already have a cached copy of the substitutions, return them. auto *canon = getCanonicalType()->castTo(); const ASTContext &ctx = canon->getASTContext(); if (auto known = ctx.getSubstitutions(canon)) return *known; // Compute the set of substitutions. llvm::SmallPtrSet knownArchetypes; SmallVector archetypeStack; TypeSubstitutionMap substitutions; auto genericParams = canon->getDecl()->getGenericParams(); unsigned index = 0; for (Type arg : canon->getGenericArgs()) { auto gp = genericParams->getParams()[index++]; auto archetype = gp.getAsTypeParam()->getArchetype(); substitutions[archetype] = arg; } // Collect all of the archetypes. SmallVector allArchetypesList; ArrayRef allArchetypes = genericParams->getAllArchetypes(); if (genericParams->getOuterParameters()) { SmallVector allGenericParams; unsigned numArchetypes = 0; for (; genericParams; genericParams = genericParams->getOuterParameters()) { allGenericParams.push_back(genericParams); numArchetypes += genericParams->getAllArchetypes().size(); } allArchetypesList.reserve(numArchetypes); for (auto gp = allGenericParams.rbegin(), gpEnd = allGenericParams.rend(); gp != gpEnd; ++gp) { allArchetypesList.append((*gp)->getAllArchetypes().begin(), (*gp)->getAllArchetypes().end()); } allArchetypes = allArchetypesList; } // For each of the archetypes, compute the substitution. bool hasTypeVariables = canon->hasTypeVariable(); SmallVector resultSubstitutions; resultSubstitutions.resize(allArchetypes.size()); index = 0; for (auto archetype : allArchetypes) { // Substitute into the type. auto type = Type(archetype).subst(module, substitutions, /*ignoreMissing=*/hasTypeVariables, resolver); assert(type && "Unable to perform type substitution"); SmallVector conformances; if (type->hasTypeVariable()) { // If the type involves a type variable, just fill in null conformances. // FIXME: It seems like we should record these as requirements (?). conformances.assign(archetype->getConformsTo().size(), nullptr); } else { // Find the conformances. for (auto proto : archetype->getConformsTo()) { auto conforms = module->lookupConformance(type, proto, resolver); switch (conforms.getInt()) { case ConformanceKind::Conforms: conformances.push_back(conforms.getPointer()); break; case ConformanceKind::DoesNotConform: case ConformanceKind::UncheckedConforms: llvm_unreachable("Couldn't find conformance"); } } } // Record this substitution. resultSubstitutions[index].Archetype = archetype; resultSubstitutions[index].Replacement = type; resultSubstitutions[index].Conformance = ctx.AllocateCopy(conformances); ++index; } // Copy and record the substitutions. auto permanentSubs = ctx.AllocateCopy(resultSubstitutions, hasTypeVariables ? AllocationArena::ConstraintSolver : AllocationArena::Permanent); ctx.setSubstitutions(canon, permanentSubs); return permanentSubs; } /// Retrieve the explicit conformance of the given nominal type declaration /// to the given protocol. static std::tuple findExplicitConformance(NominalTypeDecl *nominal, ProtocolDecl *protocol, LazyResolver *resolver) { // FIXME: Introduce a cache/lazy lookup structure to make this more efficient? using NominalOrConformance = llvm::PointerUnion; if (!nominal->hasType()) resolver->resolveDeclSignature(nominal); // Walk the nominal type, its extensions, superclasses, and so on. llvm::SmallPtrSet visitedProtocols; SmallVector, 4> stack; Decl *declaresConformance = nullptr; ProtocolConformance *foundConformance = nullptr; // Local function that checks for our protocol in the given array of // protocols. auto isProtocolInList = [&](Decl *currentOwner, ArrayRef protocols, ArrayRef nominalConformances) -> bool { for (unsigned i = 0, n = protocols.size(); i != n; ++i) { auto testProto = protocols[i]; if (testProto == protocol) { declaresConformance = currentOwner; if (i < nominalConformances.size()) foundConformance = nominalConformances[i]; return true; } if (visitedProtocols.insert(testProto)) { NominalOrConformance next = {}; if (i < nominalConformances.size()) next = nominalConformances[i]; if (next.isNull()) next = testProto; stack.push_back({next, currentOwner}); } } return false; }; // Walk the stack of types to find a conformance. stack.push_back({nominal, nominal}); while (!stack.empty()) { NominalOrConformance current; Decl *currentOwner; std::tie(current, currentOwner) = stack.pop_back_val(); assert(!current.isNull()); if (auto currentNominal = current.dyn_cast()) { // Visit the superclass of a class. if (auto classDecl = dyn_cast(currentNominal)) { if (auto superclassTy = classDecl->getSuperclass()) { auto super = superclassTy->getAnyNominal(); stack.push_back({super, super}); } } // Visit the protocols this type conforms to directly. if (isProtocolInList(currentOwner, currentNominal->getProtocols(), currentNominal->getConformances())) break; // Visit the extensions of this type. for (auto ext : currentNominal->getExtensions()) { if (isProtocolInList(ext, ext->getProtocols(), ext->getConformances())) { // Break outer loop as well. stack.clear(); break; } } } else { auto currentConformance = current.get(); for (auto inherited : currentConformance->getInheritedConformances()) { if (inherited.first == protocol) { declaresConformance = currentOwner; foundConformance = inherited.second; // Break outer loop as well. stack.clear(); break; } if (visitedProtocols.insert(inherited.first)) stack.push_back({inherited.second, currentOwner}); } } } // If we didn't find the protocol, we don't conform. Cache the negative result // and return. if (!declaresConformance) return std::make_tuple(nullptr, nullptr, nullptr); NominalTypeDecl *owningNominal; if (auto ext = dyn_cast(declaresConformance)) owningNominal = ext->getExtendedType()->getAnyNominal(); else owningNominal = cast(declaresConformance); assert(owningNominal); // If we don't have a nominal conformance, but we do have a resolver, try // to resolve the nominal conformance now. if (!foundConformance && resolver) { foundConformance = resolver->resolveConformance( owningNominal, protocol, dyn_cast(declaresConformance)); } // If we have a nominal conformance, we're done. if (foundConformance) { return std::make_tuple(owningNominal, declaresConformance, foundConformance); } return std::make_tuple(nullptr, nullptr, nullptr); } LookupConformanceResult Module::lookupConformance(Type type, ProtocolDecl *protocol, LazyResolver *resolver) { ASTContext &ctx = getASTContext(); // An archetype conforms to a protocol if the protocol is listed in the // archetype's list of conformances. if (auto archetype = type->getAs()) { for (auto ap : archetype->getConformsTo()) { if (ap == protocol || ap->inheritsFrom(protocol)) return { nullptr, ConformanceKind::Conforms }; } return { nullptr, ConformanceKind::DoesNotConform }; } // An archetype conforms to a protocol if the protocol is listed in the // existential's list of conformances and the existential conforms to // itself. if (type->isExistentialType()) { // If the protocol doesn't conform to itself, there's no point in looking // further. auto known = protocol->existentialConformsToSelf(); if (!known && resolver) { resolver->resolveExistentialConformsToItself(protocol); known = protocol->existentialConformsToSelf(); } // If we know that protocol doesn't conform to itself, we're done. if (known && !*known) return { nullptr, ConformanceKind::DoesNotConform }; // Look for this protocol within the existential's list of conformances. SmallVector protocols; type->isExistentialType(protocols); for (auto ap : protocols) { if (ap == protocol || ap->inheritsFrom(protocol)) { return { nullptr, known? ConformanceKind::Conforms : ConformanceKind::UncheckedConforms }; } } // We didn't find our protocol in the existential's list; it doesn't // conform. return { nullptr, ConformanceKind::DoesNotConform }; } // Check whether we have already cached an answer to this query. ASTContext::ConformsToMap::key_type key(type->getCanonicalType(), protocol); auto known = ctx.ConformsTo.find(key); if (known != ctx.ConformsTo.end()) { // If we conform, return the conformance. if (known->second.getInt()) { return { known->second.getPointer(), ConformanceKind::Conforms }; } // We don't conform. return { nullptr, ConformanceKind::DoesNotConform }; } auto nominal = type->getAnyNominal(); // If we don't have a nominal type, there are no conformances. // FIXME: We may have implicit conformances for some cases. Handle those // here. if (!nominal) { return { nullptr, ConformanceKind::DoesNotConform }; } // Find the explicit conformance. NominalTypeDecl *owningNominal = nullptr; Decl *declaresConformance = nullptr; ProtocolConformance *nominalConformance = nullptr; std::tie(owningNominal, declaresConformance, nominalConformance) = findExplicitConformance(nominal, protocol, resolver); // If we didn't find an owning nominal, we don't conform. Cache the negative // result and return. if (!owningNominal) { ctx.ConformsTo[key] = ConformanceEntry(nullptr, false); return { nullptr, ConformanceKind::DoesNotConform }; } // If we found an owning nominal but didn't have a conformance, this is // an unchecked conformance. if (!nominalConformance) { return { nullptr, ConformanceKind::UncheckedConforms }; } // If the nominal type in which we found the conformance is not the same // as the type we asked for, it's an inherited type. if (owningNominal != nominal) { // Find the superclass type Type superclassTy = type->getSuperclass(resolver); while (superclassTy->getAnyNominal() != owningNominal) superclassTy = superclassTy->getSuperclass(resolver); // Compute the conformance for the inherited type. auto inheritedConformance = lookupConformance(superclassTy, protocol, resolver); switch (inheritedConformance.getInt()) { case ConformanceKind::DoesNotConform: llvm_unreachable("We already found the inherited conformance"); case ConformanceKind::UncheckedConforms: return inheritedConformance; case ConformanceKind::Conforms: // Create inherited conformance below. break; } // Create the inherited conformance entry. auto result = ctx.getInheritedConformance(type, inheritedConformance.getPointer()); ctx.ConformsTo[key] = ConformanceEntry(result, true); return { result, ConformanceKind::Conforms }; } // If the type is specialized, find the conformance for the generic type. if (type->isSpecialized()) { // Figure out the type that's explicitly conforming to this protocol. Type explicitConformanceType; if (auto nominal = dyn_cast(declaresConformance)) { explicitConformanceType = nominal->getDeclaredTypeInContext(); } else { explicitConformanceType = cast(declaresConformance) ->getDeclaredTypeInContext(); } // If the explicit conformance is associated with a type that is different // from the type we're checking, retrieve generic conformance. if (!explicitConformanceType->isEqual(type)) { // Gather the substitutions we need to map the generic conformance to // the specialized conformance. auto substitutions = type->gatherAllSubstitutions(this, resolver); // Create the specialized conformance entry. ctx.ConformsTo[key] = ConformanceEntry(nullptr, false); auto result = ctx.getSpecializedConformance(type, nominalConformance, substitutions); ctx.ConformsTo[key] = ConformanceEntry(result, true); return { result, ConformanceKind::Conforms }; } } // Record and return the simple conformance. ctx.ConformsTo[key] = ConformanceEntry(nominalConformance, true); return { nominalConformance, ConformanceKind::Conforms }; } namespace { template using OperatorMap = SourceFile::OperatorMap; template struct OperatorKind { static_assert(static_cast(nullptr), "Only usable with operators"); }; template <> struct OperatorKind { static const auto value = DeclKind::PrefixOperator; }; template <> struct OperatorKind { static const auto value = DeclKind::InfixOperator; }; template <> struct OperatorKind { static const auto value = DeclKind::PostfixOperator; }; } template static Op *lookupOperator(T &container, Identifier name) { return cast_or_null(container.lookupOperator(name, OperatorKind::value)); } template static Optional lookupOperatorDeclForName(Module *M, SourceLoc Loc, Identifier Name, OperatorMap SourceFile::*OP_MAP); // Returns Nothing on error, Optional(nullptr) if no operator decl found, or // Optional(decl) if decl was found. template static Optional lookupOperatorDeclForName(const FileUnit &File, SourceLoc Loc, Identifier Name, bool includePrivate, OperatorMap SourceFile::*OP_MAP) { switch (File.getKind()) { case FileUnitKind::Builtin: // The Builtin module declares no operators. return nullptr; case FileUnitKind::Source: break; case FileUnitKind::SerializedAST: case FileUnitKind::ClangModule: return lookupOperator(cast(File), Name); } auto &SF = cast(File); assert(SF.ASTStage >= SourceFile::NameBound); // Look for an operator declaration in the current module. auto found = (SF.*OP_MAP).find(Name); if (found != (SF.*OP_MAP).end() && (includePrivate || found->second.getInt())) return found->second.getPointer(); // Look for imported operator decls. // Record whether they come from re-exported modules. // FIXME: We ought to prefer operators elsewhere in this module before we // check imports. llvm::SmallDenseMap importedOperators; for (auto &imported : SF.getImports()) { if (!includePrivate && !imported.second) continue; Optional maybeOp = lookupOperatorDeclForName(imported.first.second, Loc, Name, OP_MAP); if (!maybeOp) return Nothing; if (OP_DECL *op = *maybeOp) importedOperators[op] |= imported.second; } typename OperatorMap::mapped_type result = { nullptr, true }; if (!importedOperators.empty()) { // Check for conflicts. auto i = importedOperators.begin(), end = importedOperators.end(); auto start = i; for (++i; i != end; ++i) { if (i->first->conflictsWith(start->first)) { if (Loc.isValid()) { ASTContext &C = SF.getASTContext(); C.Diags.diagnose(Loc, diag::ambiguous_operator_decls); C.Diags.diagnose(start->first->getLoc(), diag::found_this_operator_decl); C.Diags.diagnose(i->first->getLoc(), diag::found_this_operator_decl); } return Nothing; } } result = { start->first, start->second }; } if (includePrivate) { // Cache the mapping so we don't need to troll imports next time. // It's not safe to cache the non-private results because we didn't search // private imports there, but in most non-private cases the result will // be cached in the final lookup. auto &mutableOpMap = const_cast &>(SF.*OP_MAP); mutableOpMap[Name] = result; } if (includePrivate || result.getInt()) return result.getPointer(); return nullptr; } template static Optional lookupOperatorDeclForName(Module *M, SourceLoc Loc, Identifier Name, OperatorMap SourceFile::*OP_MAP) { OP_DECL *result = nullptr; for (const FileUnit *File : M->getFiles()) { auto next = lookupOperatorDeclForName(*File, Loc, Name, false, OP_MAP); if (!next.hasValue()) return next; // FIXME: Diagnose ambiguity. if (*next && result) return Nothing; if (*next) result = *next; } return result; } #define LOOKUP_OPERATOR(Kind) \ Kind##OperatorDecl * \ Module::lookup##Kind##Operator(Identifier name, SourceLoc loc) { \ auto result = lookupOperatorDeclForName(this, loc, name, \ &SourceFile::Kind##Operators); \ return result ? *result : nullptr; \ } \ Kind##OperatorDecl * \ SourceFile::lookup##Kind##Operator(Identifier name, SourceLoc loc) { \ auto result = lookupOperatorDeclForName(*this, loc, name, true, \ &SourceFile::Kind##Operators); \ if (result.hasValue() && !result.getValue()) \ result = lookupOperatorDeclForName(getParentModule(), loc, name, \ &SourceFile::Kind##Operators); \ return result ? *result : nullptr; \ } LOOKUP_OPERATOR(Prefix) LOOKUP_OPERATOR(Infix) LOOKUP_OPERATOR(Postfix) #undef LOOKUP_OPERATOR void Module::getImportedModules(SmallVectorImpl &modules, bool includePrivate) const { // FIXME: Audit uses of this function and make sure they make sense in a // multi-file world. FORWARD(getImportedModules, (modules, includePrivate)); } void SourceFile::getImportedModules(SmallVectorImpl &modules, bool includePrivate) const { for (auto importPair : getImports()) if (includePrivate || importPair.second) modules.push_back(importPair.first); } namespace { /// Arbitrarily orders ImportedModule records, for inclusion in sets and such. class OrderImportedModules { using ImportedModule = Module::ImportedModule; using AccessPathTy = Module::AccessPathTy; public: bool operator()(const ImportedModule &lhs, const ImportedModule &rhs) { if (lhs.second != rhs.second) return std::less()(lhs.second, rhs.second); if (lhs.first.data() != rhs.first.data()) return std::less()(lhs.first.begin(), rhs.first.begin()); return lhs.first.size() < rhs.first.size(); } }; } bool Module::isSameAccessPath(AccessPathTy lhs, AccessPathTy rhs) { using AccessPathElem = std::pair; if (lhs.size() != rhs.size()) return false; auto iters = std::mismatch(lhs.begin(), lhs.end(), rhs.begin(), [](const AccessPathElem &lElem, const AccessPathElem &rElem) { return lElem.first == rElem.first; }); return iters.first == lhs.end(); } StringRef Module::getModuleFilename() const { // FIXME: Audit uses of this function and figure out how to migrate them to // per-file names. Modules can consist of more than one file. if (getFiles().size() == 1) { if (auto SF = dyn_cast(getFiles().front())) return SF->getFilename(); if (auto LF = dyn_cast(getFiles().front())) return LF->getFilename(); } return StringRef(); } bool Module::isStdlibModule() const { return !getParent() && Name == Ctx.StdlibModuleName; } template static bool forAllImportedModules(Module *topLevel, Optional thisPath, const Callback &fn) { using ImportedModule = Module::ImportedModule; using AccessPathTy = Module::AccessPathTy; llvm::SmallSet visited; SmallVector queue; AccessPathTy overridingPath; if (thisPath.hasValue()) { if (respectVisibility) overridingPath = thisPath.getValue(); queue.push_back(ImportedModule(overridingPath, topLevel)); } else { visited.insert(ImportedModule({}, topLevel)); } // Even if we're processing the top-level module like any other, we still want // to include non-exported modules. topLevel->getImportedModules(queue, !respectVisibility); while (!queue.empty()) { auto next = queue.pop_back_val(); // Filter any whole-module imports, and skip specific-decl imports if the // import path doesn't match exactly. if (next.first.empty() || !respectVisibility) next.first = overridingPath; else if (!overridingPath.empty() && !Module::isSameAccessPath(next.first, overridingPath)) { // If we ever allow importing non-top-level decls, it's possible the rule // above isn't what we want. assert(next.first.size() == 1 && "import of non-top-level decl"); continue; } if (!visited.insert(next)) continue; if (!fn(next)) return false; next.second->getImportedModules(queue, !respectVisibility); } return true; } bool Module::forAllVisibleModules(Optional thisPath, std::function fn) { return forAllImportedModules(this, thisPath, fn); } bool FileUnit::forAllVisibleModules(std::function fn) { if (!getParentModule()->forAllVisibleModules(Module::AccessPathTy(), fn)) return false; if (auto SF = dyn_cast(this)) { // Handle privately visible modules as well. for (auto importPair : SF->getImports()) { if (importPair.second) continue; Module *M = importPair.first.second; if (!M->forAllVisibleModules(importPair.first.first, fn)) return false; } } return true; } void Module::collectLinkLibraries(LinkLibraryCallback callback) { // FIXME: The proper way to do this depends on the decls used. FORWARD(collectLinkLibraries, (callback)); } void SourceFile::collectLinkLibraries(Module::LinkLibraryCallback callback) const { for (auto importPair : Imports) importPair.first.second->collectLinkLibraries(callback); } bool Module::walk(ASTWalker &Walker) { llvm::SaveAndRestore SAR(Walker.Parent, this); for (auto SF : getFiles()) if (SF->walk(Walker)) return true; return false; } //===----------------------------------------------------------------------===// // SourceFile Implementation //===----------------------------------------------------------------------===// void SourceFile::print(raw_ostream &OS, const PrintOptions &PO) { StreamPrinter Printer(OS); print(Printer, PO); } void SourceFile::print(ASTPrinter &Printer, const PrintOptions &PO) { for (auto decl : Decls) { if (!decl->shouldPrintInContext(PO)) continue; decl->print(Printer, PO); Printer << "\n"; } } void SourceFile::clearLookupCache() { Cache.reset(); } void SourceFile::cacheVisibleDecls(SmallVectorImpl &&globals) const { SmallVectorImpl &cached = getCache().AllVisibleValues; cached = std::move(globals); } const SmallVectorImpl & SourceFile::getCachedVisibleDecls() const { return getCache().AllVisibleValues; } static void performAutoImport(SourceFile &SF, bool hasBuiltinModuleAccess) { if (SF.Kind == SourceFileKind::SIL) return; // If we're building the standard library, import the magic Builtin module, // otherwise, import the standard library. ASTContext &Ctx = SF.getASTContext(); Module *M; if (hasBuiltinModuleAccess) M = Ctx.TheBuiltinModule; else M = Ctx.getModule({ {Ctx.StdlibModuleName, SourceLoc()} }); if (!M) return; // FIXME: These will be the same for most source files, but we copy them // over and over again. std::pair Imports[] = { std::make_pair(Module::ImportedModule({}, M), false) }; SF.setImports(Ctx.AllocateCopy(Imports)); } SourceFile::SourceFile(Module &M, SourceFileKind K, Optional bufferID, bool hasBuiltinModuleAccess) : FileUnit(FileUnitKind::Source, M), BufferID(bufferID ? *bufferID : -1), Kind(K) { performAutoImport(*this, hasBuiltinModuleAccess); } bool FileUnit::walk(ASTWalker &walker) { SmallVector Decls; getTopLevelDecls(Decls); llvm::SaveAndRestore SAR(walker.Parent, getParentModule()); for (Decl *D : Decls) { if (D->walk(walker)) return true; } return false; } bool SourceFile::walk(ASTWalker &walker) { llvm::SaveAndRestore SAR(walker.Parent, getParentModule()); for (Decl *D : Decls) { if (D->walk(walker)) return true; } return false; } StringRef SourceFile::getFilename() const { if (BufferID == -1) return ""; SourceManager &SM = getASTContext().SourceMgr; return SM->getMemoryBuffer(BufferID)->getBufferIdentifier(); } //===----------------------------------------------------------------------===// // Miscellaneous //===----------------------------------------------------------------------===// void FileUnit::anchor() {} void *FileUnit::operator new(size_t Bytes, ASTContext &C, unsigned Alignment) { return C.Allocate(Bytes, Alignment); } StringRef LoadedFile::getFilename() const { return ""; }