Skip to content

Commit 7b56977

Browse files
committed
[Type checker] Consistently mark used protocol conformances as "used".
Keep track of the protocol conformances required to form a particular solution. At the point where we apply a solution, mark each of those conformances as "used" so we're sure they are complete for later phases (SILGen, SIL optimizer, IRGen). This general mechanism makes sure we don't miss any cases in CSApply, such as the multi-case illustrated in the new test where CSApply doesn't form any AST notes describing the type erasure in a function conversion, so it otherwise wouldn't see the conformance to mark it "used". Pavel went most of the way down this path to track conformances last month for unrelated reasons (that didn't really pan out). Resurrect his work to track conformances, but only use them to mark as "used". Fixes rdar://problem/32111710.
1 parent 3781877 commit 7b56977

File tree

6 files changed

+57
-54
lines changed

6 files changed

+57
-54
lines changed

lib/Sema/CSApply.cpp

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7513,38 +7513,9 @@ Expr *ConstraintSystem::applySolution(Solution &solution, Expr *expr,
75137513
return nullptr;
75147514
}
75157515

7516-
for (auto &e : solution.Conformances) {
7517-
const auto &conformance = e.second;
7518-
7519-
auto anchor = expr;
7520-
if (auto *locator = e.first)
7521-
anchor = locator->getAnchor();
7522-
7523-
if (conformance.isAbstract())
7524-
continue;
7525-
7526-
auto *concrete = conformance.getConcrete();
7527-
// If conformance check is not yet complete let's re-check using 'Used'
7528-
// to require conformance check to happen.
7529-
if (concrete->getState() != ProtocolConformanceState::Complete) {
7530-
if (auto conformance = TC.conformsToProtocol(
7531-
concrete->getType(), concrete->getProtocol(), DC,
7532-
ConformanceCheckFlags::InExpression |
7533-
ConformanceCheckFlags::Used)) {
7534-
if (conformance->isAbstract())
7535-
continue;
7536-
7537-
concrete = conformance->getConcrete();
7538-
}
7539-
}
7540-
7541-
if (concrete->isComplete() && concrete->isInvalid()) {
7542-
TC.diagnose(anchor->getLoc(), diag::type_does_not_conform,
7543-
concrete->getType(),
7544-
concrete->getProtocol()->getDeclaredType());
7545-
return nullptr;
7546-
}
7547-
}
7516+
// Mark any normal conformances used in this solution as "used".
7517+
for (auto &e : solution.Conformances)
7518+
TC.markConformanceUsed(e.second, DC);
75487519

75497520
ExprRewriter rewriter(*this, solution, suppressDiagnostics, skipClosures);
75507521
ExprWalker walker(rewriter);

lib/Sema/CSSimplify.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2473,19 +2473,22 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
24732473
// separately.
24742474
switch (kind) {
24752475
case ConstraintKind::SelfObjectOfProtocol:
2476-
if (TC.containsProtocol(type, protocol, DC,
2477-
ConformanceCheckFlags::InExpression))
2476+
if (auto conformance =
2477+
TC.containsProtocol(type, protocol, DC,
2478+
ConformanceCheckFlags::InExpression)) {
2479+
CheckedConformances.push_back({getConstraintLocator(locator),
2480+
*conformance});
24782481
return SolutionKind::Solved;
2482+
}
24792483
break;
24802484
case ConstraintKind::ConformsTo:
24812485
case ConstraintKind::LiteralConformsTo: {
24822486
// Check whether this type conforms to the protocol.
2483-
auto conformance = TC.conformsToProtocol(
2484-
type, protocol, DC, ConformanceCheckFlags::InExpression);
2485-
2486-
if (conformance) {
2487-
CheckedConformances.push_back(
2488-
{getConstraintLocator(locator), std::move(*conformance)});
2487+
if (auto conformance =
2488+
TC.conformsToProtocol(type, protocol, DC,
2489+
ConformanceCheckFlags::InExpression)) {
2490+
CheckedConformances.push_back({getConstraintLocator(locator),
2491+
*conformance});
24892492
return SolutionKind::Solved;
24902493
}
24912494
break;

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5471,20 +5471,8 @@ Optional<ProtocolConformanceRef> TypeChecker::conformsToProtocol(
54715471
}
54725472

54735473
// If we're using this conformance, note that.
5474-
if (options.contains(ConformanceCheckFlags::Used) &&
5475-
lookupResult->isConcrete()) {
5476-
auto concrete = lookupResult->getConcrete();
5477-
auto normalConf = concrete->getRootNormalConformance();
5478-
5479-
// If the conformance is incomplete, queue it for completion.
5480-
if (normalConf->isIncomplete())
5481-
UsedConformances.insert(normalConf);
5482-
5483-
// Record the usage of this conformance in the enclosing source
5484-
// file.
5485-
if (auto sf = DC->getParentSourceFile()) {
5486-
sf->addUsedConformance(normalConf);
5487-
}
5474+
if (options.contains(ConformanceCheckFlags::Used)) {
5475+
markConformanceUsed(*lookupResult, DC);
54885476
}
54895477

54905478
// When requested, print the conformance access path used to find this
@@ -5547,6 +5535,24 @@ TypeChecker::conformsToProtocol(Type T, ProtocolDecl *Proto, DeclContext *DC,
55475535
: ConformsToProtocolResult::failure();
55485536
}
55495537

5538+
void TypeChecker::markConformanceUsed(ProtocolConformanceRef conformance,
5539+
DeclContext *dc) {
5540+
if (conformance.isAbstract()) return;
5541+
5542+
auto normalConformance =
5543+
conformance.getConcrete()->getRootNormalConformance();
5544+
5545+
if (normalConformance->isComplete()) return;
5546+
5547+
UsedConformances.insert(normalConformance);
5548+
5549+
// Record the usage of this conformance in the enclosing source
5550+
// file.
5551+
if (auto sf = dc->getParentSourceFile()) {
5552+
sf->addUsedConformance(normalConformance);
5553+
}
5554+
}
5555+
55505556
Optional<ProtocolConformanceRef>
55515557
TypeChecker::LookUpConformance::operator()(
55525558
CanType dependentType,

lib/Sema/TypeChecker.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,6 +1854,11 @@ class TypeChecker final : public LazyResolver {
18541854
ConformanceCheckOptions options, SourceLoc ComplainLoc,
18551855
UnsatisfiedDependency *unsatisfiedDependency);
18561856

1857+
/// Mark the given protocol conformance as "used" from the given declaration
1858+
/// context.
1859+
void markConformanceUsed(ProtocolConformanceRef conformance,
1860+
DeclContext *dc);
1861+
18571862
/// Functor class suitable for use as a \c LookupConformanceFn to look up a
18581863
/// conformance through a particular declaration context using the given
18591864
/// type checker.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
protocol Super {}
2+
protocol P : Super { }
3+
4+
enum E {}
5+
6+
extension E : P { }
7+
8+
enum E2 {
9+
case Filter(P)
10+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir -primary-file %s %S/Inputs/conformance_multifile_1.swift | %FileCheck %s
2+
3+
func g<U>(_ f : (E) throws -> (U)) {}
4+
5+
// CHECK: _T021conformance_multifile1tyyF
6+
func t() {
7+
g(E2.Filter)
8+
}

0 commit comments

Comments
 (0)