Skip to content

Commit 724d434

Browse files
authored
Merge pull request #16951 from DougGregor/overlay-shadow-reexported-module
[Type checking] A declaration in an overlay can shadow an imported declaration.
2 parents c246626 + 248ca75 commit 724d434

File tree

11 files changed

+115
-28
lines changed

11 files changed

+115
-28
lines changed

lib/AST/NameLookup.cpp

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
//===----------------------------------------------------------------------===//
1616

1717
#include "NameLookupImpl.h"
18-
#include "swift/Basic/Statistic.h"
18+
#include "swift/ClangImporter/ClangImporter.h"
1919
#include "swift/AST/NameLookup.h"
2020
#include "swift/AST/ASTContext.h"
2121
#include "swift/AST/ASTScope.h"
@@ -26,6 +26,7 @@
2626
#include "swift/AST/Initializer.h"
2727
#include "swift/AST/ReferencedNameTracker.h"
2828
#include "swift/Basic/SourceManager.h"
29+
#include "swift/Basic/Statistic.h"
2930
#include "swift/Basic/STLExtras.h"
3031
#include "llvm/ADT/DenseMap.h"
3132
#include "llvm/ADT/TinyPtrVector.h"
@@ -281,20 +282,35 @@ bool swift::removeShadowedDecls(SmallVectorImpl<ValueDecl*> &decls,
281282
// module.
282283
// FIXME: This is a hack. We should query a (lazily-built, cached)
283284
// module graph to determine shadowing.
284-
if ((firstModule == curModule) == (secondModule == curModule))
285-
continue;
285+
if ((firstModule == curModule) != (secondModule == curModule)) {
286+
// If the first module is the current module, the second declaration
287+
// is shadowed by the first.
288+
if (firstModule == curModule) {
289+
shadowed.insert(secondDecl);
290+
continue;
291+
}
286292

287-
// If the first module is the current module, the second declaration
288-
// is shadowed by the first.
289-
if (firstModule == curModule) {
290-
shadowed.insert(secondDecl);
291-
continue;
293+
// Otherwise, the first declaration is shadowed by the second. There is
294+
// no point in continuing to compare the first declaration to others.
295+
shadowed.insert(firstDecl);
296+
break;
292297
}
293298

294-
// Otherwise, the first declaration is shadowed by the second. There is
295-
// no point in continuing to compare the first declaration to others.
296-
shadowed.insert(firstDecl);
297-
break;
299+
// Prefer declarations in an overlay to similar declarations in
300+
// the Clang module it customizes.
301+
if (firstDecl->hasClangNode() != secondDecl->hasClangNode()) {
302+
if (isInOverlayModuleForImportedModule(firstDecl->getDeclContext(),
303+
secondDecl->getDeclContext())){
304+
shadowed.insert(secondDecl);
305+
continue;
306+
}
307+
308+
if (isInOverlayModuleForImportedModule(secondDecl->getDeclContext(),
309+
firstDecl->getDeclContext())) {
310+
shadowed.insert(firstDecl);
311+
break;
312+
}
313+
}
298314
}
299315
}
300316
}

lib/Sema/TypeCheckNameLookup.cpp

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,37 @@ namespace {
7575
Options |= NameLookupFlags::IgnoreAccessControl;
7676
}
7777

