Skip to content

Commit 555e522

Browse files
authored
Sema: fill-protocol-stub fixits should include those missing witnesses that are handled by delayed diagnostics. (#8011)
1 parent 179424f commit 555e522

File tree

4 files changed

+80
-4
lines changed

4 files changed

+80
-4
lines changed

include/swift/AST/ASTContext.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,15 @@ class ASTContext {
682682
std::vector<DelayedConformanceDiag>
683683
takeDelayedConformanceDiags(NormalProtocolConformance *conformance);
684684

685+
/// Add delayed missing witnesses for the given normal protocol conformance.
686+
void addDelayedMissingWitnesses(NormalProtocolConformance *conformance,
687+
ArrayRef<ValueDecl*> witnesses);
688+
689+
/// Retrieve the delayed missing witnesses for the given normal protocol
690+
/// conformance.
691+
std::vector<ValueDecl*>
692+
takeDelayedMissingWitnesses(NormalProtocolConformance *conformance);
693+
685694
/// \brief Produce a specialized conformance, which takes a generic
686695
/// conformance and substitutions written in terms of the generic
687696
/// conformance's signature.

lib/AST/ASTContext.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,12 @@ struct ASTContext::Implementation {
206206
std::vector<ASTContext::DelayedConformanceDiag>>
207207
DelayedConformanceDiags;
208208

209+
/// Map from normal protocol conformances to missing witnesses that have
210+
/// been delayed until the conformance is fully checked, so that we can
211+
/// issue a fixit that fills the entire protocol stub.
212+
llvm::DenseMap<NormalProtocolConformance *, std::vector<ValueDecl*>>
213+
DelayedMissingWitnesses;
214+
209215
/// Stores information about lazy deserialization of various declarations.
210216
llvm::DenseMap<const DeclContext *, LazyContextData *> LazyContexts;
211217

@@ -1491,6 +1497,24 @@ void ASTContext::addDelayedConformanceDiag(
14911497
Impl.DelayedConformanceDiags[conformance].push_back(std::move(fn));
14921498
}
14931499

1500+
void ASTContext::
1501+
addDelayedMissingWitnesses(NormalProtocolConformance *conformance,
1502+
ArrayRef<ValueDecl*> witnesses) {
1503+
auto &bucket = Impl.DelayedMissingWitnesses[conformance];
1504+
bucket.insert(bucket.end(), witnesses.begin(), witnesses.end());
1505+
}
1506+
1507+
std::vector<ValueDecl*> ASTContext::
1508+
takeDelayedMissingWitnesses(NormalProtocolConformance *conformance) {
1509+
std::vector<ValueDecl*> result;
1510+
auto known = Impl.DelayedMissingWitnesses.find(conformance);
1511+
if (known != Impl.DelayedMissingWitnesses.end()) {
1512+
result = std::move(known->second);
1513+
Impl.DelayedMissingWitnesses.erase(known);
1514+
}
1515+
return result;
1516+
}
1517+
14941518
std::vector<ASTContext::DelayedConformanceDiag>
14951519
ASTContext::takeDelayedConformanceDiags(NormalProtocolConformance *conformance){
14961520
std::vector<ASTContext::DelayedConformanceDiag> result;

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1945,12 +1945,21 @@ namespace {
19451945
ProtocolConformance *MultiConformanceChecker::
19461946
checkIndividualConformance(NormalProtocolConformance *conformance,
19471947
bool issueFixit) {
1948+
std::vector<ValueDecl*> revivedMissingWitnesses;
19481949
switch (conformance->getState()) {
19491950
case ProtocolConformanceState::Incomplete:
19501951
if (conformance->isInvalid()) {
1951-
// Emit any delayed diagnostics and return.
1952-
ConformanceChecker(TC, conformance, MissingWitnesses, false).
1953-
emitDelayedDiags();
1952+
// Revive registered missing witnesses to handle it below.
1953+
revivedMissingWitnesses = TC.Context.
1954+
takeDelayedMissingWitnesses(conformance);
1955+
1956+
// If we have no missing witnesses for this invalid conformance, the
1957+
// conformance is invalid for other reasons, so emit diagnosis now.
1958+
if (revivedMissingWitnesses.empty()) {
1959+
// Emit any delayed diagnostics.
1960+
ConformanceChecker(TC, conformance, MissingWitnesses, false).
1961+
emitDelayedDiags();
1962+
}
19541963
}
19551964

19561965
// Check the rest of the conformance below.
@@ -2051,6 +2060,8 @@ namespace {
20512060

20522061
// The conformance checker we're using.
20532062
AllUsedCheckers.emplace_back(TC, conformance, MissingWitnesses);
2063+
MissingWitnesses.insert(revivedMissingWitnesses.begin(),
2064+
revivedMissingWitnesses.end());
20542065
AllUsedCheckers.back().checkConformance(issueFixit ?
20552066
MissingWitnessDiagnosisKind::ErrorFixIt :
20562067
MissingWitnessDiagnosisKind::ErrorOnly);
@@ -2618,6 +2629,7 @@ printRequirementStub(ValueDecl *Requirement, DeclContext *Adopter,
26182629
}
26192630

26202631
PrintOptions Options = PrintOptions::printForDiagnostics();
2632+
Options.PrintDocumentationComments = false;
26212633
Options.AccessibilityFilter = Accessibility::Private;
26222634
Options.PrintAccessibility = false;
26232635
Options.FunctionBody = [](const ValueDecl *VD) { return "<#code#>"; };
@@ -2721,7 +2733,15 @@ diagnoseMissingWitnesses(MissingWitnessDiagnosisKind Kind) {
27212733

27222734
switch (Kind) {
27232735
case MissingWitnessDiagnosisKind::ErrorFixIt: {
2724-
diagnoseOrDefer(LocalMissing[0], true, InsertFixitCallback);
2736+
if (SuppressDiagnostics) {
2737+
// If the diagnostics are suppressed, we register these missing witnesses
2738+
// for later revisiting.
2739+
Conformance->setInvalid();
2740+
TC.Context.addDelayedMissingWitnesses(Conformance,
2741+
MissingWitnesses.getArrayRef());
2742+
} else {
2743+
diagnoseOrDefer(LocalMissing[0], true, InsertFixitCallback);
2744+
}
27252745
clearGlobalMissingWitnesses();
27262746
return;
27272747
}
@@ -4875,6 +4895,15 @@ void ConformanceChecker::checkConformance(MissingWitnessDiagnosisKind Kind) {
48754895
// FIXME: Caller checks that this type conforms to all of the
48764896
// inherited protocols.
48774897

4898+
// Emit known diags for this conformance.
4899+
emitDelayedDiags();
4900+
4901+
// If delayed diags have already complained, return.
4902+
if (AlreadyComplained) {
4903+
Conformance->setInvalid();
4904+
return;
4905+
}
4906+
48784907
// Resolve all of the type witnesses.
48794908
resolveTypeWitnesses();
48804909

test/decl/protocol/conforms/fixit_stub_editor.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,17 @@ protocol P2 {
1111
}
1212

1313
class C1 : P1, P2 {} // expected-error{{type 'C1' does not conform to protocol 'P1'}} expected-error{{type 'C1' does not conform to protocol 'P2'}} expected-note{{do you want to add protocol stubs?}}{{20-20=\n func foo1() {\n <#code#>\n \}\n\n func foo2() {\n <#code#>\n \}\n\n func bar1() {\n <#code#>\n \}\n\n func bar2() {\n <#code#>\n \}\n}}
14+
15+
protocol P3 {
16+
associatedtype T1
17+
associatedtype T2
18+
associatedtype T3
19+
}
20+
21+
protocol P4 : P3 {
22+
associatedtype T4 = T1
23+
associatedtype T5 = T2
24+
associatedtype T6 = T3
25+
}
26+
27+
class C2 : P4 {} // expected-error{{type 'C2' does not conform to protocol 'P4'}} expected-error{{type 'C2' does not conform to protocol 'P3'}} expected-note{{do you want to add protocol stubs?}}{{16-16=\n typealias T4 = <#type#>\n\n typealias T5 = <#type#>\n\n typealias T6 = <#type#>\n\n typealias T1 = <#type#>\n\n typealias T2 = <#type#>\n\n typealias T3 = <#type#>\n}}

0 commit comments

Comments
 (0)