Skip to content

Commit 1c97cc3

Browse files
authored
Merge pull request #73094 from tshortli/rename-extension-import-visibility-feature-6.0
[6.0] Rename ExtensionImportVisibility to MemberImportVisibility and fix bugs
2 parents d9f0f8e + a37efe1 commit 1c97cc3

34 files changed

+316
-124
lines changed

include/swift/AST/Decl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2788,7 +2788,7 @@ class ValueDecl : public Decl {
27882788
public:
27892789
/// Find the import that makes the given declaration available.
27902790
std::optional<AttributedImport<ImportedModule>>
2791-
findImport(const DeclContext *fromDC);
2791+
findImport(const DeclContext *fromDC) const;
27922792

27932793
/// Return true if this protocol member is a protocol requirement.
27942794
///

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,9 @@ ERROR(init_candidate_inaccessible,none,
167167

168168
ERROR(candidate_from_missing_import,none,
169169
"%0 %1 is not available due to missing import of defining module %2",
170-
(DescriptiveDeclKind, DeclName, DeclName))
170+
(DescriptiveDeclKind, DeclName, ModuleDecl *))
171171
NOTE(candidate_add_import,none,
172-
"add import of module %0", (DeclName))
172+
"add import of module %0", (ModuleDecl *))
173173

174174
ERROR(cannot_pass_rvalue_mutating_subelement,none,
175175
"cannot use mutating member on immutable value: %0",

include/swift/AST/Module.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,6 +1269,11 @@ void collectParsedExportedImports(const ModuleDecl *M,
12691269
llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4> &QualifiedImports,
12701270
llvm::function_ref<bool(AttributedImport<ImportedModule>)> includeImport = nullptr);
12711271

1272+
/// If the import that would make the given declaration visibile is absent,
1273+
/// emit a diagnostic and a fix-it suggesting adding the missing import.
1274+
bool diagnoseMissingImportForMember(const ValueDecl *decl,
1275+
const DeclContext *dc, SourceLoc loc);
1276+
12721277
} // end namespace swift
12731278

12741279
#endif

include/swift/AST/SourceFile.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,9 @@ class SourceFile final : public FileUnit {
457457
/// If not, we can fast-path module checks.
458458
bool hasImportsWithFlag(ImportFlags flag) const;
459459

460+
/// Returns the import flags that are active on imports of \p module.
461+
ImportFlags getImportFlags(const ModuleDecl *module) const;
462+
460463
/// Get the most permissive restriction applied to the imports of \p module.
461464
RestrictedImportKind getRestrictedImportKind(const ModuleDecl *module) const;
462465

include/swift/Basic/Features.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,8 +364,8 @@ EXPERIMENTAL_FEATURE(ClosureIsolation, true)
364364
// Enable isolated(any) attribute on function types.
365365
CONDITIONALLY_SUPPRESSIBLE_EXPERIMENTAL_FEATURE(IsolatedAny, true)
366366

367-
// Whether members of extensions respect the enclosing file's imports.
368-
EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE(ExtensionImportVisibility, true)
367+
// Whether lookup of members respects the enclosing file's imports.
368+
EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE(MemberImportVisibility, true)
369369

370370
// Alias for IsolatedAny
371371
EXPERIMENTAL_FEATURE(IsolatedAny2, true)

lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3856,7 +3856,7 @@ ValueDecl::getSatisfiedProtocolRequirements(bool Sorted) const {
38563856
}
38573857

38583858
std::optional<AttributedImport<ImportedModule>>
3859-
ValueDecl::findImport(const DeclContext *fromDC) {
3859+
ValueDecl::findImport(const DeclContext *fromDC) const {
38603860
// If the type is from the current module, there's no import.
38613861
auto module = getModuleContext();
38623862
if (module == fromDC->getParentModule())

lib/AST/FeatureSet.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ static bool usesFeatureIsolatedAny(Decl *decl) {
680680
});
681681
}
682682

683-
UNINTERESTING_FEATURE(ExtensionImportVisibility)
683+
UNINTERESTING_FEATURE(MemberImportVisibility)
684684
UNINTERESTING_FEATURE(IsolatedAny2)
685685

686686
UNINTERESTING_FEATURE(ObjCImplementation)

lib/AST/Module.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2702,6 +2702,15 @@ bool SourceFile::hasImportsWithFlag(ImportFlags flag) const {
27022702
ctx.evaluator, HasImportsMatchingFlagRequest{mutableThis, flag}, false);
27032703
}
27042704