78+
/// Determine whether we should filter out the results by removing
79+
/// overridden and shadowed declarations.
80+
/// FIXME: We should *always* do this, but there are weird assumptions
81+
/// about the results of unqualified name lookup, e.g., that a local
82+
/// variable not having a type indicates that it hasn't been seen yet.
83+
bool shouldFilterResults() const {
84+
// Member lookups always filter results.
85+
if (IsMemberLookup) return true;
86+
87+
bool allAreInOtherModules = true;
88+
auto currentModule = DC->getParentModule();
89+
for (const auto &found : Result) {
90+
// We found a member, so we need to filter.
91+
if (found.getBaseDecl() != nullptr)
92+
return true;
93+
94+
// We found something in our own module.
95+
if (found.getValueDecl()->getDeclContext()->getParentModule() ==
96+
currentModule)
97+
allAreInOtherModules = false;
98+
}
99+
100+
// FIXME: Only perform shadowing if we found things from other modules.
101+
// This prevents us from introducing additional type-checking work
102+
// during name lookup.
103+
return allAreInOtherModules;
104+
}
105+
78106
~LookupResultBuilder() {
79-
// If any of the results have a base, we need to remove
80-
// overridden and shadowed declarations.
81-
// FIXME: We should *always* remove overridden and shadowed declarations,
82-
// but there are weird assumptions about the results of unqualified
83-
// name lookup, e.g., that a local variable not having a type indicates
84-
// that it hasn't been seen yet.
85-
if (!IsMemberLookup &&
86-
std::find_if(Result.begin(), Result.end(),
87-
[](const LookupResultEntry &found) {
88-
return found.getBaseDecl() != nullptr;
89-
}) == Result.end())
90-
return;
107+
// Check whether we should do this filtering aat all.
108+
if (!shouldFilterResults()) return;
91109

92110
// Remove any overridden declarations from the found-declarations set.
93111
removeOverriddenDecls(FoundDecls);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#import <SomeKit/SKWidget.h>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#import <SomeKitCore/SKWidget.h>

test/ClangImporter/Inputs/privateframeworks/overlay/SomeKit.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,10 @@ public func inlineWidgetOperations(_ widget: SKWidget) {
4747
someKitGlobalFunc()
4848
hao.anObject = widget
4949
}
50+
51+
@available(swift, deprecated: 4.2)
52+
public func someKitOtherGlobalFunc() { }
53+
54+
extension SKWidget {
55+
public var name: String { return "blah" }
56+
}

test/ClangImporter/Inputs/privateframeworks/withoutprivate/SomeKit.framework/Headers/SKWidget.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,8 @@ typedef enum __attribute__((ns_error_domain(SKWidgetErrorDomain))) __attribute__
2424
@end
2525

2626
extern void someKitGlobalFunc(void);
27+
28+
static inline void someKitOtherGlobalFunc(void) { }
29+
30+
extern NSString * _Nonnull someKitGetWidgetName(SKWidget * _Nonnull)
31+
__attribute__((swift_name("getter:SKWidget.name(self:)")));
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
Name: SomeKit
3+
Functions:
4+
- Name: someKitOtherGlobalFunc
5+
SwiftPrivate: true
6+
SwiftVersions:
7+
- Version: 4
8+
Functions:
9+
- Name: someKitOtherGlobalFunc
10+
SwiftPrivate: false
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
Name: SomeKit
3+
SwiftVersions:
4+
- Version: 4
5+
Functions:
6+
- Name: someKitOtherGlobalFunc
7+
SwiftPrivate: false

test/ClangImporter/Inputs/privateframeworks/withprivate/SomeKitCore.framework/Headers/SKWidget.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,8 @@ typedef enum __attribute__((ns_error_domain(SKWidgetErrorDomain))) __attribute__
2525
@end
2626

2727
extern void someKitGlobalFunc(void);
28+
29+
static inline void someKitOtherGlobalFunc(void) { }
30+
31+
extern NSString * _Nonnull someKitGetWidgetName(SKWidget * _Nonnull)
32+
__attribute__((swift_name("getter:SKWidget.name(self:)")));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
Name: SomeKitCore
3+
Functions:
4+
- Name: someKitOtherGlobalFunc
5+
SwiftPrivate: true
6+
SwiftVersions:
7+
- Version: 4
8+
Functions:
9+
- Name: someKitOtherGlobalFunc
10+
SwiftPrivate: false

test/ClangImporter/private_frameworks.swift

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@
99
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-module -F %S/Inputs/privateframeworks/withprivate -o %t %S/Inputs/privateframeworks/overlay/SomeKit.swift
1010

1111
// Use the overlay with private frameworks.
12-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withprivate %s -verify
12+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withprivate -swift-version 4 %s -import-objc-header %S/Inputs/privateframeworks/bridging-somekitcore.h -verify
1313

1414
// Use the overlay without private frameworks.
15-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withoutprivate -I %t %s
15+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withoutprivate -I %t -swift-version 4 -import-objc-header %S/Inputs/privateframeworks/bridging-somekit.h %s
1616

1717
// Build the overlay with public frameworks.
1818
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-module -F %S/Inputs/privateframeworks/withoutprivate -o %t %S/Inputs/privateframeworks/overlay/SomeKit.swift
1919

2020
// Use the overlay with private frameworks.
21-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withprivate %s -verify
21+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withprivate -swift-version 4 %s -import-objc-header %S/Inputs/privateframeworks/bridging-somekitcore.h -verify
2222

2323
// Use the overlay without private frameworks.
24-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withoutprivate -I %t %s
24+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -emit-sil -o /dev/null -F %S/Inputs/privateframeworks/withoutprivate -I %t -swift-version 4 %s -import-objc-header %S/Inputs/privateframeworks/bridging-somekit.h
2525

2626
// REQUIRES: objc_interop
2727

@@ -36,10 +36,17 @@ func testWidget(widget: SKWidget) {
3636

3737
widget.doSomethingElse(widget)
3838
inlineWidgetOperations(widget)
39+
40+
let _ = widget.name
3941
}
4042

4143
func testError(widget: SKWidget) {
4244
let c: SKWidget.Error.Code = SKWidget.Error(.boom).getCode(from: widget)
4345
if c.isBoom { }
4446
}
4547

48+
func testGlobals() {
49+
someKitGlobalFunc()
50+
SomeKit.someKitOtherGlobalFunc()
51+
someKitOtherGlobalFunc()
52+
}

0 commit comments

Comments
 (0)