Skip to content

Commit dfc8d5a

Browse files
committed
[Sema/SILGen] Track per-source-file "used" conformances to reference in SILGen
Sema was dutifully tracking conformances that were "used" as part of type checking, so it could make sure that those conformances got completed for SILGen to use. However, this information never actually made it to SILGen, which included its own (more conservative, not broad enough) heuristics for finding "used" conformances. Teach Sema to record conformances within the appropriate source file, and have SILGen reference the conformances when it emits SIL for the source file.
1 parent 197875a commit dfc8d5a

File tree

14 files changed

+106
-15
lines changed

14 files changed

+106
-15
lines changed

include/swift/AST/Module.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "swift/Basic/STLExtras.h"
2828
#include "llvm/ADT/ArrayRef.h"
2929
#include "llvm/ADT/DenseSet.h"
30+
#include "llvm/ADT/SetVector.h"
3031
#include "llvm/ADT/SmallSet.h"
3132
#include "llvm/ADT/SmallVector.h"
3233
#include "llvm/ADT/StringMap.h"
@@ -929,6 +930,10 @@ class SourceFile final : public FileUnit {
929930
/// May be -1, to indicate no association with a buffer.
930931
int BufferID;
931932

933+
/// The list of protocol conformances that were "used" within this
934+
/// source file.
935+
llvm::SetVector<NormalProtocolConformance *> UsedConformances;
936+
932937
friend ASTContext;
933938
friend Impl;
934939

@@ -1028,6 +1033,17 @@ class SourceFile final : public FileUnit {
10281033

10291034
virtual bool walk(ASTWalker &walker) override;
10301035

1036+
/// Note that the given conformance was used by this source file.
1037+
void addUsedConformance(NormalProtocolConformance *conformance) {
1038+
UsedConformances.insert(conformance);
1039+
}
1040+
1041+
/// Retrieve the set of conformances that were used in this source
1042+
/// file.
1043+
ArrayRef<NormalProtocolConformance *> getUsedConformances() const {
1044+
return UsedConformances.getArrayRef();
1045+
}
1046+
10311047
/// @{
10321048

10331049
/// Look up the given operator in this file.

include/swift/AST/TypeAlignments.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ namespace swift {
3434
class DeclContext;
3535
class Expr;
3636
class GenericTypeParamDecl;
37+
class NormalProtocolConformance;
3738
class OperatorDecl;
3839
class ProtocolDecl;
3940
class ProtocolConformance;
@@ -91,6 +92,8 @@ LLVM_DECLARE_TYPE_ALIGNMENT(swift::ASTContext, 2);
9192
LLVM_DECLARE_TYPE_ALIGNMENT(swift::DeclContext, swift::DeclContextAlignInBits)
9293
LLVM_DECLARE_TYPE_ALIGNMENT(swift::Expr, swift::ExprAlignInBits)
9394
LLVM_DECLARE_TYPE_ALIGNMENT(swift::ProtocolConformance, swift::DeclAlignInBits)
95+
LLVM_DECLARE_TYPE_ALIGNMENT(swift::NormalProtocolConformance,
96+
swift::DeclAlignInBits)
9497

9598
static_assert(llvm::AlignOf<void*>::Alignment >= 2,
9699
"pointer alignment is too small");

lib/ClangImporter/ImportDecl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,6 +1333,8 @@ namespace {
13331333
decl->getUnderlyingType(), ImportTypeKind::Value,
13341334
isInSystemModule(dc), decl->getUnderlyingType()->isBlockPointerType(),
13351335
OTK_None);
1336+
if (auto objTy = storedUnderlyingType->getAnyOptionalObjectType())
1337+
storedUnderlyingType = objTy;
13361338

13371339
// If the type is Unmanaged, that is it is not CF ARC audited,
13381340
// we will store the underlying type and leave it up to the use site
@@ -1349,6 +1351,9 @@ namespace {
13491351
decl->getUnderlyingType(), ImportTypeKind::Property,
13501352
isInSystemModule(dc), decl->getUnderlyingType()->isBlockPointerType(),
13511353
OTK_None);
1354+
if (auto objTy =
1355+
computedPropertyUnderlyingType->getAnyOptionalObjectType())
1356+
computedPropertyUnderlyingType = objTy;
13521357

13531358
bool isBridged =
13541359
!storedUnderlyingType->isEqual(computedPropertyUnderlyingType);

lib/SILGen/SILGen.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,10 @@ void SILGenModule::emitSourceFile(SourceFile *sf, unsigned startElem) {
13091309
SourceFileScope scope(*this, sf);
13101310
for (Decl *D : llvm::makeArrayRef(sf->Decls).slice(startElem))
13111311
visit(D);
1312+
1313+
// Mark any conformances as "used".
1314+
for (auto conformance : sf->getUsedConformances())
1315+
useConformance(ProtocolConformanceRef(conformance));
13121316
}
13131317

13141318
//===----------------------------------------------------------------------===//

lib/SILGen/SILGenFunction.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ SILGenFunction::SILGenFunction(SILGenModule &SGM, SILFunction &F)
3939
Cleanups(*this)
4040
{
4141
B.setCurrentDebugScope(F.getDebugScope());
42+
checkForImportedUsedConformances(F.getLoweredType().getSwiftType());
4243
}
4344

4445
/// SILGenFunction destructor - called after the entire function's AST has been

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4063,13 +4063,21 @@ bool TypeChecker::conformsToProtocol(Type T, ProtocolDecl *Proto,
40634063
recordDependency(nullptr);
40644064
}
40654065

4066-
// If we're using this conformance and it is incomplete, queue it for
4067-
// completion.
4066+
// If we're using this conformance, note that.
40684067
if (options.contains(ConformanceCheckFlags::Used) &&
4069-
lookupResult->isConcrete() &&
4070-
lookupResult->getConcrete()->isIncomplete()) {
4071-
auto normalConf = lookupResult->getConcrete()->getRootNormalConformance();
4072-
UsedConformances.insert(normalConf);
4068+
lookupResult->isConcrete()) {
4069+
auto concrete = lookupResult->getConcrete();
4070+
auto normalConf = concrete->getRootNormalConformance();
4071+
4072+
// If the conformance is incomplete, queue it for completion.
4073+
if (normalConf->isIncomplete())
4074+
UsedConformances.insert(normalConf);
4075+
4076+
// Record the usage of this conformance in the enclosing source
4077+
// file.
4078+
if (auto sf = DC->getParentSourceFile()) {
4079+
sf->addUsedConformance(normalConf);
4080+
}
40734081
}
40744082
return true;
40754083
}
@@ -4107,6 +4115,25 @@ void TypeChecker::useObjectiveCBridgeableConformances(DeclContext *dc,
41074115
type.walk(Walker(*this, dc, proto));
41084116
}
41094117

4118+
void TypeChecker::useObjectiveCBridgeableConformancesOfArgs(
4119+
DeclContext *dc, BoundGenericType *bound) {
4120+
auto proto = getProtocol(SourceLoc(),
4121+
KnownProtocolKind::ObjectiveCBridgeable);
4122+
if (!proto) return;
4123+
4124+
// Check whether the bound generic type itself is bridged to
4125+
// Objective-C.
4126+
ConformanceCheckOptions options = ConformanceCheckFlags::InExpression
4127+
| ConformanceCheckFlags::SuppressDependencyTracking;
4128+
if (!conformsToProtocol(bound->getDecl()->getDeclaredType(), proto, dc,
4129+
options))
4130+
return;
4131+
4132+
// Mark the conformances within the arguments.
4133+
for (auto arg : bound->getGenericArgs())
4134+
useObjectiveCBridgeableConformances(dc, arg);
4135+
}
4136+
41104137
void TypeChecker::checkConformance(NormalProtocolConformance *conformance) {
41114138
checkConformsToProtocol(*this, conformance);
41124139
}

lib/Sema/TypeCheckType.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,8 @@ Type TypeChecker::applyUnboundGenericArguments(
532532
if (checkGenericArguments(dc, loc, noteLoc, unbound, genericSig,
533533
allGenericArgs))
534534
return nullptr;
535+
536+
useObjectiveCBridgeableConformancesOfArgs(dc, BGT);
535537
}
536538

537539
return BGT;
@@ -2196,6 +2198,9 @@ Type TypeResolver::resolveArrayType(ArrayTypeRepr *repr,
21962198
if (!sliceTy)
21972199
return ErrorType::get(Context);
21982200

2201+
// Check for _ObjectiveCBridgeable conformances in the element type.
2202+
TC.useObjectiveCBridgeableConformances(DC, baseTy);
2203+
21992204
return sliceTy;
22002205
}
22012206

@@ -2221,6 +2226,11 @@ Type TypeResolver::resolveDictionaryType(DictionaryTypeRepr *repr,
22212226
return ErrorType::get(TC.Context);
22222227
}
22232228

2229+
// Check for _ObjectiveCBridgeable conformances in the key and value
2230+
// types.
2231+
TC.useObjectiveCBridgeableConformances(DC, keyTy);
2232+
TC.useObjectiveCBridgeableConformances(DC, valueTy);
2233+
22242234
return dictTy;
22252235
}
22262236

lib/Sema/TypeChecker.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,6 +1489,12 @@ class TypeChecker final : public LazyResolver {
14891489
/// Mark any _ObjectiveCBridgeable conformances in the given type as "used".
14901490
void useObjectiveCBridgeableConformances(DeclContext *dc, Type type);
14911491

1492+
/// If this bound-generic type is bridged, mark any
1493+
/// _ObjectiveCBridgeable conformances in the generic arguments of
1494+
/// the given type as "used".
1495+
void useObjectiveCBridgeableConformancesOfArgs(DeclContext *dc,
1496+
BoundGenericType *bound);
1497+
14921498
/// Derive an implicit declaration to satisfy a requirement of a derived
14931499
/// protocol conformance.
14941500
///

test/IDE/Inputs/custom-modules/Newtype.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
@import Foundation;
2+
@import CoreFoundation;
23

34
typedef NSString *__nonnull SNTErrorDomain __attribute((swift_newtype(struct)))
45
__attribute((swift_name("ErrorDomain")));
56

67
extern void SNTErrorDomainProcess(SNTErrorDomain d)
78
__attribute((swift_name("ErrorDomain.process(self:)")));
89

9-
typedef struct {} Foo;
10+
typedef struct {} Food;
1011

1112
extern const SNTErrorDomain SNTErrOne
1213
__attribute((swift_name("ErrorDomain.one")));
@@ -16,7 +17,7 @@ extern const SNTErrorDomain SNTFourErrorDomain;
1617
extern const SNTErrorDomain SNTFive
1718
__attribute((swift_name("stillAMember")));
1819
extern const SNTErrorDomain SNTElsewhere
19-
__attribute((swift_name("Foo.err")));
20+
__attribute((swift_name("Food.err")));
2021

2122
typedef NSString *__nullable SNTClosedEnum __attribute((swift_newtype(enum)))
2223
__attribute((swift_name("ClosedEnum")));

test/IDE/newtype.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@
1919
// PRINT-NEXT: static let fourErrorDomain: ErrorDomain
2020
// PRINT-NEXT: static let stillAMember: ErrorDomain
2121
// PRINT-NEXT: }
22-
// PRINT-NEXT: struct Foo {
22+
// PRINT-NEXT: struct Food {
2323
// PRINT-NEXT: init()
2424
// PRINT-NEXT: }
25-
// PRINT-NEXT: extension Foo {
25+
// PRINT-NEXT: extension Food {
2626
// PRINT-NEXT: static let err: ErrorDomain
2727
// PRINT-NEXT: }
2828
// PRINT-NEXT: struct ClosedEnum : RawRepresentable, _SwiftNewtypeWrapper, Equatable, Hashable, Comparable, _ObjectiveCBridgeable {
@@ -81,15 +81,15 @@ func tests() {
8181
let errOne = ErrorDomain.one
8282
errOne.process()
8383

84-
let fooErr = Foo.err
84+
let fooErr = Food.err
8585
fooErr.process()
86-
Foo().process() // expected-error{{value of type 'Foo' has no member 'process'}}
86+
Food().process() // expected-error{{value of type 'Food' has no member 'process'}}
8787

8888
let thirdEnum = ClosedEnum.thirdEntry!
8989
thirdEnum.process()
9090
// expected-error@-1{{value of type 'ClosedEnum' has no member 'process'}}
9191

92-
let _ = ErrorDomain(rawValue: thirdEnum.rawValue!)
92+
let _ = ErrorDomain(rawValue: thirdEnum.rawValue)
9393
let _ = ClosedEnum(rawValue: errOne.rawValue)
9494

9595
let _ = NSNotificationName.Foo

0 commit comments

Comments
 (0)