2705+
ImportFlags SourceFile::getImportFlags(const ModuleDecl *module) const {
2706+
unsigned flags = 0x0;
2707+
for (auto import : *Imports) {
2708+
if (import.module.importedModule == module)
2709+
flags |= import.options.toRaw();
2710+
}
2711+
return ImportFlags(flags);
2712+
}
2713+
27052714
bool SourceFile::hasTestableOrPrivateImport(
27062715
AccessLevel accessLevel, const swift::ValueDecl *ofDecl,
27072716
SourceFile::ImportQueryKind queryKind) const {
@@ -4001,3 +4010,62 @@ version::Version ModuleDecl::getLanguageVersionBuiltWith() const {
40014010

40024011
return version::Version();
40034012
}
4013+
4014+
bool swift::diagnoseMissingImportForMember(const ValueDecl *decl,
4015+
const DeclContext *dc,
4016+
SourceLoc loc) {
4017+
if (decl->findImport(dc))
4018+
return false;
4019+
4020+
auto &ctx = dc->getASTContext();
4021+
auto definingModule = decl->getModuleContext();
4022+
ctx.Diags.diagnose(loc, diag::candidate_from_missing_import,
4023+
decl->getDescriptiveKind(), decl->getName(),
4024+
definingModule);
4025+
4026+
SourceLoc bestLoc =
4027+
ctx.Diags.getBestAddImportFixItLoc(decl, dc->getParentSourceFile());
4028+
if (!bestLoc.isValid())
4029+
return false;
4030+
4031+
llvm::SmallString<64> importText;
4032+
4033+
// Check other source files for import flags that should be applied to the
4034+
// fix-it for consistency with the rest of the imports in the module.
4035+
auto parentModule = dc->getParentModule();
4036+
OptionSet<ImportFlags> flags;
4037+
for (auto file : parentModule->getFiles()) {
4038+
if (auto sf = dyn_cast<SourceFile>(file))
4039+
flags |= sf->getImportFlags(definingModule);
4040+
}
4041+
4042+
if (flags.contains(ImportFlags::Exported) ||
4043+
parentModule->isClangOverlayOf(definingModule))
4044+
importText += "@_exported ";
4045+
if (flags.contains(ImportFlags::ImplementationOnly))
4046+
importText += "@_implementationOnly ";
4047+
if (flags.contains(ImportFlags::WeakLinked))
4048+
importText += "@_weakLinked ";
4049+
if (flags.contains(ImportFlags::SPIOnly))
4050+
importText += "@_spiOnly ";
4051+
4052+
// FIXME: Access level should be considered, too.
4053+
4054+
// @_spi imports.
4055+
if (decl->isSPI()) {
4056+
auto spiGroups = decl->getSPIGroups();
4057+
if (!spiGroups.empty()) {
4058+
importText += "@_spi(";
4059+
importText += spiGroups[0].str();
4060+
importText += ") ";
4061+
}
4062+
}
4063+
4064+
importText += "import ";
4065+
importText += definingModule->getName().str();
4066+
importText += "\n";
4067+
ctx.Diags.diagnose(bestLoc, diag::candidate_add_import, definingModule)
4068+
.fixItInsert(bestLoc, importText);
4069+
4070+
return true;
4071+
}

lib/AST/NameLookup.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2293,7 +2293,7 @@ static bool isAcceptableLookupResult(const DeclContext *dc,
22932293
// makes this decl visible.
22942294
if (decl->getDeclContext()->getParentModule() != dc->getParentModule() &&
22952295
dc->getASTContext().LangOpts.hasFeature(
2296-
Feature::ExtensionImportVisibility) &&
2296+
Feature::MemberImportVisibility) &&
22972297
!decl->findImport(dc))
22982298
return false;
22992299
}

