Skip to content

[AST] Do not copy SearchPathOptions in updateNonUserModule #64593

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
merged 1 commit into from
Mar 25, 2023
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
8 changes: 2 additions & 6 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
HasAnyUnavailableValues : 1
);

SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1,
SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1,
/// If the module is compiled as static library.
StaticLibrary : 1,

Expand Down Expand Up @@ -680,11 +680,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {

/// If the map from @objc provided name to top level swift::Decl in this
/// module is populated
ObjCNameLookupCachePopulated : 1,

/// Whether the module is contained in the SDK or stdlib, or its a system
/// module and no SDK was specified.
IsNonUserModule : 1
ObjCNameLookupCachePopulated : 1
);

SWIFT_INLINE_BITFIELD(PrecedenceGroupDecl, Decl, 1+2,
Expand Down
12 changes: 3 additions & 9 deletions include/swift/AST/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -661,15 +661,9 @@ class ModuleDecl
void setIsSystemModule(bool flag = true);

/// \returns true if this module is part of the stdlib or contained within
/// the SDK. If no SDK was specified, also falls back to whether the module
/// was specified as a system module (ie. it's on the system search path).
bool isNonUserModule() const { return Bits.ModuleDecl.IsNonUserModule; }

private:
/// Update whether this module is a non-user module, see \c isNonUserModule.
/// \p newUnit is the added unit that caused this update, or \c nullptr if
/// the update wasn't caused by adding a new unit.
void updateNonUserModule(FileUnit *newUnit);
/// the SDK. If no SDK was specified, falls back to whether the module was
/// specified as a system module (ie. it's on the system search path).
bool isNonUserModule() const;

public:
/// Returns true if the module was rebuilt from a module interface instead
Expand Down
19 changes: 19 additions & 0 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -4172,6 +4172,25 @@ void simple_display(llvm::raw_ostream &out, const TypeRepr *TyR);
void simple_display(llvm::raw_ostream &out, ImplicitMemberAction action);
void simple_display(llvm::raw_ostream &out, ResultBuilderBodyPreCheck pck);

/// Computes whether a module is part of the stdlib or contained within the
/// SDK. If no SDK was specified, falls back to whether the module was
/// specified as a system module (ie. it's on the system search path).
class IsNonUserModuleRequest
: public SimpleRequest<IsNonUserModuleRequest,
bool(ModuleDecl *),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

bool evaluate(Evaluator &evaluator, ModuleDecl *mod) const;

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

#define SWIFT_TYPEID_ZONE TypeChecker
#define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def"
#include "swift/Basic/DefineTypeIDZone.h"
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -466,3 +466,6 @@ SWIFT_REQUEST(TypeChecker, GetRuntimeDiscoverableAttributes,
SWIFT_REQUEST(TypeChecker, LocalDiscriminatorsRequest,
unsigned(DeclContext *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, IsNonUserModuleRequest,
bool(ModuleDecl *),
Cached, NoLocationInfo)
86 changes: 48 additions & 38 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -605,49 +605,19 @@ ModuleDecl::ModuleDecl(Identifier name, ASTContext &ctx,
Bits.ModuleDecl.HasHermeticSealAtLink = 0;
Bits.ModuleDecl.IsConcurrencyChecked = 0;
Bits.ModuleDecl.ObjCNameLookupCachePopulated = 0;
Bits.ModuleDecl.IsNonUserModule = 0;
}

void ModuleDecl::setIsSystemModule(bool flag) {
Bits.ModuleDecl.IsSystemModule = flag;
updateNonUserModule(/*newFile=*/nullptr);
}

static bool prefixMatches(StringRef prefix, StringRef path) {
auto i = llvm::sys::path::begin(prefix), e = llvm::sys::path::end(prefix);
for (auto pi = llvm::sys::path::begin(path), pe = llvm::sys::path::end(path);
i != e && pi != pe; ++i, ++pi) {
if (*i != *pi)
return false;
}
return i == e;
}

void ModuleDecl::updateNonUserModule(FileUnit *newUnit) {
if (isNonUserModule())
return;

SearchPathOptions searchPathOpts = getASTContext().SearchPathOpts;
StringRef sdkPath = searchPathOpts.getSDKPath();

if (isStdlibModule() || (sdkPath.empty() && isSystemModule())) {
Bits.ModuleDecl.IsNonUserModule = true;
return;
}
bool ModuleDecl::isNonUserModule() const {
// For clang submodules, retrieve their top level module (submodules have no
// source path, so we'd always return false for them).
ModuleDecl *mod = const_cast<ModuleDecl *>(this)->getTopLevelModule();

// If we loaded a serialized module, check if it was compiler adjacent or in
// the SDK.

auto *LF = dyn_cast_or_null<LoadedFile>(newUnit);
if (!LF)
return;

StringRef runtimePath = searchPathOpts.RuntimeResourcePath;
StringRef modulePath = LF->getSourceFilename();
if ((!runtimePath.empty() && prefixMatches(runtimePath, modulePath)) ||
(!sdkPath.empty() && prefixMatches(sdkPath, modulePath))) {
Bits.ModuleDecl.IsNonUserModule = true;
}
auto &evaluator = getASTContext().evaluator;
return evaluateOrDefault(evaluator, IsNonUserModuleRequest{mod}, false);
}

ImplicitImportList ModuleDecl::getImplicitImports() const {
Expand All @@ -669,8 +639,6 @@ void ModuleDecl::addFile(FileUnit &newFile) {
cast<SourceFile>(newFile).Kind == SourceFileKind::SIL);
Files.push_back(&newFile);
clearLookupCache();

updateNonUserModule(&newFile);
}

void ModuleDecl::addAuxiliaryFile(SourceFile &sourceFile) {
Expand Down Expand Up @@ -4133,3 +4101,45 @@ const UnifiedStatsReporter::TraceFormatter*
FrontendStatsTracer::getTraceFormatter<const SourceFile *>() {
return &TF;
}

static bool prefixMatches(StringRef prefix, StringRef path) {
auto prefixIt = llvm::sys::path::begin(prefix),
prefixEnd = llvm::sys::path::end(prefix);
for (auto pathIt = llvm::sys::path::begin(path),
pathEnd = llvm::sys::path::end(path);
prefixIt != prefixEnd && pathIt != pathEnd; ++prefixIt, ++pathIt) {
if (*prefixIt != *pathIt)
return false;
}
return prefixIt == prefixEnd;
}

bool IsNonUserModuleRequest::evaluate(Evaluator &evaluator, ModuleDecl *mod) const {
// stdlib is non-user by definition
if (mod->isStdlibModule())
return true;

// If there's no SDK path, fallback to checking whether the module was
// in the system search path or a clang system module
SearchPathOptions &searchPathOpts = mod->getASTContext().SearchPathOpts;
StringRef sdkPath = searchPathOpts.getSDKPath();
if (sdkPath.empty() && mod->isSystemModule())
return true;

// Some temporary module's get created with no module name and they have no
// files. Avoid running `getFiles` on them (which will assert if there
// aren't any).
if (!mod->hasName() || mod->getFiles().empty())
return false;

auto *LF = dyn_cast_or_null<LoadedFile>(mod->getFiles().front());
if (!LF)
return false;

StringRef modulePath = LF->getSourceFilename();
if (modulePath.empty())
return false;

StringRef runtimePath = searchPathOpts.RuntimeResourcePath;
return (!runtimePath.empty() && prefixMatches(runtimePath, modulePath)) || (!sdkPath.empty() && prefixMatches(sdkPath, modulePath));
}
3 changes: 3 additions & 0 deletions lib/IDE/CompletionLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ void CompletionLookup::addSubModuleNames(
CodeCompletionResultBuilder Builder(
Sink, CodeCompletionResultKind::Declaration, SemanticContextKind::None);
auto MD = ModuleDecl::create(Ctx.getIdentifier(Pair.first), Ctx);
MD->setFailedToLoad();
Builder.setAssociatedDecl(MD);
Builder.addBaseName(MD->getNameStr());
Builder.addTypeAnnotation("Module");
Expand Down Expand Up @@ -365,6 +366,8 @@ void CompletionLookup::addImportModuleNames() {
continue;

auto MD = ModuleDecl::create(ModuleName, Ctx);
MD->setFailedToLoad();

Optional<ContextualNotRecommendedReason> Reason = None;

// Imported modules are not recommended.
Expand Down
2 changes: 1 addition & 1 deletion test/IDE/complete_diagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ import MyModule
import #^IMPORT^#;
// IMPORT-DAG: Decl[Module]/None/NotRecommended: MyModule[#Module#]; name=MyModule; diagnostics=warning:module 'MyModule' is already imported{{$}}
// IMPORT-DAG: Decl[Module]/None/NotRecommended: OtherModule[#Module#]; name=OtherModule; diagnostics=note:module 'OtherModule' is already imported via another module import{{$}}
// IMPORT-DAG: Decl[Module]/None/NotRecommended: Swift[#Module#]; name=Swift; diagnostics=warning:module 'Swift' is already imported{{$}}
// IMPORT-DAG: Decl[Module]/None/NotRecommended/IsSystem: Swift[#Module#]; name=Swift; diagnostics=warning:module 'Swift' is already imported{{$}}

func test(foo: Foo) {
foo.#^MEMBER^#
Expand Down