Skip to content

Commit fdecd00

Browse files
authored
Merge pull request #26031 from slavapestov/storage-validation-cleanup
Storage validation cleanup
2 parents 6feb540 + ecc9e32 commit fdecd00

File tree

6 files changed

+112
-106
lines changed

6 files changed

+112
-106
lines changed

lib/AST/ASTVerifier.cpp

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2471,44 +2471,48 @@ class Verifier : public ASTWalker {
24712471
Out << "property getter has parameters\n";
24722472
abort();
24732473
}
2474-
Type getterResultType = getter->getResultInterfaceType();
2475-
getterResultType =
2476-
var->getDeclContext()->mapTypeIntoContext(getterResultType);
2477-
if (!getterResultType->isEqual(typeForAccessors)) {
2478-
Out << "property and getter have mismatched types: '";
2479-
typeForAccessors.print(Out);
2480-
Out << "' vs. '";
2481-
getterResultType.print(Out);
2482-
Out << "'\n";
2483-
abort();
2474+
if (getter->hasInterfaceType()) {
2475+
Type getterResultType = getter->getResultInterfaceType();
2476+
getterResultType =
2477+
var->getDeclContext()->mapTypeIntoContext(getterResultType);
2478+
if (!getterResultType->isEqual(typeForAccessors)) {
2479+
Out << "property and getter have mismatched types: '";
2480+
typeForAccessors.print(Out);
2481+
Out << "' vs. '";
2482+
getterResultType.print(Out);
2483+
Out << "'\n";
2484+
abort();
2485+
}
24842486
}
24852487
}
24862488
}
24872489

