From e0cc652616254db9b97fae41fa599a373b472684 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 2 Aug 2019 13:11:59 -0400 Subject: [PATCH 1/5] AST: Replace AbstractStorageDecl::hasAnyAccessors() with hasParsedAccessors() --- include/swift/AST/Decl.h | 7 +++---- lib/AST/Decl.cpp | 7 +++++++ lib/SILGen/SILGenExpr.cpp | 2 +- lib/Sema/TypeCheckAvailability.cpp | 4 ++-- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 74ec049c0320d..78f9da4046f87 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -4565,10 +4565,9 @@ class AbstractStorageDecl : public ValueDecl { bool isSettable(const DeclContext *UseDC, const DeclRefExpr *base = nullptr) const; - /// Are there any accessors for this declaration, including implicit ones? - bool hasAnyAccessors() const { - return !getAllAccessors().empty(); - } + /// Does this storage declaration have explicitly-defined accessors + /// written in the source? + bool hasParsedAccessors() const; /// Return the ownership of values opaquely read from this storage. OpaqueReadOwnership getOpaqueReadOwnership() const; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 43d699db2e6b1..e97a51e3d246b 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2010,6 +2010,13 @@ AccessorDecl *AbstractStorageDecl::getOpaqueAccessor(AccessorKind kind) const { return getSynthesizedAccessor(kind); } +bool AbstractStorageDecl::hasParsedAccessors() const { + for (auto *accessor : getAllAccessors()) + if (!accessor->isImplicit()) + return true; + return false; +} + AccessorDecl *AbstractStorageDecl::getParsedAccessor(AccessorKind kind) const { auto *accessor = getAccessor(kind); if (accessor && !accessor->isImplicit()) diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index c143cd28eb1b7..6f263c8609e61 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -3360,7 +3360,7 @@ SILGenModule::emitKeyPathComponentForDecl(SILLocation loc, // storage. // Properties that are not public don't need property descriptors // either. - (!baseDecl->hasAnyAccessors() || + (!baseDecl->requiresOpaqueAccessors() || (!getAccessorDeclRef(getRepresentativeAccessorForKeyPath(baseDecl)) .isForeign && getAccessorDeclRef(getRepresentativeAccessorForKeyPath(baseDecl)) diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index 82fce21a28820..90dad40cd9f56 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -181,7 +181,7 @@ class TypeRefinementContextBuilder : private ASTWalker { // when we process the accessor, we can use this TRC as the // parent. if (auto *StorageDecl = dyn_cast(D)) { - if (StorageDecl->hasAnyAccessors()) { + if (StorageDecl->hasParsedAccessors()) { StorageContexts[StorageDecl] = NewTRC; } } @@ -230,7 +230,7 @@ class TypeRefinementContextBuilder : private ASTWalker { // locations and have callers of that method provide appropriate source // locations. SourceLoc BracesEnd = storageDecl->getBracesRange().End; - if (storageDecl->hasAnyAccessors() && BracesEnd.isValid()) { + if (storageDecl->hasParsedAccessors() && BracesEnd.isValid()) { return SourceRange(storageDecl->getStartLoc(), BracesEnd); } From 6c5ecb5fc9825acc856786fc7785a84dbc12f7fb Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 2 Aug 2019 14:46:06 -0400 Subject: [PATCH 2/5] AST: Introduce AbstractStorageDecl::visit{Parsed,Emitted}Accessors() --- include/swift/AST/Decl.h | 12 ++++++-- lib/AST/ASTScopeCreation.cpp | 6 ++-- lib/AST/Decl.cpp | 16 ++++++++++ lib/IDE/Refactoring.cpp | 5 ++-- lib/Index/Index.cpp | 10 +++---- lib/SILGen/SILGen.cpp | 6 ++-- lib/SILGen/SILGenDecl.cpp | 3 +- lib/SILGen/SILGenType.cpp | 12 ++++---- lib/Sema/TypeCheckAttr.cpp | 57 +++++++++++++++++++----------------- lib/Sema/TypeCheckDecl.cpp | 6 ++-- lib/TBDGen/TBDGen.cpp | 4 +-- 11 files changed, 83 insertions(+), 54 deletions(-) diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 78f9da4046f87..251b905fa7246 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -4627,13 +4627,21 @@ class AbstractStorageDecl : public ValueDecl { /// accessor was not explicitly defined by the user. AccessorDecl *getParsedAccessor(AccessorKind kind) const; - /// Visit all the opaque accessors that this storage is expected to have. + /// Visit all parsed accessors. + void visitParsedAccessors(llvm::function_ref) const; + + /// Visit all opaque accessor kinds. void visitExpectedOpaqueAccessors( llvm::function_ref) const; - /// Visit all the opaque accessors of this storage declaration. + /// Visit all opaque accessors. void visitOpaqueAccessors(llvm::function_ref) const; + /// Visit all eagerly emitted accessors. + /// + /// This is the union of the parsed and opaque sets. + void visitEmittedAccessors(llvm::function_ref) const; + void setAccessors(SourceLoc lbraceLoc, ArrayRef accessors, SourceLoc rbraceLoc); diff --git a/lib/AST/ASTScopeCreation.cpp b/lib/AST/ASTScopeCreation.cpp index f85cd54d0424c..c73592c9574f0 100644 --- a/lib/AST/ASTScopeCreation.cpp +++ b/lib/AST/ASTScopeCreation.cpp @@ -516,8 +516,8 @@ ASTScopeImpl *ScopeCreator::createScopeFor(ASTNode n, ASTScopeImpl *parent) { void ScopeCreator::addChildrenForAllExplicitAccessors(AbstractStorageDecl *asd, ASTScopeImpl *parent) { - for (auto accessor : asd->getAllAccessors()) { - if (!accessor->isImplicit() && accessor->getStartLoc().isValid()) { + asd->visitParsedAccessors([&](AccessorDecl *accessor) { + if (accessor->getStartLoc().isValid()) { // Accessors are always nested within their abstract storage // declaration. The nesting may not be immediate, because subscripts may // have intervening scopes for generics. @@ -526,7 +526,7 @@ void ScopeCreator::addChildrenForAllExplicitAccessors(AbstractStorageDecl *asd, ASTVisitorForScopeCreation().visitAbstractFunctionDecl(accessor, parent, *this); } - } + }); } #pragma mark creation helpers diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index e97a51e3d246b..5442b2f336ae6 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2025,6 +2025,22 @@ AccessorDecl *AbstractStorageDecl::getParsedAccessor(AccessorKind kind) const { return nullptr; } +void AbstractStorageDecl::visitParsedAccessors( + llvm::function_ref visit) const { + for (auto *accessor : getAllAccessors()) + if (!accessor->isImplicit()) + visit(accessor); +} + +void AbstractStorageDecl::visitEmittedAccessors( + llvm::function_ref visit) const { + visitParsedAccessors(visit); + visitOpaqueAccessors([&](AccessorDecl *accessor) { + if (accessor->isImplicit()) + visit(accessor); + }); +} + void AbstractStorageDecl::visitExpectedOpaqueAccessors( llvm::function_ref visit) const { if (!requiresOpaqueAccessors()) diff --git a/lib/IDE/Refactoring.cpp b/lib/IDE/Refactoring.cpp index 1cbdabf559006..6c5c2fe3d4e57 100644 --- a/lib/IDE/Refactoring.cpp +++ b/lib/IDE/Refactoring.cpp @@ -1618,8 +1618,9 @@ class FindAllSubDecls : public SourceEntityWalker { return false; if (auto ASD = dyn_cast(D)) { - auto accessors = ASD->getAllAccessors(); - Found.insert(accessors.begin(), accessors.end()); + ASD->visitParsedAccessors([&](AccessorDecl *accessor) { + Found.insert(accessor); + }); } return true; } diff --git a/lib/Index/Index.cpp b/lib/Index/Index.cpp index cfc5e93e6f978..41f61cfc1fa65 100644 --- a/lib/Index/Index.cpp +++ b/lib/Index/Index.cpp @@ -1103,15 +1103,13 @@ bool IndexSwiftASTWalker::report(ValueDecl *D) { // Even if we don't record a local property we still need to walk its // accessor bodies. if (auto StoreD = dyn_cast(D)) { - for (auto accessor : StoreD->getAllAccessors()) { - if (accessor->isImplicit()) - continue; + StoreD->visitParsedAccessors([&](AccessorDecl *accessor) { + if (Cancelled) + return; ManuallyVisitedAccessorStack.push_back(accessor); SourceEntityWalker::walk(cast(accessor)); ManuallyVisitedAccessorStack.pop_back(); - if (Cancelled) - return false; - } + }); } } diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 93f5b0be803b4..785b4ff7e3158 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -1328,15 +1328,15 @@ void SILGenModule::visitVarDecl(VarDecl *vd) { if (vd->hasStorage()) addGlobalVariable(vd); - for (auto *accessor : vd->getAllAccessors()) + vd->visitEmittedAccessors([&](AccessorDecl *accessor) { emitFunction(accessor); + }); tryEmitPropertyDescriptor(vd); } void SILGenModule::visitSubscriptDecl(SubscriptDecl *sd) { - for (auto *accessor : sd->getAllAccessors()) - emitFunction(accessor); + llvm_unreachable("top-level subscript?"); } bool diff --git a/lib/SILGen/SILGenDecl.cpp b/lib/SILGen/SILGenDecl.cpp index ccc09071f4f50..323636a97b831 100644 --- a/lib/SILGen/SILGenDecl.cpp +++ b/lib/SILGen/SILGenDecl.cpp @@ -1194,8 +1194,9 @@ void SILGenFunction::visitVarDecl(VarDecl *D) { // We handle emitting the variable storage when we see the pattern binding. // Emit the variable's accessors. - for (auto *accessor : D->getAllAccessors()) + D->visitEmittedAccessors([&](AccessorDecl *accessor) { SGM.emitFunction(accessor); + }); } /// Emit literals for the major, minor, and subminor components of the version diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index 045d65b6f2c37..2a51ca2d1e013 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -1050,9 +1050,9 @@ class SILGenType : public TypeMemberVisitor { } void visitAccessors(AbstractStorageDecl *asd) { - for (auto *accessor : asd->getAllAccessors()) - if (!accessor->hasForcedStaticDispatch()) - visitFuncDecl(accessor); + asd->visitEmittedAccessors([&](AccessorDecl *accessor) { + visitFuncDecl(accessor); + }); } }; @@ -1182,9 +1182,9 @@ class SILGenExtension : public TypeMemberVisitor { } void visitAccessors(AbstractStorageDecl *asd) { - for (auto *accessor : asd->getAllAccessors()) - if (!accessor->hasForcedStaticDispatch()) - visitFuncDecl(accessor); + asd->visitEmittedAccessors([&](AccessorDecl *accessor) { + visitFuncDecl(accessor); + }); } }; diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index aae1d1665b513..4e444c0c58a43 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -2140,23 +2140,24 @@ static FuncDecl *findReplacedAccessor(DeclName replacedVarName, } // Find the accessor in the replaced storage decl. - for (auto *origAccessor : origStorage->getAllAccessors()) { - TC.validateDecl(origAccessor); - if (origAccessor->getAccessorKind() != replacement->getAccessorKind()) - continue; + auto *origAccessor = origStorage->getOpaqueAccessor( + replacement->getAccessorKind()); + if (!origAccessor) + return nullptr; - if (origAccessor->isImplicit() && - !(origStorage->getReadImpl() == ReadImplKind::Stored && - origStorage->getWriteImpl() == WriteImplKind::Stored)) { - TC.diagnose(attr->getLocation(), - diag::dynamic_replacement_accessor_not_explicit, - (unsigned)origAccessor->getAccessorKind(), replacedVarName); - attr->setInvalid(); - return nullptr; - } - return origAccessor; + TC.validateDecl(origAccessor); + + if (origAccessor->isImplicit() && + !(origStorage->getReadImpl() == ReadImplKind::Stored && + origStorage->getWriteImpl() == WriteImplKind::Stored)) { + TC.diagnose(attr->getLocation(), + diag::dynamic_replacement_accessor_not_explicit, + (unsigned)origAccessor->getAccessorKind(), replacedVarName); + attr->setInvalid(); + return nullptr; } - return nullptr; + + return origAccessor; } static AbstractFunctionDecl * @@ -2298,19 +2299,19 @@ void TypeChecker::checkDynamicReplacementAttribute(ValueDecl *D) { // Collect the accessor replacement mapping if this is an abstract storage. if (auto *var = dyn_cast(D)) { - for (auto *accessor : var->getAllAccessors()) { + var->visitParsedAccessors([&](AccessorDecl *accessor) { + if (attr->isInvalid()) + return; + validateDecl(accessor); - if (accessor->isImplicit()) - continue; auto *orig = findReplacedAccessor(attr->getReplacedFunctionName(), accessor, attr, *this); - if (attr->isInvalid()) - return; if (!orig) - continue; + return; + origs.push_back(orig); replacements.push_back(accessor); - } + }); } else { // Otherwise, find the matching function. auto *fun = cast(D); @@ -2823,12 +2824,14 @@ void TypeChecker::addImplicitDynamicAttribute(Decl *D) { return; } - // Don't add dynamic if accessor is inlinable or tranparent. + // Don't add dynamic if accessor is inlinable or transparent. if (auto *asd = dyn_cast(D)) { - for (auto *accessor : asd->getAllAccessors()) { - if (!accessor->isImplicit() && shouldBlockImplicitDynamic(accessor)) - return; - } + bool blocked = false; + asd->visitParsedAccessors([&](AccessorDecl *accessor) { + blocked |= shouldBlockImplicitDynamic(accessor); + }); + if (blocked) + return; } if (auto *VD = dyn_cast(D)) { diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 388e32abe1b82..ea4bfd08e044c 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2658,8 +2658,9 @@ class DeclChecker : public DeclVisitor { TC.checkDynamicReplacementAttribute(VD); // Now check all the accessors. - for (auto *accessor : VD->getAllAccessors()) + VD->visitEmittedAccessors([&](AccessorDecl *accessor) { visit(accessor); + }); } void visitBoundVars(Pattern *P) { @@ -2880,8 +2881,9 @@ class DeclChecker : public DeclVisitor { } // Now check all the accessors. - for (auto *accessor : SD->getAllAccessors()) + SD->visitEmittedAccessors([&](AccessorDecl *accessor) { visit(accessor); + }); } void visitTypeAliasDecl(TypeAliasDecl *TAD) { diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index f51b78442c5f0..be1c1cae695f9 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -280,9 +280,9 @@ void TBDGenVisitor::visitAbstractStorageDecl(AbstractStorageDecl *ASD) { } // Explicitly look at each accessor here: see visitAccessorDecl. - for (auto accessor : ASD->getAllAccessors()) { + ASD->visitEmittedAccessors([&](AccessorDecl *accessor) { visitFuncDecl(accessor); - } + }); } void TBDGenVisitor::visitVarDecl(VarDecl *VD) { From a4bb3101ea8d5cd9ad14604dba002daa45e3d002 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 30 Jul 2019 22:28:41 -0400 Subject: [PATCH 3/5] Sema: Remove addExpectedOpaqueAccessorsToStorage() --- lib/Sema/CSApply.cpp | 1 - lib/Sema/CodeSynthesis.cpp | 8 -------- lib/Sema/CodeSynthesis.h | 3 --- lib/Sema/TypeCheckDecl.cpp | 16 ++++------------ lib/Sema/TypeCheckDeclOverride.cpp | 2 -- test/attr/attr_objc.swift | 2 +- 6 files changed, 5 insertions(+), 27 deletions(-) diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index a16ccdf9d861e..f4cc47340743b 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -4039,7 +4039,6 @@ namespace { method = func; } else if (auto var = dyn_cast(foundDecl)) { // Properties. - addExpectedOpaqueAccessorsToStorage(var); // If this isn't a property on a type, complain. if (!var->getDeclContext()->isTypeContext()) { diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index a90bdcd0bafbf..06539cc007af2 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -1293,13 +1293,6 @@ SynthesizeAccessorRequest::evaluate(Evaluator &evaluator, } } -void swift::addExpectedOpaqueAccessorsToStorage(AbstractStorageDecl *storage) { - storage->visitExpectedOpaqueAccessors([&](AccessorKind kind) { - // Force synthesis if necessary. - (void) storage->getSynthesizedAccessor(kind); - }); -} - /// Synthesize the body of a setter which just delegates to a mutable /// addressor. static std::pair @@ -1717,7 +1710,6 @@ static VarDecl *synthesizePropertyWrapperStorageWrapperProperty( property->setImplInfo(StorageImplInfo::getMutableComputed()); else property->setImplInfo(StorageImplInfo::getImmutableComputed()); - addExpectedOpaqueAccessorsToStorage(property); var->getAttrs().add( new (ctx) ProjectedValuePropertyAttr(name, SourceLoc(), SourceRange(), diff --git a/lib/Sema/CodeSynthesis.h b/lib/Sema/CodeSynthesis.h index 6b85cf048a7e5..f624c9da19d85 100644 --- a/lib/Sema/CodeSynthesis.h +++ b/lib/Sema/CodeSynthesis.h @@ -45,9 +45,6 @@ class ObjCReason; // Implemented in TypeCheckerOverride.cpp bool checkOverrides(ValueDecl *decl); -// These are implemented in CodeSynthesis.cpp. -void addExpectedOpaqueAccessorsToStorage(AbstractStorageDecl *storage); - /// Describes the kind of implicit constructor that will be /// generated. enum class ImplicitConstructorKind { diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index ea4bfd08e044c..49665bcf623fd 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -2528,12 +2528,8 @@ class DeclChecker : public DeclVisitor { // Compute these requests in case they emit diagnostics. (void) VD->isGetterMutating(); (void) VD->isSetterMutating(); - - // Retrieve the backing property of a wrapped property. (void) VD->getPropertyWrapperBackingProperty(); - - // Set up accessors, also lowering lazy and @NSManaged properties. - addExpectedOpaqueAccessorsToStorage(VD); + (void) VD->getImplInfo(); // Add the '@_hasStorage' attribute if this property is stored. if (VD->hasStorage() && !VD->getAttrs().hasAttribute()) @@ -2542,9 +2538,8 @@ class DeclChecker : public DeclVisitor { // Reject cases where this is a variable that has storage but it isn't // allowed. if (VD->hasStorage()) { - // Stored properties in protocols are diagnosed in - // addExpectedOpaqueAccessorsToStorage(), to ensure they run when a - // protocol requirement is validated but not type checked. + // Note: Stored properties in protocols are diagnosed in + // finishProtocolStorageImplInfo(). // Enums and extensions cannot have stored instance properties. // Static stored properties are allowed, with restrictions @@ -2615,8 +2610,6 @@ class DeclChecker : public DeclVisitor { TC.checkDeclAttributes(VD); - addExpectedOpaqueAccessorsToStorage(VD); - if (VD->getDeclContext()->getSelfClassDecl()) { checkDynamicSelfType(VD, VD->getValueInterfaceType()); @@ -2861,8 +2854,7 @@ class DeclChecker : public DeclVisitor { // Compute these requests in case they emit diagnostics. (void) SD->isGetterMutating(); (void) SD->isSetterMutating(); - - addExpectedOpaqueAccessorsToStorage(SD); + (void) SD->getImplInfo(); if (SD->getAttrs().hasAttribute()) { TC.checkDynamicReplacementAttribute(SD); diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index 4675c254130f9..cab0e94b5ec11 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -1879,8 +1879,6 @@ OverriddenDeclsRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const { SmallVector matches; for (auto overridden : overridingASD->getOverriddenDecls()) { auto baseASD = cast(overridden); - addExpectedOpaqueAccessorsToStorage(baseASD); - auto kind = accessor->getAccessorKind(); // If the base doesn't consider this an opaque accessor, diff --git a/test/attr/attr_objc.swift b/test/attr/attr_objc.swift index 8d5c46e7d85ef..335b9d2cdf430 100644 --- a/test/attr/attr_objc.swift +++ b/test/attr/attr_objc.swift @@ -845,7 +845,7 @@ class infer_instanceVar1 { } var observingAccessorsVar1: Int { - // CHECK: @objc @_hasStorage var observingAccessorsVar1: Int { + // CHECK: @_hasStorage @objc var observingAccessorsVar1: Int { willSet {} // CHECK-NEXT: {{^}} @objc get didSet {} From 2e3f4acfd1cbff5bbae264a816d228767e83f21d Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 6 Aug 2019 16:16:45 -0400 Subject: [PATCH 4/5] AST: Fix mangling of unvalidated declarations This is again just a temporary workaround until getInterfaceType() can kick off a request. --- lib/AST/ASTMangler.cpp | 7 +++++++ test/IRGen/Inputs/vtable_multi_file_helper.swift | 6 +++++- test/IRGen/vtable_multi_file.swift | 6 ++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 49ff01e9c5aef..bb56cc7d83d68 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -20,6 +20,7 @@ #include "swift/AST/ExistentialLayout.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/Initializer.h" +#include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/Ownership.h" #include "swift/AST/ParameterList.h" @@ -2323,6 +2324,12 @@ CanType ASTMangler::getDeclTypeForMangling( parentGenericSig = nullptr; auto &C = decl->getASTContext(); + if (!decl->hasInterfaceType() && !decl->getDeclContext()->isLocalContext()) { + if (auto *resolver = C.getLazyResolver()) { + resolver->resolveDeclSignature(const_cast(decl)); + } + } + if (!decl->hasInterfaceType() || decl->getInterfaceType()->is()) { if (isa(decl)) return CanFunctionType::get({AnyFunctionType::Param(C.TheErrorType)}, diff --git a/test/IRGen/Inputs/vtable_multi_file_helper.swift b/test/IRGen/Inputs/vtable_multi_file_helper.swift index a85e6e3dc3e7d..86c2e81755a6b 100644 --- a/test/IRGen/Inputs/vtable_multi_file_helper.swift +++ b/test/IRGen/Inputs/vtable_multi_file_helper.swift @@ -9,7 +9,7 @@ class SillySequence : Sequence, IteratorProtocol { var storedProperty: Int = 0 func makeIterator() -> SillySequence { - return sel + return self } func next() -> Int? { @@ -21,4 +21,8 @@ class Holder { func getSillySequence() -> SillySequence { return SillySequence() } +} + +class Base { + func method() {} } \ No newline at end of file diff --git a/test/IRGen/vtable_multi_file.swift b/test/IRGen/vtable_multi_file.swift index 72c03cbc9c85d..7bc50df82fd31 100644 --- a/test/IRGen/vtable_multi_file.swift +++ b/test/IRGen/vtable_multi_file.swift @@ -2,6 +2,12 @@ // REQUIRES: CPU=x86_64 +// CHECK-LABEL: @"$s17vtable_multi_file7DerivedCMf" = internal global +// CHECK-SAME: @"$s17vtable_multi_file4BaseC6methodyyF" +class Derived : Base { + func another() {} +} + func markUsed(_ t: T) {} // CHECK-LABEL: define hidden swiftcc void @"$s17vtable_multi_file36baseClassVtablesIncludeImplicitInitsyyF"() {{.*}} { From 05baaa86cc15540bbcae054598fa494ff6be0e7b Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 5 Aug 2019 15:23:20 -0400 Subject: [PATCH 5/5] AST: Slightly more efficient requiresNewVTableEntry() --- lib/AST/Decl.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 5442b2f336ae6..cd9425be16612 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -6463,13 +6463,6 @@ static bool requiresNewVTableEntry(const AbstractFunctionDecl *decl) { auto &ctx = dc->getASTContext(); - // FIXME: Remove this once getInterfaceType(), isDesignatedInit() and - // anything else that is used below has been request-ified. - if (!decl->hasInterfaceType()) { - ctx.getLazyResolver()->resolveDeclSignature( - const_cast(decl)); - } - // Initializers are not normally inherited, but required initializers can // be overridden for invocation from dynamic types, and convenience initializers // are conditionally inherited when all designated initializers are available, @@ -6494,13 +6487,6 @@ static bool requiresNewVTableEntry(const AbstractFunctionDecl *decl) { if (!base || base->hasClangNode() || base->isObjCDynamic()) return true; - // FIXME: Remove this once getInterfaceType(), isDesignatedInit() and - // anything else that is used below has been request-ified. - if (!base->hasInterfaceType()) { - ctx.getLazyResolver()->resolveDeclSignature( - const_cast(base)); - } - // As above, convenience initializers are not formally overridable in Swift // vtables, although same-named initializers are modeled as overriding for // various QoI and objc interop reasons. Even if we "override" a non-required @@ -6517,6 +6503,17 @@ static bool requiresNewVTableEntry(const AbstractFunctionDecl *decl) { if (decl->isEffectiveLinkageMoreVisibleThan(base)) return true; + // FIXME: Remove this once getInterfaceType() has been request-ified. + if (!decl->hasInterfaceType()) { + ctx.getLazyResolver()->resolveDeclSignature( + const_cast(decl)); + } + + if (!base->hasInterfaceType()) { + ctx.getLazyResolver()->resolveDeclSignature( + const_cast(base)); + } + // If the method overrides something, we only need a new entry if the // override has a more general AST type. However an abstraction // change is OK; we don't want to add a whole new vtable entry just