Skip to content

Commit 9209e4f

Browse files
authored
Merge pull request #28840 from CodaFi/constrnation
2 parents 15bcf53 + b654bc3 commit 9209e4f

File tree

8 files changed

+77
-38
lines changed

8 files changed

+77
-38
lines changed

lib/AST/NameLookup.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,13 +1274,6 @@ TinyPtrVector<ValueDecl *> NominalTypeDecl::lookupDirect(
12741274
bool includeAttrImplements =
12751275
flags.contains(LookupDirectFlags::IncludeAttrImplements);
12761276

1277-
// FIXME: At present, lazy member is not able to find inherited constructors
1278-
// in imported classes, because SwiftDeclConverter::importInheritedConstructors()
1279-
// is only called via ClangImporter::Implementation::loadAllMembers().
1280-
if (hasClangNode() &&
1281-
name.getBaseName() == DeclBaseName::createConstructor())
1282-
useNamedLazyMemberLoading = false;
1283-
12841277
LLVM_DEBUG(llvm::dbgs() << getNameStr() << ".lookupDirect("
12851278
<< name << ")"
12861279
<< ", isLookupTablePopulated()=" << isLookupTablePopulated()

lib/ClangImporter/ClangImporter.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3822,6 +3822,16 @@ ClangImporter::Implementation::loadNamedMembers(
38223822
}
38233823
}
38243824
}
3825+
3826+
if (N == DeclBaseName::createConstructor()) {
3827+
if (auto *classDecl = dyn_cast<ClassDecl>(D)) {
3828+
SmallVector<Decl *, 4> ctors;
3829+
importInheritedConstructors(cast<clang::ObjCInterfaceDecl>(CD),
3830+
classDecl, ctors);
3831+
for (auto ctor : ctors)
3832+
Members.push_back(cast<ValueDecl>(ctor));
3833+
}
3834+
}
38253835
return Members;
38263836
}
38273837

lib/ClangImporter/DWARFImporter.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,17 @@ ModuleDecl *ClangImporter::Implementation::loadModuleDWARF(
128128
return decl;
129129
}
130130

131+
// This function exists to defeat the lazy member importing mechanism. The
132+
// DWARFImporter is not capable of loading individual members, so it cannot
133+
// benefit from this optimization yet anyhow. Besides, if you're importing a
134+
// type here, you more than likely want to dump it and its fields. Loading all
135+
// members populates lookup tables in the Clang Importer and ensures the
136+
// absence of cache-fill-related side effects.
137+
static void forceLoadAllMembers(IterableDeclContext *IDC) {
138+
if (!IDC) return;
139+
IDC->loadAllMembers();
140+
}
141+
131142
void ClangImporter::Implementation::lookupValueDWARF(
132143
DeclName name, NLKind lookupKind, Identifier inModule,
133144
SmallVectorImpl<ValueDecl *> &results) {
@@ -150,8 +161,10 @@ void ClangImporter::Implementation::lookupValueDWARF(
150161
continue;
151162

152163
if (swiftDecl->getFullName().matchesRef(name) &&
153-
swiftDecl->getDeclContext()->isModuleScopeContext())
164+
swiftDecl->getDeclContext()->isModuleScopeContext()) {
165+
forceLoadAllMembers(dyn_cast<IterableDeclContext>(swiftDecl));
154166
results.push_back(swiftDecl);
167+
}
155168
}
156169
}
157170

@@ -174,8 +187,10 @@ void ClangImporter::Implementation::lookupTypeDeclDWARF(
174187
Decl *importedDecl = cast_or_null<ValueDecl>(
175188
importDeclReal(namedDecl->getMostRecentDecl(), CurrentVersion));
176189

177-
if (auto *importedType = dyn_cast_or_null<TypeDecl>(importedDecl))
190+
if (auto *importedType = dyn_cast_or_null<TypeDecl>(importedDecl)) {
191+
forceLoadAllMembers(dyn_cast<IterableDeclContext>(importedType));
178192
receiver(importedType);
193+
}
179194
}
180195
}
181196

lib/ClangImporter/ImportDecl.cpp

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ getDefaultMakeStructRawValuedOptions() {
104104
return opts;
105105
}
106106

