Skip to content

Commit 304f9c4

Browse files
committed
AST: Look through missing imports in OverriddenDeclsRequest.
If `OverriddenDeclsRequest` fails to find any overridden declarations, query again ignoring missing imports to find declarations that were excluded due to the `MemberImportVisibility` feature being enabled.
1 parent bdc6fc6 commit 304f9c4

File tree

2 files changed

+116
-55
lines changed

2 files changed

+116
-55
lines changed

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 114 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -814,8 +814,11 @@ namespace {
814814
/// The type of the declaration, cached here once it has been computed.
815815
Type cachedDeclType;
816816

817+
/// Whether to ignore missing imports when looking for overridden methods.
818+
bool ignoreMissingImports;
819+
817820
public:
818-
OverrideMatcher(ValueDecl *decl);
821+
OverrideMatcher(ValueDecl *decl, bool ignoreMissingImports);
819822

820823
/// Returns true when it's possible to perform any override matching.
821824
explicit operator bool() const {
@@ -860,8 +863,9 @@ namespace {
860863
};
861864
}
862865

863-
OverrideMatcher::OverrideMatcher(ValueDecl *decl)
864-
: ctx(decl->getASTContext()), decl(decl) {
866+
OverrideMatcher::OverrideMatcher(ValueDecl *decl, bool ignoreMissingImports)
867+
: ctx(decl->getASTContext()), decl(decl),
868+
ignoreMissingImports(ignoreMissingImports) {
865869
// The final step for this constructor is to set up the superclass type,
866870
// without which we will not perform an matching. Early exits therefore imply
867871
// that there is no way we can match this declaration.
@@ -916,8 +920,12 @@ SmallVector<OverrideMatch, 2> OverrideMatcher::match(
916920
for (auto *ctx : superContexts) {
917921
ctx->synthesizeSemanticMembersIfNeeded(membersName);
918922
}
919-
dc->lookupQualified(superContexts, DeclNameRef(membersName),
920-
decl->getLoc(), NL_QualifiedDefault, members);
923+
auto lookupOptions = NL_QualifiedDefault;
924+
if (ignoreMissingImports)
925+
lookupOptions |= NL_IgnoreMissingImports;
926+
927+
dc->lookupQualified(superContexts, DeclNameRef(membersName), decl->getLoc(),
928+
lookupOptions, members);
921929
}
922930

923931
// Check each member we found.
@@ -1373,50 +1381,12 @@ TinyPtrVector<ValueDecl *> OverrideMatcher::checkPotentialOverrides(
13731381
return overridden;
13741382
}
13751383

1376-
/// Determine which method or subscript this method or subscript overrides
1377-
/// (if any).
1378-
///
1379-
/// \returns true if an error occurred.
1380-
bool swift::checkOverrides(ValueDecl *decl) {
1381-
// If there is a @_nonoverride attribute, this does not override anything.
1382-
if (decl->getAttrs().hasAttribute<NonOverrideAttr>())
1383-
return false;
1384-
1385-
// If we already computed overridden declarations and either succeeded
1386-
// or invalidated the attribute, there's nothing more to do.
1387-
if (decl->overriddenDeclsComputed()) {
1388-
// If we computed an overridden declaration successfully, we're done.
1389-
if (decl->getOverriddenDecl())
1390-
return false;
1391-
1392-
// If we set the override attribute to "invalid", we already diagnosed
1393-
// something here.
1394-
if (decl->getAttrs().hasAttribute<OverrideAttr>(/*AllowInvalid=*/true) &&
1395-
!decl->getAttrs().hasAttribute<OverrideAttr>())
1396-
return true;
1397-
1398-
// Otherwise, we have more checking to do.
1399-
}
1400-
1401-
// Members of constrained extensions are not considered to be overrides.
1402-
if (auto *ext = dyn_cast<ExtensionDecl>(decl->getDeclContext()))
1403-
if (ext->isConstrainedExtension())
1404-
return false;
1405-
1406-
// Accessor methods get overrides through their storage declaration, and
1407-
// all checking can be performed via that mechanism.
1408-
if (isa<AccessorDecl>(decl)) {
1409-
(void)decl->getOverriddenDecls();
1410-
return false;
1411-
}
1412-
1413-
// Don't bother checking any further for invalid decls since they won't match
1414-
// anything.
1415-
if (decl->isInvalid())
1416-
return true;
1417-
1384+
static bool
1385+
checkPotentialOverrides(ValueDecl *decl,
1386+
TinyPtrVector<ValueDecl *> &potentialOverrides,
1387+
bool ignoreMissingImports) {
14181388
// Set up matching, but bail out if there's nothing to match.
1419-
OverrideMatcher matcher(decl);
1389+
OverrideMatcher matcher(decl, ignoreMissingImports);
14201390
if (!matcher) return false;
14211391

14221392
// Look for members with the same name and matching types as this
@@ -1470,10 +1440,80 @@ bool swift::checkOverrides(ValueDecl *decl) {
14701440

14711441
// FIXME: Check for missing 'override' keyword here?
14721442

1443+
for (auto match : matcher.checkPotentialOverrides(matches, attempt)) {
1444+
potentialOverrides.push_back(match);
1445+
}
1446+
1447+
return true;
1448+
}
1449+
1450+
/// Determine which method or subscript this method or subscript overrides
1451+
/// (if any).
1452+
///
1453+
/// \returns true if an error occurred.
1454+
bool swift::checkOverrides(ValueDecl *decl) {
1455+
// If there is a @_nonoverride attribute, this does not override anything.
1456+
if (decl->getAttrs().hasAttribute<NonOverrideAttr>())
1457+
return false;
1458+
1459+
// If we already computed overridden declarations and either succeeded
1460+
// or invalidated the attribute, there's nothing more to do.
1461+
if (decl->overriddenDeclsComputed()) {
1462+
// If we computed an overridden declaration successfully, we're done.
1463+
if (decl->getOverriddenDecl())
1464+
return false;
1465+
1466+
// If we set the override attribute to "invalid", we already diagnosed
1467+
// something here.
1468+
if (decl->getAttrs().hasAttribute<OverrideAttr>(/*AllowInvalid=*/true) &&
1469+
!decl->getAttrs().hasAttribute<OverrideAttr>())
1470+
return true;
1471+
1472+
// Otherwise, we have more checking to do.
1473+
}
1474+
1475+
// Members of constrained extensions are not considered to be overrides.
1476+
if (auto *ext = dyn_cast<ExtensionDecl>(decl->getDeclContext()))
1477+
if (ext->isConstrainedExtension())
1478+
return false;
1479+
1480+
// Accessor methods get overrides through their storage declaration, and
1481+
// all checking can be performed via that mechanism.
1482+
if (isa<AccessorDecl>(decl)) {
1483+
(void)decl->getOverriddenDecls();
1484+
return false;
1485+
}
1486+
1487+
// Don't bother checking any further for invalid decls since they won't match
1488+
// anything.
1489+
if (decl->isInvalid())
1490+
return true;
1491+
1492+
TinyPtrVector<ValueDecl *> overridden;
1493+
if (!checkPotentialOverrides(decl, overridden,
1494+
/*ignoreMissingImports=*/false))
1495+
return false;
1496+
1497+
auto &ctx = decl->getASTContext();
1498+
if (overridden.empty() &&
1499+
ctx.LangOpts.hasFeature(Feature::MemberImportVisibility)) {
1500+
// If we didn't find anything, try broadening the search by ignoring missing
1501+
// imports.
1502+
if (!checkPotentialOverrides(decl, overridden,
1503+
/*ignoreMissingImports=*/true))
1504+
return false;
1505+
1506+
if (!overridden.empty()) {
1507+
auto first = overridden.front();
1508+
if (maybeDiagnoseMissingImportForMember(first, decl->getDeclContext(),
1509+
decl->getLoc()))
1510+
return true;
1511+
}
1512+
}
1513+
14731514
// We performed override checking, so record the overrides.
14741515
// FIXME: It's weird to be pushing state here, but how do we say that
14751516
// this check subsumes the normal 'override' check?
1476-
auto overridden = matcher.checkPotentialOverrides(matches, attempt);
14771517
if (overridden.empty())
14781518
invalidateOverrideAttribute(decl);
14791519
decl->setOverriddenDecls(overridden);
@@ -2263,8 +2303,8 @@ computeOverriddenAssociatedTypes(AssociatedTypeDecl *assocType) {
22632303
return overriddenAssocTypes;
22642304
}
22652305

2266-
llvm::TinyPtrVector<ValueDecl *>
2267-
OverriddenDeclsRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
2306+
static llvm::TinyPtrVector<ValueDecl *>
2307+
computeOverriddenDecls(ValueDecl *decl, bool ignoreMissingImports) {
22682308
// Value to return in error cases
22692309
auto noResults = llvm::TinyPtrVector<ValueDecl *>();
22702310

@@ -2359,7 +2399,7 @@ OverriddenDeclsRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
23592399
return noResults;
23602400

23612401
// Check the correctness of the overrides.
2362-
OverrideMatcher matcher(accessor);
2402+
OverrideMatcher matcher(accessor, ignoreMissingImports);
23632403
return matcher.checkPotentialOverrides(
23642404
matches,
23652405
OverrideCheckingAttempt::PerfectMatch);
@@ -2373,7 +2413,7 @@ OverriddenDeclsRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
23732413
return noResults;
23742414

23752415
// Try to match potential overridden declarations.
2376-
OverrideMatcher matcher(decl);
2416+
OverrideMatcher matcher(decl, ignoreMissingImports);
23772417
if (!matcher) {
23782418
return noResults;
23792419
}
@@ -2398,6 +2438,27 @@ OverriddenDeclsRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
23982438
OverrideCheckingAttempt::PerfectMatch);
23992439
}
24002440

2441+
llvm::TinyPtrVector<ValueDecl *>
2442+
OverriddenDeclsRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
2443+
auto &ctx = decl->getASTContext();
2444+
auto overridden = computeOverriddenDecls(decl, false);
2445+
2446+
// If we didn't find anything, try broadening the search by ignoring missing
2447+
// imports.
2448+
if (overridden.empty() &&
2449+
ctx.LangOpts.hasFeature(Feature::MemberImportVisibility)) {
2450+
overridden = computeOverriddenDecls(decl, true);
2451+
if (!overridden.empty()) {
2452+
auto first = overridden.front();
2453+
if (maybeDiagnoseMissingImportForMember(first, decl->getDeclContext(),
2454+
decl->getLoc()))
2455+
return {};
2456+
}
2457+
}
2458+
2459+
return overridden;
2460+
}
2461+
24012462
bool IsABICompatibleOverrideRequest::evaluate(Evaluator &evaluator,
24022463
ValueDecl *decl) const {
24032464
auto base = decl->getOverriddenDecl();

test/NameLookup/members_transitive.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// RUN: %target-swift-frontend -typecheck %s -I %t -verify -swift-version 5 -package-name TestPackage -enable-experimental-feature MemberImportVisibility -verify-additional-prefix member-visibility-
88

99
import members_C
10-
// expected-member-visibility-note 11{{add import of module 'members_B'}}{{1-1=internal import members_B\n}}
10+
// expected-member-visibility-note 12{{add import of module 'members_B'}}{{1-1=internal import members_B\n}}
1111

1212

1313
func testExtensionMembers(x: X, y: Y<Z>) {
@@ -70,7 +70,7 @@ func testTopLevelTypes() {
7070

7171
class DerivedFromClassInC: DerivedClassInC {
7272
override func methodInA() {}
73-
override func methodInB() {} // expected-member-visibility-error{{method does not override any method from its superclass}}
73+
override func methodInB() {} // expected-member-visibility-error{{instance method 'methodInB()' is not available due to missing import of defining module 'members_B'}}
7474
override func methodInC() {}
7575
}
7676

0 commit comments

Comments
 (0)