Skip to content

Requestify scoped import validation #30038

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/swift/AST/ClangModuleLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace clang {
class ASTContext;
class CompilerInstance;
class Decl;
class Module;
class Preprocessor;
class Sema;
class TargetInfo;
Expand Down Expand Up @@ -125,6 +126,10 @@ class ClangModuleLoader : public ModuleLoader {
/// Objective-C header files.
virtual ModuleDecl *getImportedHeaderModule() const = 0;

/// Retrieves the Swift wrapper for the given Clang module, creating
/// it if necessary.
virtual ModuleDecl *getWrapperForModule(const clang::Module *mod) const = 0;

/// Adds a new search path to the Clang CompilerInstance, as if specified with
/// -I or -F.
///
Expand Down
7 changes: 3 additions & 4 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1527,8 +1527,6 @@ class ImportDecl final : public Decl,

/// The resolved module.
ModuleDecl *Mod = nullptr;
/// The resolved decls if this is a decl import.
ArrayRef<ValueDecl *> Decls;

ImportDecl(DeclContext *DC, SourceLoc ImportLoc, ImportKind K,
SourceLoc KindLoc, ArrayRef<AccessPathElement> Path);
Expand Down Expand Up @@ -1581,8 +1579,9 @@ class ImportDecl final : public Decl,
ModuleDecl *getModule() const { return Mod; }
void setModule(ModuleDecl *M) { Mod = M; }

ArrayRef<ValueDecl *> getDecls() const { return Decls; }
void setDecls(ArrayRef<ValueDecl *> Ds) { Decls = Ds; }
/// For a scoped import such as 'import class Foundation.NSString', retrieve
/// the decls it references. Otherwise, returns an empty array.
ArrayRef<ValueDecl *> getDecls() const;

const clang::Module *getClangModule() const {
return getClangNode().getClangModule();
Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,11 @@ class ModuleDecl : public DeclContext, public TypeDecl {
Bits.ModuleDecl.IsNonSwiftModule = flag;
}

/// Retrieve the top-level module. If this module is already top-level, this
/// returns itself. If this is a submodule such as \c Foo.Bar.Baz, this
/// returns the module \c Foo.
ModuleDecl *getTopLevelModule();

bool isResilient() const {
return getResilienceStrategy() != ResilienceStrategy::Default;
}
Expand Down
26 changes: 26 additions & 0 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -2073,6 +2073,32 @@ class TypeEraserHasViableInitRequest
bool isCached() const { return true; }
};

/// Looks up the decls that a scoped import references, ensuring the import is
/// valid.
///
/// A "scoped import" is an import which only covers one particular
/// declaration, such as:
///
/// import class Foundation.NSString
///
class ScopedImportLookupRequest
: public SimpleRequest<ScopedImportLookupRequest,
ArrayRef<ValueDecl *>(ImportDecl *),
CacheKind::Cached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

llvm::Expected<ArrayRef<ValueDecl *>> evaluate(Evaluator &evaluator,
ImportDecl *import) const;

public:
// Cached.
bool isCached() const { return true; }
};

// Allow AnyValue to compare two Type values, even though Type doesn't
// support ==.
template<>
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -225,3 +225,5 @@ SWIFT_REQUEST(TypeChecker, ValueWitnessRequest,
SWIFT_REQUEST(TypeChecker, PatternTypeRequest,
Type(ContextualPattern),
Cached, HasNearestLocation)
SWIFT_REQUEST(TypeChecker, ScopedImportLookupRequest,
ArrayRef<ValueDecl *>(ImportDecl *), Cached, NoLocationInfo)
4 changes: 4 additions & 0 deletions include/swift/ClangImporter/ClangImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,10 @@ class ClangImporter final : public ClangModuleLoader {
/// \sa importHeader
ModuleDecl *getImportedHeaderModule() const override;

/// Retrieves the Swift wrapper for the given Clang module, creating
/// it if necessary.
ModuleDecl *getWrapperForModule(const clang::Module *mod) const override;

std::string getBridgingHeaderContents(StringRef headerPath, off_t &fileSize,
time_t &fileModTime);

Expand Down
11 changes: 11 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1174,6 +1174,17 @@ ImportDecl::findBestImportKind(ArrayRef<ValueDecl *> Decls) {
return FirstKind;
}

ArrayRef<ValueDecl *> ImportDecl::getDecls() const {
// If this isn't a scoped import, there's nothing to do.
if (getImportKind() == ImportKind::Module)
return {};

auto &ctx = getASTContext();
auto *mutableThis = const_cast<ImportDecl *>(this);
return evaluateOrDefault(ctx.evaluator,
ScopedImportLookupRequest{mutableThis}, {});
}

void NominalTypeDecl::setConformanceLoader(LazyMemberLoader *lazyLoader,
uint64_t contextData) {
assert(!Bits.NominalTypeDecl.HasLazyConformances &&
Expand Down
16 changes: 16 additions & 0 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "swift/AST/ASTPrinter.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/Builtins.h"
#include "swift/AST/ClangModuleLoader.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/FileUnit.h"
Expand Down Expand Up @@ -440,6 +441,21 @@ SourceLookupCache &ModuleDecl::getSourceLookupCache() const {
return *Cache;
}

ModuleDecl *ModuleDecl::getTopLevelModule() {
// If this is a Clang module, ask the Clang importer for the top-level module.
// We need to check isNonSwiftModule() to ensure we don't look through
// overlays.
if (isNonSwiftModule()) {
if (auto *underlying = findUnderlyingClangModule()) {
auto &ctx = getASTContext();
auto *clangLoader = ctx.getClangModuleLoader();
return clangLoader->getWrapperForModule(underlying->getTopLevelModule());
}
}
// Swift modules don't currently support submodules.
return this;
}

static bool isParsedModule(const ModuleDecl *mod) {
// FIXME: If we ever get mixed modules that contain both SourceFiles and other
// kinds of file units, this will break; there all callers of this function should
Expand Down
4 changes: 4 additions & 0 deletions lib/ClangImporter/ClangImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1858,6 +1858,10 @@ ModuleDecl *ClangImporter::getImportedHeaderModule() const {
return Impl.ImportedHeaderUnit->getParentModule();
}

ModuleDecl *ClangImporter::getWrapperForModule(const clang::Module *mod) const {
return Impl.getWrapperForModule(mod)->getParentModule();
}

PlatformAvailability::PlatformAvailability(LangOptions &langOpts)
: platformKind(targetPlatform(langOpts)) {
switch (platformKind) {
Expand Down
Loading