24882490
if (const FuncDecl *setter = var->getSetter()) {
2489-
if (!setter->getResultInterfaceType()->isVoid()) {
2490-
Out << "property setter has non-Void result type\n";
2491-
abort();
2492-
}
2493-
if (setter->getParameters()->size() == 0) {
2494-
Out << "property setter has no parameters\n";
2495-
abort();
2496-
}
2497-
if (setter->getParameters()->size() != 1) {
2498-
Out << "property setter has 2+ parameters\n";
2499-
abort();
2500-
}
2501-
const ParamDecl *param = setter->getParameters()->get(0);
2502-
Type paramType = param->getInterfaceType();
2503-
if (!var->getDeclContext()->contextHasLazyGenericEnvironment()) {
2504-
paramType = var->getDeclContext()->mapTypeIntoContext(paramType);
2505-
if (!paramType->isEqual(typeForAccessors)) {
2506-
Out << "property and setter param have mismatched types:\n";
2507-
typeForAccessors.dump(Out, 2);
2508-
Out << "vs.\n";
2509-
paramType.dump(Out, 2);
2491+
if (setter->hasInterfaceType()) {
2492+
if (!setter->getResultInterfaceType()->isVoid()) {
2493+
Out << "property setter has non-Void result type\n";
2494+
abort();
2495+
}
2496+
if (setter->getParameters()->size() == 0) {
2497+
Out << "property setter has no parameters\n";
25102498
abort();
25112499
}
2500+
if (setter->getParameters()->size() != 1) {
2501+
Out << "property setter has 2+ parameters\n";
2502+
abort();
2503+
}
2504+
const ParamDecl *param = setter->getParameters()->get(0);
2505+
Type paramType = param->getInterfaceType();
2506+
if (!var->getDeclContext()->contextHasLazyGenericEnvironment()) {
2507+
paramType = var->getDeclContext()->mapTypeIntoContext(paramType);
2508+
if (!paramType->isEqual(typeForAccessors)) {
2509+
Out << "property and setter param have mismatched types:\n";
2510+
typeForAccessors.dump(Out, 2);
2511+
Out << "vs.\n";
2512+
paramType.dump(Out, 2);
2513+
abort();
2514+
}
2515+
}
25122516
}
25132517
}
25142518

@@ -3010,6 +3014,16 @@ class Verifier : public ASTWalker {
30103014
void verifyChecked(AbstractFunctionDecl *AFD) {
30113015
PrettyStackTraceDecl debugStack("verifying AbstractFunctionDecl", AFD);
30123016

3017+
if (!AFD->hasValidSignature()) {
3018+
if (isa<AccessorDecl>(AFD) && AFD->isImplicit())
3019+
return;
3020+
3021+
Out << "All functions except implicit accessors should be "
3022+
"validated by now\n";
3023+
AFD->dump(Out);
3024+
abort();
3025+
}
3026+
30133027
// If this function is generic or is within a generic context, it should
30143028
// have an interface type.
30153029
if (AFD->isGenericContext() !=

lib/AST/Decl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2701,7 +2701,8 @@ bool ValueDecl::canInferObjCFromRequirement(ValueDecl *requirement) {
27012701
// If there is already an @objc attribute with an explicit name, we
27022702
// can't infer a name (it's already there).
27032703
if (auto objcAttr = getAttrs().getAttribute<ObjCAttr>()) {
2704-
if (!objcAttr->isNameImplicit()) return false;
2704+
if (objcAttr->hasName() && !objcAttr->isNameImplicit())
2705+
return false;
27052706
}
27062707

27072708
// If the nominal type doesn't conform to the protocol at all, we

lib/SILGen/SILGenType.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "swift/AST/ASTMangler.h"
2525
#include "swift/AST/GenericEnvironment.h"
2626
#include "swift/AST/ProtocolConformance.h"
27+
#include "swift/AST/PrettyStackTrace.h"
2728
#include "swift/AST/SubstitutionMap.h"
2829
#include "swift/AST/TypeMemberVisitor.h"
2930
#include "swift/SIL/FormalLinkage.h"
@@ -410,6 +411,10 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
410411
if (!Conformance)
411412
return nullptr;
412413

414+
PrettyStackTraceConformance trace(SGM.getASTContext(),
415+
"generating SIL witness table",
416+
Conformance);
417+
413418
auto *proto = Conformance->getProtocol();
414419
visitProtocolDecl(proto);
415420

@@ -773,6 +778,10 @@ class SILGenSelfConformanceWitnessTable
773778
}
774779

775780
void emit() {
781+
PrettyStackTraceConformance trace(SGM.getASTContext(),
782+
"generating SIL witness table",
783+
conformance);
784+
776785
// Add entries for all the requirements.
777786
visitProtocolDecl(conformance->getProtocol());
778787

lib/Sema/CodeSynthesis.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,6 +1404,10 @@ void TypeChecker::synthesizeWitnessAccessorsForStorage(
14041404
AbstractStorageDecl *storage) {
14051405
bool addedAccessor = false;
14061406

1407+
// Make sure the protocol requirement itself has the right accessors.
1408+
// FIXME: This should be a request kicked off by SILGen.
1409+
DeclsToFinalize.insert(requirement);
1410+
14071411
requirement->visitExpectedOpaqueAccessors([&](AccessorKind kind) {
14081412
// If the accessor already exists, we have nothing to do.
14091413
if (storage->getAccessor(kind))
@@ -1708,6 +1712,10 @@ LazyStoragePropertyRequest::evaluate(Evaluator &evaluator,
17081712
NameBuf += "$__lazy_storage_$_";
17091713
NameBuf += VD->getName().str();
17101714
auto StorageName = Context.getIdentifier(NameBuf);
1715+
1716+
if (!VD->hasInterfaceType())
1717+
Context.getLazyResolver()->resolveDeclSignature(VD);
1718+
17111719
auto StorageTy = OptionalType::get(VD->getType());
17121720
auto StorageInterfaceTy = OptionalType::get(VD->getInterfaceType());
17131721

lib/Sema/TypeCheckDecl.cpp

Lines changed: 47 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2153,35 +2153,6 @@ OpaqueReadOwnershipRequest::evaluate(Evaluator &evaluator,
21532153
: OpaqueReadOwnership::Owned);
21542154
}
21552155

2156-
static void validateAbstractStorageDecl(TypeChecker &TC,
2157-
AbstractStorageDecl *storage) {
2158-
if (storage->getOpaqueResultTypeDecl()) {
2159-
if (auto sf = storage->getInnermostDeclContext()->getParentSourceFile()) {
2160-
sf->markDeclWithOpaqueResultTypeAsValidated(storage);
2161-
}
2162-
}
2163-
2164-
// Everything else about the accessors can wait until finalization.
2165-
// This will validate all the accessors.
2166-
TC.DeclsToFinalize.insert(storage);
2167-
}
2168-
2169-
static void finalizeAbstractStorageDecl(TypeChecker &TC,
2170-
AbstractStorageDecl *storage) {
2171-
TC.validateDecl(storage);
2172-
2173-
// Add any mandatory accessors now.
2174-
maybeAddAccessorsToStorage(storage);
2175-
2176-
for (auto accessor : storage->getAllAccessors()) {
2177-
// Are there accessors we can safely ignore here, like maybe observers?
2178-
TC.validateDecl(accessor);
2179-
2180-
// Finalize the accessors as well.
2181-
TC.DeclsToFinalize.insert(accessor);
2182-
}
2183-
}
2184-
21852156
/// Check the requirements in the where clause of the given \c source
21862157
/// to ensure that they don't introduce additional 'Self' requirements.
21872158
static void checkProtocolSelfRequirements(ProtocolDecl *proto,
@@ -2255,6 +2226,18 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
22552226
if (auto VD = dyn_cast<ValueDecl>(decl)) {
22562227
checkRedeclaration(TC, VD);
22572228

2229+
// Force some requests, which can produce diagnostics.
2230+
2231+
// Compute access level.
2232+
(void) VD->getFormalAccess();
2233+
2234+
// Compute overrides.
2235+
(void) VD->getOverriddenDecls();
2236+
2237+
// Check whether the member is @objc or dynamic.
2238+
(void) VD->isObjC();
2239+
(void) VD->isDynamic();
2240+
22582241
// Make sure we finalize this declaration.
22592242
TC.DeclsToFinalize.insert(VD);
22602243

@@ -2974,6 +2957,24 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
29742957
TC.addImplicitConstructors(CD);
29752958
CD->addImplicitDestructor();
29762959

2960+
// Compute @objc for each superclass member, to catch selector
2961+
// conflicts resulting from unintended overrides.
2962+
//
2963+
// FIXME: This should be a request so we can measure how much work
2964+
// we're doing here.
2965+
CD->walkSuperclasses(
2966+
[&](ClassDecl *superclass) {
2967+
for (auto *member : superclass->getMembers()) {
2968+
if (auto *vd = dyn_cast<ValueDecl>(member)) {
2969+
if (vd->isPotentiallyOverridable()) {
2970+
(void) vd->isObjC();
2971+
}
2972+
}
2973+
}
2974+
2975+
return TypeWalker::Action::Continue;
2976+
});
2977+
29772978
if (auto superclassTy = CD->getSuperclass()) {
29782979
ClassDecl *Super = superclassTy->getClassOrBoundGenericClass();
29792980

@@ -3961,8 +3962,11 @@ void TypeChecker::validateDecl(ValueDecl *D) {
39613962
checkDeclAttributesEarly(VD);
39623963
validateAttributes(*this, VD);
39633964

3964-
// Perform accessor-related validation.
3965-
validateAbstractStorageDecl(*this, VD);
3965+
if (VD->getOpaqueResultTypeDecl()) {
3966+
if (auto SF = VD->getInnermostDeclContext()->getParentSourceFile()) {
3967+
SF->markDeclWithOpaqueResultTypeAsValidated(VD);
3968+
}
3969+
}
39663970

39673971
break;
39683972
}
@@ -4240,7 +4244,11 @@ void TypeChecker::validateDecl(ValueDecl *D) {
42404244
}
42414245

42424246
// Perform accessor-related validation.
4243-
validateAbstractStorageDecl(*this, SD);
4247+
if (SD->getOpaqueResultTypeDecl()) {
4248+
if (auto SF = SD->getInnermostDeclContext()->getParentSourceFile()) {
4249+
SF->markDeclWithOpaqueResultTypeAsValidated(SD);
4250+
}
4251+
}
42444252

42454253
break;
42464254
}
@@ -4423,29 +4431,9 @@ void TypeChecker::requestMemberLayout(ValueDecl *member) {
44234431
if (auto *protocolDecl = dyn_cast<ProtocolDecl>(dc))
44244432
requestNominalLayout(protocolDecl);
44254433

4426-
if (auto ext = dyn_cast<ExtensionDecl>(dc)) {
4427-
if (ext->getSelfClassDecl()) {
4428-
// Finalize members of class extensions, to ensure we compute their
4429-
// @objc and dynamic state.
4430-
DeclsToFinalize.insert(member);
4431-
}
4432-
}
4433-
44344434
// If this represents (abstract) storage, form the appropriate accessors.
4435-
if (auto storage = dyn_cast<AbstractStorageDecl>(member)) {
4436-
validateAbstractStorageDecl(*this, storage);
4437-
4438-
// Request layout of the accessors for an @objc declaration.
4439-
// We can't delay validation of getters and setters on @objc properties,
4440-
// because if they never get validated at all then conformance checkers
4441-
// will complain about selector mismatches.
4442-
if (storage->isObjC()) {
4443-
maybeAddAccessorsToStorage(storage);
4444-
for (auto accessor : storage->getAllAccessors()) {
4445-
requestMemberLayout(accessor);
4446-
}
4447-
}
4448-
}
4435+
if (auto storage = dyn_cast<AbstractStorageDecl>(member))
4436+
DeclsToFinalize.insert(storage);
44494437
}
44504438

44514439
void TypeChecker::requestNominalLayout(NominalTypeDecl *nominalDecl) {
@@ -4485,20 +4473,19 @@ static void finalizeType(TypeChecker &TC, NominalTypeDecl *nominal) {
44854473

44864474
TC.DeclsToFinalize.insert(VD);
44874475

4488-
// The only thing left to do is synthesize storage for lazy variables.
4476+
// The only thing left to do is synthesize storage for lazy variables
4477+
// and property wrappers.
44894478
auto *prop = dyn_cast<VarDecl>(D);
44904479
if (!prop)
44914480
continue;
44924481

44934482
if (prop->getAttrs().hasAttribute<LazyAttr>() && !prop->isStatic() &&
44944483
(!prop->getGetter() || !prop->getGetter()->hasBody())) {
4495-
finalizeAbstractStorageDecl(TC, prop);
44964484
(void) prop->getLazyStorageProperty();
44974485
}
44984486

44994487
// Ensure that we create the backing variable for a wrapped property.
45004488
if (prop->hasAttachedPropertyWrapper()) {
4501-
finalizeAbstractStorageDecl(TC, prop);
45024489
(void) prop->getPropertyWrapperBackingProperty();
45034490
}
45044491
}
@@ -4530,12 +4517,9 @@ static void finalizeType(TypeChecker &TC, NominalTypeDecl *nominal) {
45304517
forceConformance(TC.Context.getProtocol(KnownProtocolKind::Hashable));
45314518
}
45324519

4533-
// validateDeclForNameLookup will not trigger an immediate full
4534-
// validation of protocols, but clients will assume that things
4535-
// like the requirement signature have been set.
45364520
if (auto PD = dyn_cast<ProtocolDecl>(nominal)) {
4537-
(void)PD->getInheritedProtocols();
4538-
TC.validateDecl(PD);
4521+
for (auto *inherited : PD->getInheritedProtocols())
4522+
TC.requestNominalLayout(inherited);
45394523
}
45404524
}
45414525

@@ -4548,18 +4532,8 @@ void TypeChecker::finalizeDecl(ValueDecl *decl) {
45484532
if (auto nominal = dyn_cast<NominalTypeDecl>(decl)) {
45494533
finalizeType(*this, nominal);
45504534
} else if (auto storage = dyn_cast<AbstractStorageDecl>(decl)) {
4551-
finalizeAbstractStorageDecl(*this, storage);
4535+
maybeAddAccessorsToStorage(storage);
45524536
}
4553-
4554-
// Compute access level.
4555-
(void)decl->getFormalAccess();
4556-
4557-
// Compute overrides.
4558-
(void)decl->getOverriddenDecls();
4559-
4560-
// Check whether the member is @objc or dynamic.
4561-
(void)decl->isObjC();
4562-
(void)decl->isDynamic();
45634537
}
45644538

45654539
/// Determine whether this is a "pass-through" typealias, which has the

test/decl/protocol/conforms/near_miss_objc.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
class C1a : P1 {
1111
@objc func doSomething(a: Int, c: Double) { }
1212
// expected-warning@-1{{instance method 'doSomething(a:c:)' nearly matches optional requirement 'doSomething(a:b:)' of protocol 'P1'}}
13-
// expected-note@-2{{rename to 'doSomething(a:b:)' to satisfy this requirement}}{{34-34=b }}{{8-8=(doSomethingWithA:b:)}} {{34-34=b }}
13+
// expected-note@-2{{rename to 'doSomething(a:b:)' to satisfy this requirement}}{{34-34=b }}
1414
// expected-note@-3{{move 'doSomething(a:c:)' to an extension to silence this warning}}
1515
// expected-note@-4{{make 'doSomething(a:c:)' private to silence this warning}}{{9-9=private }}
1616
}

0 commit comments

Comments
 (0)