lib/Sema/CSDiagnostics.cpp

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6187,40 +6187,11 @@ bool InaccessibleMemberFailure::diagnoseAsError() {
61876187

61886188
auto loc = nameLoc.isValid() ? nameLoc.getStartLoc() : ::getLoc(anchor);
61896189
auto accessLevel = Member->getFormalAccessScope().accessLevelForDiagnostics();
6190-
bool suppressDeclHereNote = false;
61916190
if (accessLevel == AccessLevel::Public &&
6192-
!Member->findImport(getDC())) {
6193-
auto definingModule = Member->getDeclContext()->getParentModule();
6194-
emitDiagnosticAt(loc, diag::candidate_from_missing_import,
6195-
Member->getDescriptiveKind(), Member->getName(),
6196-
definingModule->getName());
6197-
6198-
auto enclosingSF = getDC()->getParentSourceFile();
6199-
SourceLoc bestLoc =
6200-
getBestAddImportFixItLocation(Member, getDC()->getParentSourceFile());
6201-
if (bestLoc.isValid()) {
6202-
llvm::SmallString<64> importText;
6203-
6204-
// @_spi imports.
6205-
if (Member->isSPI()) {
6206-
auto spiGroups = Member->getSPIGroups();
6207-
if (!spiGroups.empty()) {
6208-
importText += "@_spi(";
6209-
importText += spiGroups[0].str();
6210-
importText += ") ";
6211-
}
6212-
}
6213-
6214-
importText += "import ";
6215-
importText += definingModule->getName().str();
6216-
importText += "\n";
6217-
emitDiagnosticAt(bestLoc, diag::candidate_add_import,
6218-
definingModule->getName())
6219-
.fixItInsert(bestLoc, importText);
6220-
}
6191+
diagnoseMissingImportForMember(Member, getDC(), loc))
6192+
return true;
62216193

6222-
suppressDeclHereNote = true;
6223-
} else if (auto *CD = dyn_cast<ConstructorDecl>(Member)) {
6194+
if (auto *CD = dyn_cast<ConstructorDecl>(Member)) {
62246195
emitDiagnosticAt(loc, diag::init_candidate_inaccessible,
62256196
CD->getResultInterfaceType(), accessLevel)
62266197
.highlight(nameLoc.getSourceRange());
@@ -6230,8 +6201,7 @@ bool InaccessibleMemberFailure::diagnoseAsError() {
62306201
.highlight(nameLoc.getSourceRange());
62316202
}
62326203

6233-
if (!suppressDeclHereNote)
6234-
emitDiagnosticAt(Member, diag::decl_declared_here, Member);
6204+
emitDiagnosticAt(Member, diag::decl_declared_here, Member);
62356205
return true;
62366206
}
62376207

lib/Sema/PreCheckExpr.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -521,9 +521,14 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE,
521521
if (inaccessibleResults) {
522522
// FIXME: What if the unviable candidates have different levels of access?
523523
const ValueDecl *first = inaccessibleResults.front().getValueDecl();
524-
Context.Diags.diagnose(
525-
Loc, diag::candidate_inaccessible, first,
526-
first->getFormalAccessScope().accessLevelForDiagnostics());
524+
auto accessLevel =
525+
first->getFormalAccessScope().accessLevelForDiagnostics();
526+
if (accessLevel == AccessLevel::Public &&
527+
diagnoseMissingImportForMember(first, DC, Loc))
528+
return errorResult();
529+
530+
Context.Diags.diagnose(Loc, diag::candidate_inaccessible, first,
531+
accessLevel);
527532

528533
// FIXME: If any of the candidates (usually just one) are in the same
529534
// module we could offer a fix-it.

lib/Sema/TypeCheckType.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "swift/AST/ExistentialLayout.h"
3131
#include "swift/AST/ForeignErrorConvention.h"
3232
#include "swift/AST/GenericEnvironment.h"
33+
#include "swift/AST/Module.h"
3334
#include "swift/AST/NameLookup.h"
3435
#include "swift/AST/PackExpansionMatcher.h"
3536
#include "swift/AST/ParameterList.h"
@@ -1364,8 +1365,14 @@ static Type diagnoseUnknownType(TypeResolution resolution,
13641365
if (!inaccessibleResults.empty()) {
13651366
// FIXME: What if the unviable candidates have different levels of access?
13661367
auto first = cast<TypeDecl>(inaccessibleResults.front().getValueDecl());
1367-
diags.diagnose(repr->getNameLoc(), diag::candidate_inaccessible,
1368-
first, first->getFormalAccess());
1368+
auto formalAccess = first->getFormalAccess();
1369+
auto nameLoc = repr->getNameLoc();
1370+
if (formalAccess >= AccessLevel::Public &&
1371+
diagnoseMissingImportForMember(first, dc, nameLoc.getStartLoc()))
1372+
return ErrorType::get(ctx);
1373+
1374+
diags.diagnose(nameLoc, diag::candidate_inaccessible, first,
1375+
formalAccess);
13691376

13701377
// FIXME: If any of the candidates (usually just one) are in the same
13711378
// module we could offer a fix-it.
@@ -1454,8 +1461,13 @@ static Type diagnoseUnknownType(TypeResolution resolution,
14541461
if (inaccessibleMembers) {
14551462
// FIXME: What if the unviable candidates have different levels of access?
14561463
const TypeDecl *first = inaccessibleMembers.front().Member;
1457-
diags.diagnose(repr->getNameLoc(), diag::candidate_inaccessible,
1458-
first, first->getFormalAccess());
1464+
auto formalAccess = first->getFormalAccess();
1465+
auto nameLoc = repr->getNameLoc();
1466+
if (formalAccess >= AccessLevel::Public &&
1467+
diagnoseMissingImportForMember(first, dc, nameLoc.getStartLoc()))
1468+
return ErrorType::get(ctx);
1469+
1470+
diags.diagnose(nameLoc, diag::candidate_inaccessible, first, formalAccess);
14591471

14601472
// FIXME: If any of the candidates (usually just one) are in the same module
14611473
// we could offer a fix-it.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
@import Categories_A;
2+
3+
@interface X (BridgingHeader)
4+
- (void)fromBridgingHeader;
5+
@end
6+
7+
struct StructInBridgingHeader {
8+
int member;
9+
};
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
struct UnderlyingStruct {
3+
int a;
4+
};

test/NameLookup/Inputs/extensions_A.swift renamed to test/NameLookup/Inputs/MemberImportVisibility/members_A.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,19 @@ infix operator <>
1515
extension X {
1616
public func XinA() { }
1717

18+
public var propXinA: Bool { return true }
19+
1820
public static func <<<(a: Self, b: Self) -> Self { a }
21+
22+
public struct NestedInA {}
1923
}
2024

2125
extension Y {
2226
public func YinA() { }
2327

2428
public static func <<<(a: Self, b: Self) -> Self { a }
2529
}
30+
31+
public enum EnumInA {
32+
case caseInA
33+
}
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
import extensions_A
1+
import members_A
22

33

44
extension X {
55
public func XinB() { }
66

7+
public var propXinB: Bool { return true }
8+
79
public static func >>>(a: Self, b: Self) -> Self { b }
10+
11+
public struct NestedInB {}
812
}
913

1014
extension Y {
@@ -13,3 +17,6 @@ extension Y {
1317
public static func >>>(a: Self, b: Self) -> Self { b }
1418
}
1519

20+
public enum EnumInB {
21+
case caseInB
22+
}
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
1-
@_exported import extensions_A
2-
import extensions_B
1+
@_exported import members_A
2+
import members_B
33

44

55
extension X {
66
public func XinC() { }
77

8+
public var propXinC: Bool { return true }
9+
810
public static func <>(a: Self, b: Self) -> Self { a }
11+
12+
public struct NestedInC {}
913
}
1014

1115
extension Y {
1216
public func YinC() { }
1317

1418
public static func <>(a: Self, b: Self) -> Self { a }
1519
}
20+
21+
public enum EnumInC {
22+
case caseInC
23+
}

test/NameLookup/Inputs/Categories/module.modulemap renamed to test/NameLookup/Inputs/MemberImportVisibility/module.modulemap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,7 @@ module Categories_D {
2323
}
2424
}
2525

26+
module Underlying {
27+
header "Underlying.h"
28+
export *
29+
}

test/NameLookup/extensions_transitive.swift

Lines changed: 0 additions & 27 deletions
This file was deleted.

0 commit comments

Comments
 (0)