107-
static bool isInSystemModule(DeclContext *D) {
107+
static bool isInSystemModule(const DeclContext *D) {
108108
return cast<ClangModuleUnit>(D->getModuleScopeContext())->isSystemModule();
109109
}
110110

@@ -4091,7 +4091,7 @@ namespace {
40914091
/// Check whether we have already imported a method with the given
40924092
/// selector in the given context.
40934093
bool isMethodAlreadyImported(ObjCSelector selector, bool isInstance,
4094-
DeclContext *dc,
4094+
const DeclContext *dc,
40954095
llvm::function_ref<bool(AbstractFunctionDecl *fn)> filter) {
40964096
// We only need to perform this check for classes.
40974097
auto classDecl
@@ -4425,7 +4425,7 @@ namespace {
44254425
/// NSArray(capacity: 1024)
44264426
/// \endcode
44274427
ConstructorDecl *importConstructor(const clang::ObjCMethodDecl *objcMethod,
4428-
DeclContext *dc,
4428+
const DeclContext *dc,
44294429
bool implicit,
44304430
Optional<CtorInitializerKind> kind,
44314431
bool required);
@@ -4454,7 +4454,7 @@ namespace {
44544454
/// This variant of the function is responsible for actually binding the
44554455
/// constructor declaration appropriately.
44564456
ConstructorDecl *importConstructor(const clang::ObjCMethodDecl *objcMethod,
4457-
DeclContext *dc,
4457+
const DeclContext *dc,
44584458
bool implicit,
44594459
CtorInitializerKind kind,
44604460
bool required,
@@ -4518,16 +4518,15 @@ namespace {
45184518
void importMirroredProtocolMembers(const clang::ObjCContainerDecl *decl,
45194519
DeclContext *dc,
45204520
ArrayRef<ProtocolDecl *> protocols,
4521-
SmallVectorImpl<Decl *> &members,
4522-
ASTContext &Ctx);
4521+
SmallVectorImpl<Decl *> &members);
45234522

45244523
void importNonOverriddenMirroredMethods(DeclContext *dc,
45254524
MutableArrayRef<MirroredMethodEntry> entries,
45264525
SmallVectorImpl<Decl *> &newMembers);
45274526

45284527
/// Import constructors from our superclasses (and their
45294528
/// categories/extensions), effectively "inheriting" constructors.
4530-
void importInheritedConstructors(ClassDecl *classDecl,
4529+
void importInheritedConstructors(const ClassDecl *classDecl,
45314530
SmallVectorImpl<Decl *> &newMembers);
45324531

45334532
Decl *VisitObjCCategoryDecl(const clang::ObjCCategoryDecl *decl) {
@@ -6083,7 +6082,7 @@ SwiftDeclConverter::getImplicitProperty(ImportedName importedName,
60836082
}
60846083

60856084
ConstructorDecl *SwiftDeclConverter::importConstructor(
6086-
const clang::ObjCMethodDecl *objcMethod, DeclContext *dc, bool implicit,
6085+
const clang::ObjCMethodDecl *objcMethod, const DeclContext *dc, bool implicit,
60876086
Optional<CtorInitializerKind> kind, bool required) {
60886087
// Only methods in the 'init' family can become constructors.
60896088
assert(isInitMethod(objcMethod) && "Not a real init method");
@@ -6234,7 +6233,7 @@ bool SwiftDeclConverter::existingConstructorIsWorse(
62346233
/// This variant of the function is responsible for actually binding the
62356234
/// constructor declaration appropriately.
62366235
ConstructorDecl *SwiftDeclConverter::importConstructor(
6237-
const clang::ObjCMethodDecl *objcMethod, DeclContext *dc, bool implicit,
6236+
const clang::ObjCMethodDecl *objcMethod, const DeclContext *dc, bool implicit,
62386237
CtorInitializerKind kind, bool required, ObjCSelector selector,
62396238
ImportedName importedName, ArrayRef<const clang::ParmVarDecl *> args,
62406239
bool variadic, bool &redundant) {
@@ -6354,7 +6353,7 @@ ConstructorDecl *SwiftDeclConverter::importConstructor(
63546353
/*NameLoc=*/SourceLoc(), failability, /*FailabilityLoc=*/SourceLoc(),
63556354
/*Throws=*/importedName.getErrorInfo().hasValue(),
63566355
/*ThrowsLoc=*/SourceLoc(), bodyParams,
6357-
/*GenericParams=*/nullptr, dc);
6356+
/*GenericParams=*/nullptr, const_cast<DeclContext *>(dc));
63586357

63596358
addObjCAttribute(result, selector);
63606359

@@ -6941,8 +6940,7 @@ Optional<GenericParamList *> SwiftDeclConverter::importObjCGenericParams(
69416940

69426941
void SwiftDeclConverter::importMirroredProtocolMembers(
69436942
const clang::ObjCContainerDecl *decl, DeclContext *dc,
6944-
ArrayRef<ProtocolDecl *> protocols, SmallVectorImpl<Decl *> &members,
6945-
ASTContext &Ctx) {
6943+
ArrayRef<ProtocolDecl *> protocols, SmallVectorImpl<Decl *> &members) {
69466944
assert(dc);
69476945
const clang::ObjCInterfaceDecl *interfaceDecl = nullptr;
69486946
const ClangModuleUnit *declModule;
@@ -7189,7 +7187,7 @@ void SwiftDeclConverter::importNonOverriddenMirroredMethods(DeclContext *dc,
71897187
}
71907188

71917189
void SwiftDeclConverter::importInheritedConstructors(
7192-
ClassDecl *classDecl, SmallVectorImpl<Decl *> &newMembers) {
7190+
const ClassDecl *classDecl, SmallVectorImpl<Decl *> &newMembers) {
71937191
if (!classDecl->hasSuperclass())
71947192
return;
71957193

@@ -8673,6 +8671,15 @@ void ClangImporter::Implementation::insertMembersAndAlternates(
86738671
});
86748672
}
86758673

8674+
void ClangImporter::Implementation::importInheritedConstructors(
8675+
const clang::ObjCInterfaceDecl *curObjCClass,
8676+
const ClassDecl *classDecl, SmallVectorImpl<Decl *> &newMembers) {
8677+
if (curObjCClass->getName() != "Protocol") {
8678+
SwiftDeclConverter converter(*this, CurrentVersion);
8679+
converter.importInheritedConstructors(classDecl, newMembers);
8680+
}
8681+
}
8682+
86768683
void ClangImporter::Implementation::collectMembersToAdd(
86778684
const clang::ObjCContainerDecl *objcContainer, Decl *D, DeclContext *DC,
86788685
SmallVectorImpl<Decl *> &members) {
@@ -8687,24 +8694,16 @@ void ClangImporter::Implementation::collectMembersToAdd(
86878694

86888695
auto protos = getImportedProtocols(D);
86898696
if (auto clangClass = dyn_cast<clang::ObjCInterfaceDecl>(objcContainer)) {
8690-
auto swiftClass = cast<ClassDecl>(D);
86918697
objcContainer = clangClass = clangClass->getDefinition();
8692-
8693-
// Imported inherited initializers.
8694-
if (clangClass->getName() != "Protocol") {
8695-
converter.importInheritedConstructors(const_cast<ClassDecl *>(swiftClass),
8696-
members);
8697-
}
8698-
8698+
importInheritedConstructors(clangClass, cast<ClassDecl>(D), members);
86998699
} else if (auto clangProto
87008700
= dyn_cast<clang::ObjCProtocolDecl>(objcContainer)) {
87018701
objcContainer = clangProto->getDefinition();
87028702
}
87038703
// Import mirrored declarations for protocols to which this category
87048704
// or extension conforms.
87058705
// FIXME: This is supposed to be a short-term hack.
8706-
converter.importMirroredProtocolMembers(objcContainer, DC,
8707-
protos, members, SwiftContext);
8706+
converter.importMirroredProtocolMembers(objcContainer, DC, protos, members);
87088707
}
87098708

87108709
void ClangImporter::Implementation::loadAllConformances(

lib/ClangImporter/ImporterImpl.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
492492
/// Keep track of initializer declarations that correspond to
493493
/// imported methods.
494494
llvm::DenseMap<
495-
std::tuple<const clang::ObjCMethodDecl *, DeclContext *, Version>,
495+
std::tuple<const clang::ObjCMethodDecl *, const DeclContext *, Version>,
496496
ConstructorDecl *> Constructors;
497497

498498
/// Keep track of all initializers that have been imported into a
@@ -812,6 +812,10 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
812812
Decl *importMirroredDecl(const clang::NamedDecl *decl, DeclContext *dc,
813813
Version version, ProtocolDecl *proto);
814814

815+
void importInheritedConstructors(const clang::ObjCInterfaceDecl *curObjCClass,
816+
const ClassDecl *classDecl,
817+
SmallVectorImpl<Decl *> &newMembers);
818+
815819
/// Utility function for building simple generic signatures.
816820
GenericSignature buildGenericSignature(GenericParamList *genericParams,
817821
DeclContext *dc);

test/ClangImporter/attr-swift_name.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %empty-directory(%t.mcp)
2-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -I %S/Inputs/custom-modules -Xcc -w -typecheck %s -module-cache-path %t.mcp 2>&1 | %FileCheck %s
2+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -I %S/Inputs/custom-modules -Xcc -w -typecheck %s -module-cache-path %t.mcp -disable-named-lazy-member-loading 2>&1 | %FileCheck %s
33

44
// REQUIRES: objc_interop
55

test/NameBinding/Inputs/NamedLazyMembers/NamedLazyMembers.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
// Don't conform to the protocol; that loads all protocol members.
2727
@interface SimpleDoer
2828

29+
- (instancetype)initWithValue: (int)value;
30+
2931
// These are names we're hoping don't interfere with Doer, above.
3032
+ (SimpleDoer*)Doer;
3133
+ (SimpleDoer*)DoerOfNoWork;
@@ -107,4 +109,14 @@
107109
@interface SimpleDoerSubclass : SimpleDoer
108110
- (void)simplyDoSomeWorkWithSpeed:(int)s thoroughness:(int)t
109111
NS_SWIFT_NAME(simplyDoVeryImportantWork(speed:thoroughness:));
112+
113+
- (void)exuberantlyGoForWalk;
114+
- (void)exuberantlyTakeNap;
115+
- (void)exuberantlyEatMeal;
116+
- (void)exuberantlyTidyHome;
117+
- (void)exuberantlyCallFamily;
118+
- (void)exuberantlySingSong;
119+
- (void)exuberantlyReadBook;
120+
- (void)exuberantlyAttendLecture;
121+
- (void)exuberantlyWriteLetter;
110122
@end

test/NameBinding/named_lazy_member_loading_objc_interface.swift

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,23 @@
88
// Check that named-lazy-member-loading reduces the number of Decls deserialized
99
// RUN: %target-swift-frontend -typecheck -I %S/Inputs/NamedLazyMembers -disable-named-lazy-member-loading -stats-output-dir %t/stats-pre -primary-file %s %S/Inputs/NamedLazyMembers/NamedLazyMembersExt.swift
1010
// RUN: %target-swift-frontend -typecheck -I %S/Inputs/NamedLazyMembers -stats-output-dir %t/stats-post -primary-file %s %S/Inputs/NamedLazyMembers/NamedLazyMembersExt.swift
11-
// RUN: %{python} %utils/process-stats-dir.py --evaluate-delta 'NumTotalClangImportedEntities <= -1' %t/stats-pre %t/stats-post
11+
// RUN: %{python} %utils/process-stats-dir.py --evaluate-delta 'NumTotalClangImportedEntities <= -10' %t/stats-pre %t/stats-post
1212

1313
import NamedLazyMembers
1414

15-
public func bar(d: SimpleDoerSubclass) {
16-
let _ = d.simplyDoVeryImportantWork(speed: 10, motivation: 42)
15+
public func bar() {
16+
let d = SimpleDoerSubclass(value: 123)!
17+
let _ = d.simplyDoVeryImportantWork(speed: 10, motivation: 42)
1718
}
1819

19-
public func foo(d: SimpleDoer) {
20+
public func foo() {
21+
let d = SimpleDoer(value: 123)!
2022
let _ = d.simplyDoSomeWork()
2123
let _ = d.simplyDoSomeWork(withSpeed:10)
2224
let _ = d.simplyDoVeryImportantWork(speed:10, thoroughness:12)
2325
let _ = d.simplyDoSomeWorkWithSpeed(speed:10, levelOfAlacrity:12)
2426
}
27+
28+
// Make sure that simply subclassing an imported subclass doesn't page in all
29+
// members.
30+
class MostDoerSubclass : SimpleDoerSubclass {}

0 commit comments

Comments
 (0)